infrahub-server 1.6.2__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 (253) 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 +12 -9
  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 +26 -6
  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 +11 -6
  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_parameters.py +28 -1
  104. infrahub/core/schema/attribute_schema.py +11 -17
  105. infrahub/core/schema/basenode_schema.py +3 -0
  106. infrahub/core/schema/definitions/core/__init__.py +8 -2
  107. infrahub/core/schema/definitions/core/account.py +10 -10
  108. infrahub/core/schema/definitions/core/artifact.py +14 -8
  109. infrahub/core/schema/definitions/core/check.py +10 -4
  110. infrahub/core/schema/definitions/core/generator.py +26 -6
  111. infrahub/core/schema/definitions/core/graphql_query.py +1 -1
  112. infrahub/core/schema/definitions/core/group.py +9 -2
  113. infrahub/core/schema/definitions/core/ipam.py +80 -10
  114. infrahub/core/schema/definitions/core/menu.py +41 -7
  115. infrahub/core/schema/definitions/core/permission.py +16 -2
  116. infrahub/core/schema/definitions/core/profile.py +16 -2
  117. infrahub/core/schema/definitions/core/propose_change.py +24 -4
  118. infrahub/core/schema/definitions/core/propose_change_comment.py +23 -11
  119. infrahub/core/schema/definitions/core/propose_change_validator.py +50 -21
  120. infrahub/core/schema/definitions/core/repository.py +10 -0
  121. infrahub/core/schema/definitions/core/resource_pool.py +8 -1
  122. infrahub/core/schema/definitions/core/template.py +19 -2
  123. infrahub/core/schema/definitions/core/transform.py +11 -5
  124. infrahub/core/schema/definitions/core/webhook.py +27 -9
  125. infrahub/core/schema/manager.py +63 -43
  126. infrahub/core/schema/relationship_schema.py +6 -2
  127. infrahub/core/schema/schema_branch.py +115 -11
  128. infrahub/core/task/task.py +4 -2
  129. infrahub/core/utils.py +3 -25
  130. infrahub/core/validators/aggregated_checker.py +1 -1
  131. infrahub/core/validators/attribute/choices.py +1 -1
  132. infrahub/core/validators/attribute/enum.py +1 -1
  133. infrahub/core/validators/attribute/kind.py +6 -3
  134. infrahub/core/validators/attribute/length.py +1 -1
  135. infrahub/core/validators/attribute/min_max.py +1 -1
  136. infrahub/core/validators/attribute/number_pool.py +1 -1
  137. infrahub/core/validators/attribute/optional.py +1 -1
  138. infrahub/core/validators/attribute/regex.py +1 -1
  139. infrahub/core/validators/determiner.py +3 -3
  140. infrahub/core/validators/node/attribute.py +1 -1
  141. infrahub/core/validators/node/relationship.py +1 -1
  142. infrahub/core/validators/relationship/peer.py +1 -1
  143. infrahub/database/__init__.py +4 -4
  144. infrahub/dependencies/builder/constraint/grouped/node_runner.py +2 -0
  145. infrahub/dependencies/builder/constraint/relationship_manager/profiles_removal.py +8 -0
  146. infrahub/dependencies/registry.py +2 -0
  147. infrahub/display_labels/tasks.py +12 -3
  148. infrahub/git/integrator.py +18 -18
  149. infrahub/git/tasks.py +1 -1
  150. infrahub/git/utils.py +1 -1
  151. infrahub/graphql/app.py +2 -2
  152. infrahub/graphql/constants.py +3 -0
  153. infrahub/graphql/context.py +1 -1
  154. infrahub/graphql/field_extractor.py +1 -1
  155. infrahub/graphql/initialization.py +11 -0
  156. infrahub/graphql/loaders/account.py +134 -0
  157. infrahub/graphql/loaders/node.py +5 -12
  158. infrahub/graphql/loaders/peers.py +5 -7
  159. infrahub/graphql/manager.py +175 -21
  160. infrahub/graphql/metadata.py +91 -0
  161. infrahub/graphql/mutations/account.py +6 -6
  162. infrahub/graphql/mutations/attribute.py +0 -2
  163. infrahub/graphql/mutations/branch.py +9 -5
  164. infrahub/graphql/mutations/computed_attribute.py +1 -1
  165. infrahub/graphql/mutations/display_label.py +1 -1
  166. infrahub/graphql/mutations/hfid.py +1 -1
  167. infrahub/graphql/mutations/ipam.py +4 -6
  168. infrahub/graphql/mutations/main.py +9 -4
  169. infrahub/graphql/mutations/profile.py +16 -22
  170. infrahub/graphql/mutations/proposed_change.py +4 -4
  171. infrahub/graphql/mutations/relationship.py +40 -10
  172. infrahub/graphql/mutations/repository.py +14 -12
  173. infrahub/graphql/mutations/schema.py +2 -2
  174. infrahub/graphql/order.py +14 -0
  175. infrahub/graphql/queries/branch.py +62 -6
  176. infrahub/graphql/queries/diff/tree.py +5 -5
  177. infrahub/graphql/queries/resource_manager.py +25 -24
  178. infrahub/graphql/resolvers/account_metadata.py +84 -0
  179. infrahub/graphql/resolvers/ipam.py +6 -8
  180. infrahub/graphql/resolvers/many_relationship.py +77 -35
  181. infrahub/graphql/resolvers/resolver.py +59 -14
  182. infrahub/graphql/resolvers/single_relationship.py +87 -23
  183. infrahub/graphql/subscription/graphql_query.py +2 -0
  184. infrahub/graphql/types/__init__.py +0 -1
  185. infrahub/graphql/types/attribute.py +10 -5
  186. infrahub/graphql/types/branch.py +40 -53
  187. infrahub/graphql/types/enums.py +3 -0
  188. infrahub/graphql/types/metadata.py +28 -0
  189. infrahub/graphql/types/node.py +22 -2
  190. infrahub/graphql/types/relationship.py +10 -2
  191. infrahub/graphql/types/standard_node.py +12 -7
  192. infrahub/hfid/tasks.py +12 -3
  193. infrahub/lock.py +7 -0
  194. infrahub/menu/repository.py +1 -1
  195. infrahub/patch/queries/base.py +1 -1
  196. infrahub/pools/number.py +1 -8
  197. infrahub/profiles/gather.py +56 -0
  198. infrahub/profiles/mandatory_fields_checker.py +116 -0
  199. infrahub/profiles/models.py +66 -0
  200. infrahub/profiles/node_applier.py +154 -13
  201. infrahub/profiles/queries/get_profile_data.py +143 -31
  202. infrahub/profiles/tasks.py +79 -27
  203. infrahub/profiles/triggers.py +22 -0
  204. infrahub/proposed_change/action_checker.py +1 -1
  205. infrahub/proposed_change/tasks.py +4 -1
  206. infrahub/services/__init__.py +1 -1
  207. infrahub/services/adapters/cache/nats.py +1 -1
  208. infrahub/services/adapters/cache/redis.py +7 -0
  209. infrahub/tasks/artifact.py +1 -0
  210. infrahub/transformations/tasks.py +2 -2
  211. infrahub/trigger/catalogue.py +2 -0
  212. infrahub/trigger/models.py +1 -0
  213. infrahub/trigger/setup.py +3 -3
  214. infrahub/trigger/tasks.py +3 -0
  215. infrahub/validators/tasks.py +1 -0
  216. infrahub/webhook/gather.py +1 -1
  217. infrahub/webhook/models.py +1 -1
  218. infrahub/webhook/tasks.py +23 -7
  219. infrahub/workers/dependencies.py +9 -3
  220. infrahub/workers/infrahub_async.py +13 -4
  221. infrahub/workflows/catalogue.py +19 -0
  222. infrahub_sdk/analyzer.py +2 -2
  223. infrahub_sdk/branch.py +12 -39
  224. infrahub_sdk/checks.py +4 -4
  225. infrahub_sdk/client.py +36 -0
  226. infrahub_sdk/ctl/cli_commands.py +2 -1
  227. infrahub_sdk/ctl/graphql.py +15 -4
  228. infrahub_sdk/ctl/utils.py +2 -2
  229. infrahub_sdk/enums.py +6 -0
  230. infrahub_sdk/graphql/renderers.py +21 -0
  231. infrahub_sdk/graphql/utils.py +85 -0
  232. infrahub_sdk/node/attribute.py +12 -2
  233. infrahub_sdk/node/constants.py +12 -0
  234. infrahub_sdk/node/metadata.py +69 -0
  235. infrahub_sdk/node/node.py +65 -14
  236. infrahub_sdk/node/property.py +3 -0
  237. infrahub_sdk/node/related_node.py +37 -5
  238. infrahub_sdk/node/relationship.py +18 -1
  239. infrahub_sdk/operation.py +2 -2
  240. infrahub_sdk/schema/repository.py +1 -2
  241. infrahub_sdk/transforms.py +2 -2
  242. infrahub_sdk/types.py +18 -2
  243. {infrahub_server-1.6.2.dist-info → infrahub_server-1.7.0.dist-info}/METADATA +17 -16
  244. {infrahub_server-1.6.2.dist-info → infrahub_server-1.7.0.dist-info}/RECORD +252 -231
  245. infrahub_testcontainers/container.py +3 -3
  246. infrahub_testcontainers/docker-compose-cluster.test.yml +7 -7
  247. infrahub_testcontainers/docker-compose.test.yml +13 -5
  248. infrahub_testcontainers/models.py +3 -3
  249. infrahub_testcontainers/performance_test.py +1 -1
  250. infrahub/graphql/models.py +0 -6
  251. {infrahub_server-1.6.2.dist-info → infrahub_server-1.7.0.dist-info}/WHEEL +0 -0
  252. {infrahub_server-1.6.2.dist-info → infrahub_server-1.7.0.dist-info}/entry_points.txt +0 -0
  253. {infrahub_server-1.6.2.dist-info → infrahub_server-1.7.0.dist-info}/licenses/LICENSE.txt +0 -0
infrahub/actions/tasks.py CHANGED
@@ -211,8 +211,10 @@ async def configure_action_rules(
211
211
  service: InfrahubServices,
212
212
  ) -> None:
213
213
  await setup_triggers_specific(
214
- gatherer=gather_trigger_action_rules, trigger_type=TriggerType.ACTION_TRIGGER_RULE, db=service.database
215
- ) # type: ignore[misc]
214
+ gatherer=gather_trigger_action_rules, # type: ignore[arg-type]
215
+ trigger_type=TriggerType.ACTION_TRIGGER_RULE,
216
+ db=service.database,
217
+ )
216
218
 
217
219
 
218
220
  async def _get_targets(
@@ -4,12 +4,12 @@ from infrahub.exceptions import Error
4
4
  class QueryValidationError(Error):
5
5
  HTTP_CODE = 400
6
6
 
7
- def __init__(self, message: str):
7
+ def __init__(self, message: str) -> None:
8
8
  self.message = message
9
9
 
10
10
 
11
11
  class SchemaNotValidError(Error):
12
12
  HTTP_CODE = 422
13
13
 
14
- def __init__(self, message: str):
14
+ def __init__(self, message: str) -> None:
15
15
  self.message = message
infrahub/api/schema.py CHANGED
@@ -366,6 +366,7 @@ async def load_schema(
366
366
  diff=result.diff,
367
367
  limit=result.diff.all,
368
368
  update_db=True,
369
+ user_id=account_session.account_id,
369
370
  )
370
371
  branch.update_schema_hash()
371
372
  log.info("Schema has been updated", branch=branch.name, hash=branch.active_schema_hash.main)
@@ -375,7 +376,7 @@ async def load_schema(
375
376
  branch.is_isolated = True
376
377
  log.info("Branch converted to isolated mode because the schema has changed", branch=branch.name)
377
378
 
378
- await branch.save(db=dbt)
379
+ await branch.save(db=dbt, user_id=account_session.account_id)
379
380
  updated_branch = registry.schema.get_schema_branch(name=branch.name)
380
381
  updated_hash = updated_branch.get_hash()
381
382
 
@@ -387,6 +388,7 @@ async def load_schema(
387
388
  new_schema=candidate_schema,
388
389
  previous_schema=origin_schema,
389
390
  migrations=result.migrations,
391
+ user_id=account_session.account_id,
390
392
  )
391
393
  migration_error_msgs = await service.workflow.execute_workflow(
392
394
  workflow=SCHEMA_APPLY_MIGRATION,
@@ -14,6 +14,7 @@ async def create(model: CheckArtifactCreate) -> ValidatorConclusion:
14
14
  await add_tags(branches=[model.branch_name], nodes=[model.target_id])
15
15
 
16
16
  client = get_client()
17
+ client.request_context = model.context.to_request_context()
17
18
 
18
19
  validator = await client.get(kind=InfrahubKind.ARTIFACTVALIDATOR, id=model.validator_id, include=["checks"])
19
20
 
infrahub/auth.py CHANGED
@@ -73,8 +73,8 @@ async def authenticate_with_password(
73
73
  ) -> models.UserToken:
74
74
  selected_branch = await registry.get_branch(db=db, branch=branch)
75
75
 
76
- response: list[CoreGenericAccount] = await NodeManager.query(
77
- schema=InfrahubKind.GENERICACCOUNT,
76
+ response = await NodeManager.query(
77
+ schema=CoreGenericAccount,
78
78
  db=db,
79
79
  branch=selected_branch,
80
80
  filters={"name__value": credentials.username},
infrahub/cli/db.py CHANGED
@@ -65,6 +65,7 @@ def get_timestamp_string() -> str:
65
65
  if TYPE_CHECKING:
66
66
  from infrahub.cli.context import CliContext
67
67
  from infrahub.core.migrations.shared import MigrationTypes
68
+ from infrahub.core.root import Root
68
69
  from infrahub.database import InfrahubDatabase
69
70
  from infrahub.database.index import IndexManagerBase
70
71
 
@@ -93,12 +94,40 @@ def callback() -> None:
93
94
  """
94
95
 
95
96
 
97
+ async def do_migrate(
98
+ db: InfrahubDatabase,
99
+ root_node: Root,
100
+ check: bool = False,
101
+ migration_number: int | None = None,
102
+ ) -> None:
103
+ """Core migration logic that can be called independently of CLI.
104
+
105
+ Args:
106
+ db: The database connection.
107
+ root_node: The root node containing the current graph version.
108
+ check: If True, only check which migrations need to run without applying them.
109
+ migration_number: If provided, run only this specific migration.
110
+ """
111
+ migrations = await detect_migration_to_run(
112
+ current_graph_version=root_node.graph_version, migration_number=migration_number
113
+ )
114
+
115
+ if check or not migrations:
116
+ return
117
+
118
+ await migrate_database(
119
+ db=db, migrations=migrations, initialize=True, update_graph_version=(migration_number is None)
120
+ )
121
+
122
+
96
123
  @app.command(name="migrate")
97
124
  async def migrate_cmd(
98
125
  ctx: typer.Context,
99
126
  check: bool = typer.Option(False, help="Check the state of the database without applying the migrations."),
100
127
  config_file: str = typer.Argument("infrahub.toml", envvar="INFRAHUB_CONFIG"),
101
- migration_number: int | None = typer.Option(None, help="Apply a specific migration by number"),
128
+ migration_number: int | None = typer.Option(
129
+ None, help="Apply a specific migration by number, regardless of current database version"
130
+ ),
102
131
  ) -> None:
103
132
  """Check the current format of the internal graph and apply the necessary migrations"""
104
133
  logging.getLogger("infrahub").setLevel(logging.WARNING)
@@ -111,14 +140,7 @@ async def migrate_cmd(
111
140
  dbdriver = await context.init_db(retry=1)
112
141
 
113
142
  root_node = await get_root_node(db=dbdriver)
114
- migrations = await detect_migration_to_run(
115
- current_graph_version=root_node.graph_version, migration_number=migration_number
116
- )
117
-
118
- if check or not migrations:
119
- return
120
-
121
- await migrate_database(db=dbdriver, migrations=migrations, initialize=True)
143
+ await do_migrate(db=dbdriver, root_node=root_node, check=check, migration_number=migration_number)
122
144
 
123
145
  await dbdriver.close()
124
146
 
@@ -292,18 +314,17 @@ async def detect_migration_to_run(
292
314
  migration = get_migration_by_number(migration_number)
293
315
  migrations.append(migration)
294
316
  if current_graph_version > migration.minimum_version:
317
+ get_migration_console().log(f"Migration {migration_number} will be re-applied.")
318
+ else:
295
319
  get_migration_console().log(
296
- f"Migration {migration_number} already applied. To apply again, run the command without the --check flag."
320
+ f"Migration {migration_number} needs to be applied. Run `infrahub db migrate` to apply all outstanding migrations."
297
321
  )
298
- return []
299
- get_migration_console().log(
300
- f"Migration {migration_number} needs to be applied. Run `infrahub db migrate` to apply all outstanding migrations."
301
- )
302
- else:
303
- migrations.extend(await get_graph_migrations(current_graph_version=current_graph_version))
304
- if not migrations:
305
- get_migration_console().log(f"Database up-to-date (v{current_graph_version}), no migration to execute.")
306
- return []
322
+ return migrations
323
+
324
+ migrations.extend(await get_graph_migrations(current_graph_version=current_graph_version))
325
+ if not migrations:
326
+ get_migration_console().log(f"Database up-to-date (v{current_graph_version}), no migration to execute.")
327
+ return []
307
328
 
308
329
  get_migration_console().log(
309
330
  f"Database needs to be updated (v{current_graph_version} -> v{GRAPH_VERSION}), {len(migrations)} migrations pending"
@@ -312,7 +333,10 @@ async def detect_migration_to_run(
312
333
 
313
334
 
314
335
  async def migrate_database(
315
- db: InfrahubDatabase, migrations: Sequence[MigrationTypes], initialize: bool = False
336
+ db: InfrahubDatabase,
337
+ migrations: Sequence[MigrationTypes],
338
+ initialize: bool = False,
339
+ update_graph_version: bool = True,
316
340
  ) -> bool:
317
341
  """Apply the latest migrations to the database, this function will print the status directly in the console.
318
342
 
@@ -322,6 +346,7 @@ async def migrate_database(
322
346
  db: The database object.
323
347
  migrations: Sequence of migrations to apply.
324
348
  initialize: Whether to initialize the registry before running migrations.
349
+ update_graph_version: Whether to update the graph version after each migration.
325
350
  """
326
351
  if not migrations:
327
352
  return True
@@ -339,8 +364,9 @@ async def migrate_database(
339
364
  validation_result = await migration.validate_migration(db=db)
340
365
  if validation_result.success:
341
366
  get_migration_console().log(f"Migration: {migration.name} {SUCCESS_BADGE}")
342
- root_node.graph_version = migration.minimum_version + 1
343
- await root_node.save(db=db)
367
+ if update_graph_version:
368
+ root_node.graph_version = migration.minimum_version + 1
369
+ await root_node.save(db=db)
344
370
 
345
371
  if not execution_result.success or (validation_result and not validation_result.success):
346
372
  get_migration_console().log(f"Migration: {migration.name} {FAILED_BADGE}")
@@ -603,17 +629,17 @@ RETURN vertices, edges
603
629
  edge_path = export_dir / Path("edges.csv")
604
630
  edge_path.touch(exist_ok=True)
605
631
 
606
- graph_node_schemas = [GraphNodeProperties, GraphRelationshipProperties, GraphAttributeProperties]
632
+ graph_node_schemas = (GraphNodeProperties, GraphRelationshipProperties, GraphAttributeProperties)
607
633
  graph_vertex_properties = set()
608
- for graph_schema in graph_node_schemas:
609
- for field_name, field_info in graph_schema.model_fields.items():
634
+ for graph_node_schema in graph_node_schemas:
635
+ for field_name, field_info in graph_node_schema.model_fields.items():
610
636
  property_name = field_info.alias or field_name
611
637
  graph_vertex_properties.add(property_name)
612
638
 
613
- graph_edge_schemas = [GraphRelationshipIsPartOf, GraphRelationshipDefault]
639
+ graph_edge_schemas = (GraphRelationshipIsPartOf, GraphRelationshipDefault)
614
640
  graph_edge_properties = set()
615
- for graph_schema in graph_edge_schemas:
616
- for field_name, field_info in graph_schema.model_fields.items():
641
+ for graph_edge_schema in graph_edge_schemas:
642
+ for field_name, field_info in graph_edge_schema.model_fields.items():
617
643
  property_name = field_info.alias or field_name
618
644
  graph_edge_properties.add(property_name)
619
645
 
@@ -7,9 +7,9 @@ from prefect import task
7
7
  from prefect.cache_policies import NONE
8
8
  from prefect.logging import get_run_logger
9
9
 
10
- from infrahub.core.constants import InfrahubKind
11
10
  from infrahub.core.manager import NodeManager
12
11
  from infrahub.core.protocols import CoreGenericRepository, CoreGraphQLQuery
12
+ from infrahub.core.protocols import CoreTransformPython as CoreTransformPythonNode
13
13
  from infrahub.core.registry import registry
14
14
  from infrahub.database import InfrahubDatabase # noqa: TC001 needed for prefect flow
15
15
  from infrahub.git.utils import get_repositories_commit_per_branch
@@ -24,7 +24,6 @@ from .models import (
24
24
  )
25
25
 
26
26
  if TYPE_CHECKING:
27
- from infrahub.core.protocols import CoreTransformPython as CoreTransformPythonNode
28
27
  from infrahub.git.models import RepositoryData
29
28
 
30
29
 
@@ -48,9 +47,9 @@ async def gather_python_transform_attributes(
48
47
  if not transform_names:
49
48
  return []
50
49
 
51
- transforms: list[CoreTransformPythonNode] = await NodeManager.query(
50
+ transforms = await NodeManager.query(
52
51
  db=db,
53
- schema=InfrahubKind.TRANSFORMPYTHON,
52
+ schema=CoreTransformPythonNode,
54
53
  branch=branch_name,
55
54
  fields={"id": None, "name": None, "repository": None, "query": None},
56
55
  filters={"name__values": transform_names},
@@ -42,8 +42,10 @@ mutation UpdateAttribute(
42
42
  $kind: String!,
43
43
  $attribute: String!,
44
44
  $value: String!
45
+ $context_account_id: String!
45
46
  ) {
46
47
  InfrahubUpdateComputedAttribute(
48
+ context: {account: {id: $context_account_id}},
47
49
  data: {id: $id, attribute: $attribute, value: $value, kind: $kind}
48
50
  ) {
49
51
  ok
@@ -62,7 +64,7 @@ async def process_transform(
62
64
  object_id: str,
63
65
  computed_attribute_name: str, # noqa: ARG001
64
66
  computed_attribute_kind: str, # noqa: ARG001
65
- context: InfrahubContext, # noqa: ARG001
67
+ context: InfrahubContext,
66
68
  updated_fields: list[str] | None = None, # noqa: ARG001
67
69
  ) -> None:
68
70
  await add_tags(branches=[branch_name], nodes=[object_id])
@@ -103,7 +105,7 @@ async def process_transform(
103
105
  name=transform.repository.peer.name.value,
104
106
  repository_kind=str(transform.repository.peer.typename),
105
107
  commit=repo_node.commit.value,
106
- ) # type: ignore[misc]
108
+ )
107
109
 
108
110
  data = await client.query_gql_query(
109
111
  name=transform.query.id,
@@ -120,11 +122,17 @@ async def process_transform(
120
122
  location=f"{transform.file_path.value}::{transform.class_name.value}",
121
123
  data=data,
122
124
  convert_query_response=transform.convert_query_response.value,
123
- ) # type: ignore[misc]
125
+ ) # type: ignore[call-overload]
124
126
 
125
127
  await client.execute_graphql(
126
128
  query=UPDATE_ATTRIBUTE,
127
- variables={"id": object_id, "kind": node_kind, "attribute": attribute_name, "value": transformed_data},
129
+ variables={
130
+ "id": object_id,
131
+ "kind": node_kind,
132
+ "attribute": attribute_name,
133
+ "value": transformed_data,
134
+ "context_account_id": context.account.account_id,
135
+ },
128
136
  branch_name=branch_name,
129
137
  )
130
138
 
@@ -168,6 +176,7 @@ async def computed_attribute_jinja2_update_value(
168
176
  node_kind: str,
169
177
  attribute_name: str,
170
178
  template: Jinja2Template,
179
+ context: InfrahubContext,
171
180
  ) -> None:
172
181
  log = get_run_logger()
173
182
  client = get_client()
@@ -182,7 +191,13 @@ async def computed_attribute_jinja2_update_value(
182
191
  try:
183
192
  await client.execute_graphql(
184
193
  query=UPDATE_ATTRIBUTE,
185
- variables={"id": obj.node_id, "kind": node_kind, "attribute": attribute_name, "value": value},
194
+ variables={
195
+ "id": obj.node_id,
196
+ "kind": node_kind,
197
+ "attribute": attribute_name,
198
+ "value": value,
199
+ "context_account_id": context.account.account_id,
200
+ },
186
201
  branch_name=branch_name,
187
202
  )
188
203
  log.info(f"Updating computed attribute {node_kind}.{attribute_name}='{value}' ({obj.node_id})")
@@ -202,7 +217,7 @@ async def process_jinja2(
202
217
  object_id: str,
203
218
  computed_attribute_name: str,
204
219
  computed_attribute_kind: str,
205
- context: InfrahubContext, # noqa: ARG001
220
+ context: InfrahubContext,
206
221
  updated_fields: list[str] | None = None,
207
222
  ) -> None:
208
223
  log = get_run_logger()
@@ -258,6 +273,7 @@ async def process_jinja2(
258
273
  node_kind=node_schema.kind,
259
274
  attribute_name=computed_macro.attribute.name,
260
275
  template=jinja_template,
276
+ context=context,
261
277
  )
262
278
 
263
279
  _ = [response async for _, response in batch.execute()]
@@ -462,6 +478,7 @@ async def query_transform_targets(
462
478
  "object_id": subscriber.object_id,
463
479
  "computed_attribute_name": computed_attribute.name,
464
480
  "computed_attribute_kind": subscriber.kind,
481
+ "context": context,
465
482
  },
466
483
  )
467
484
 
infrahub/config.py CHANGED
@@ -207,6 +207,14 @@ class MainSettings(BaseSettings):
207
207
  def convert_to_path(cls, value: Path | str) -> Path:
208
208
  return Path(value) if isinstance(value, str) else value
209
209
 
210
+ @property
211
+ def infrahub_address(self) -> str:
212
+ """This is the address that the Prefect worker will use to connect to Infrahub API."""
213
+ if self.internal_address:
214
+ return self.internal_address
215
+
216
+ raise InitializationError()
217
+
210
218
 
211
219
  class FileSystemStorageSettings(BaseSettings):
212
220
  # Make variable lookup case-sensitive to avoid fetching $PATH value
@@ -0,0 +1,12 @@
1
+ from enum import StrEnum
2
+
3
+
4
+ class OrderDirection(StrEnum):
5
+ ASC = "ASC"
6
+ DESC = "DESC"
7
+
8
+
9
+ class OrderByField(StrEnum):
10
+ ID = "id"
11
+ CREATED_AT = "created_at"
12
+ UPDATED_AT = "updated_at"
infrahub/core/account.py CHANGED
@@ -54,11 +54,15 @@ class AccountGlobalPermissionQuery(Query):
54
54
  name: str = "account_global_permissions"
55
55
  type: QueryType = QueryType.READ
56
56
 
57
- def __init__(self, account_id: str, **kwargs: Any):
57
+ def __init__(
58
+ self,
59
+ account_id: str,
60
+ branch: Branch | None = None,
61
+ branch_agnostic: bool = False,
62
+ ) -> None:
63
+ super().__init__(branch=branch, branch_agnostic=branch_agnostic)
58
64
  self.account_id = account_id
59
- super().__init__(**kwargs)
60
65
 
61
- async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa: ARG002
62
66
  self.params["account_id"] = self.account_id
63
67
 
64
68
  branch_filter, branch_params = self.branch.get_query_filter_path(
@@ -66,7 +70,6 @@ class AccountGlobalPermissionQuery(Query):
66
70
  )
67
71
  self.params.update(branch_params)
68
72
 
69
- # ruff: noqa: E501
70
73
  query = """
71
74
  MATCH (account:%(generic_account_node)s)
72
75
  WHERE account.uuid = $account_id
@@ -164,7 +167,7 @@ class AccountObjectPermissionQuery(Query):
164
167
  name: str = "account_object_permissions"
165
168
  type: QueryType = QueryType.READ
166
169
 
167
- def __init__(self, account_id: str, **kwargs: Any):
170
+ def __init__(self, account_id: str, **kwargs: Any) -> None:
168
171
  self.account_id = account_id
169
172
  super().__init__(**kwargs)
170
173
 
@@ -293,7 +296,7 @@ class AccountObjectPermissionQuery(Query):
293
296
 
294
297
 
295
298
  async def fetch_permissions(account_id: str, db: InfrahubDatabase, branch: Branch) -> AssignedPermissions:
296
- query1 = await AccountGlobalPermissionQuery.init(db=db, branch=branch, account_id=account_id, branch_agnostic=True)
299
+ query1 = AccountGlobalPermissionQuery(branch=branch, account_id=account_id, branch_agnostic=True)
297
300
  await query1.execute(db=db)
298
301
  global_permissions = query1.get_permissions()
299
302
 
@@ -308,7 +311,7 @@ class AccountRoleGlobalPermissionQuery(Query):
308
311
  name: str = "account_role_global_permissions"
309
312
  type: QueryType = QueryType.READ
310
313
 
311
- def __init__(self, role_id: str, **kwargs: Any):
314
+ def __init__(self, role_id: str, **kwargs: Any) -> None:
312
315
  self.role_id = role_id
313
316
  super().__init__(**kwargs)
314
317
 
@@ -394,7 +397,7 @@ class AccountRoleObjectPermissionQuery(Query):
394
397
  name: str = "account_role_object_permissions"
395
398
  type: QueryType = QueryType.READ
396
399
 
397
- def __init__(self, role_id: str, **kwargs: Any):
400
+ def __init__(self, role_id: str, **kwargs: Any) -> None:
398
401
  self.role_id = role_id
399
402
  super().__init__(**kwargs)
400
403
 
@@ -515,7 +518,7 @@ class AccountTokenValidateQuery(Query):
515
518
  name: str = "account_token_validate"
516
519
  type: QueryType = QueryType.READ
517
520
 
518
- def __init__(self, token: str, **kwargs: Any):
521
+ def __init__(self, token: str, **kwargs: Any) -> None:
519
522
  self.token = token
520
523
  super().__init__(**kwargs)
521
524