infrahub-server 1.7.0rc0__py3-none-any.whl → 1.7.2__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 (124) hide show
  1. infrahub/actions/gather.py +2 -2
  2. infrahub/api/query.py +3 -2
  3. infrahub/api/schema.py +5 -0
  4. infrahub/api/transformation.py +3 -3
  5. infrahub/cli/db.py +6 -2
  6. infrahub/computed_attribute/gather.py +2 -0
  7. infrahub/config.py +2 -2
  8. infrahub/core/attribute.py +21 -2
  9. infrahub/core/branch/models.py +11 -117
  10. infrahub/core/branch/tasks.py +7 -3
  11. infrahub/core/diff/merger/merger.py +5 -1
  12. infrahub/core/diff/model/path.py +43 -0
  13. infrahub/core/graph/__init__.py +1 -1
  14. infrahub/core/graph/index.py +2 -0
  15. infrahub/core/initialization.py +2 -1
  16. infrahub/core/ipam/resource_allocator.py +229 -0
  17. infrahub/core/migrations/graph/__init__.py +10 -0
  18. infrahub/core/migrations/graph/m014_remove_index_attr_value.py +3 -2
  19. infrahub/core/migrations/graph/m015_diff_format_update.py +3 -2
  20. infrahub/core/migrations/graph/m016_diff_delete_bug_fix.py +3 -2
  21. infrahub/core/migrations/graph/m017_add_core_profile.py +6 -4
  22. infrahub/core/migrations/graph/m018_uniqueness_nulls.py +3 -4
  23. infrahub/core/migrations/graph/m020_duplicate_edges.py +3 -3
  24. infrahub/core/migrations/graph/m025_uniqueness_nulls.py +3 -4
  25. infrahub/core/migrations/graph/m026_0000_prefix_fix.py +4 -5
  26. infrahub/core/migrations/graph/m028_delete_diffs.py +3 -2
  27. infrahub/core/migrations/graph/m029_duplicates_cleanup.py +3 -2
  28. infrahub/core/migrations/graph/m031_check_number_attributes.py +4 -3
  29. infrahub/core/migrations/graph/m032_cleanup_orphaned_branch_relationships.py +3 -2
  30. infrahub/core/migrations/graph/m034_find_orphaned_schema_fields.py +3 -2
  31. infrahub/core/migrations/graph/m035_orphan_relationships.py +3 -3
  32. infrahub/core/migrations/graph/m036_drop_attr_value_index.py +3 -2
  33. infrahub/core/migrations/graph/m037_index_attr_vals.py +3 -2
  34. infrahub/core/migrations/graph/m038_redo_0000_prefix_fix.py +4 -5
  35. infrahub/core/migrations/graph/m039_ipam_reconcile.py +3 -2
  36. infrahub/core/migrations/graph/m041_deleted_dup_edges.py +3 -2
  37. infrahub/core/migrations/graph/m042_profile_attrs_in_db.py +5 -4
  38. infrahub/core/migrations/graph/m043_create_hfid_display_label_in_db.py +12 -5
  39. infrahub/core/migrations/graph/m044_backfill_hfid_display_label_in_db.py +15 -4
  40. infrahub/core/migrations/graph/m045_backfill_hfid_display_label_in_db_profile_template.py +10 -4
  41. infrahub/core/migrations/graph/m046_fill_agnostic_hfid_display_labels.py +6 -5
  42. infrahub/core/migrations/graph/m047_backfill_or_null_display_label.py +19 -5
  43. infrahub/core/migrations/graph/m048_undelete_rel_props.py +6 -4
  44. infrahub/core/migrations/graph/m049_remove_is_visible_relationship.py +3 -3
  45. infrahub/core/migrations/graph/m050_backfill_vertex_metadata.py +3 -3
  46. infrahub/core/migrations/graph/m051_subtract_branched_from_microsecond.py +39 -0
  47. infrahub/core/migrations/graph/m052_fix_global_branch_level.py +51 -0
  48. infrahub/core/migrations/graph/m053_fix_branch_level_zero.py +61 -0
  49. infrahub/core/migrations/graph/m054_cleanup_orphaned_nodes.py +87 -0
  50. infrahub/core/migrations/graph/m055_remove_webhook_validate_certificates_default.py +86 -0
  51. infrahub/core/migrations/runner.py +6 -3
  52. infrahub/core/migrations/schema/attribute_kind_update.py +8 -11
  53. infrahub/core/migrations/schema/attribute_supports_profile.py +3 -8
  54. infrahub/core/migrations/schema/models.py +8 -0
  55. infrahub/core/migrations/schema/node_attribute_add.py +24 -29
  56. infrahub/core/migrations/schema/tasks.py +7 -1
  57. infrahub/core/migrations/shared.py +37 -30
  58. infrahub/core/node/__init__.py +2 -1
  59. infrahub/core/node/lock_utils.py +23 -2
  60. infrahub/core/node/resource_manager/ip_address_pool.py +5 -11
  61. infrahub/core/node/resource_manager/ip_prefix_pool.py +5 -21
  62. infrahub/core/node/resource_manager/number_pool.py +109 -39
  63. infrahub/core/query/__init__.py +7 -1
  64. infrahub/core/query/branch.py +18 -2
  65. infrahub/core/query/ipam.py +629 -40
  66. infrahub/core/query/node.py +128 -0
  67. infrahub/core/query/resource_manager.py +114 -1
  68. infrahub/core/relationship/model.py +9 -3
  69. infrahub/core/schema/attribute_parameters.py +28 -1
  70. infrahub/core/schema/attribute_schema.py +9 -2
  71. infrahub/core/schema/definitions/core/webhook.py +0 -1
  72. infrahub/core/schema/definitions/internal.py +7 -4
  73. infrahub/core/schema/manager.py +50 -38
  74. infrahub/core/validators/attribute/kind.py +5 -2
  75. infrahub/core/validators/determiner.py +4 -0
  76. infrahub/graphql/analyzer.py +3 -1
  77. infrahub/graphql/app.py +7 -10
  78. infrahub/graphql/execution.py +95 -0
  79. infrahub/graphql/manager.py +8 -2
  80. infrahub/graphql/mutations/proposed_change.py +15 -0
  81. infrahub/graphql/parser.py +10 -7
  82. infrahub/graphql/queries/ipam.py +20 -25
  83. infrahub/graphql/queries/search.py +29 -9
  84. infrahub/lock.py +7 -0
  85. infrahub/proposed_change/tasks.py +2 -0
  86. infrahub/services/adapters/cache/redis.py +7 -0
  87. infrahub/services/adapters/http/httpx.py +27 -0
  88. infrahub/trigger/catalogue.py +2 -0
  89. infrahub/trigger/models.py +73 -4
  90. infrahub/trigger/setup.py +1 -1
  91. infrahub/trigger/system.py +36 -0
  92. infrahub/webhook/models.py +4 -2
  93. infrahub/webhook/tasks.py +2 -2
  94. infrahub/workflows/initialization.py +2 -2
  95. infrahub_sdk/analyzer.py +2 -2
  96. infrahub_sdk/branch.py +12 -39
  97. infrahub_sdk/checks.py +4 -4
  98. infrahub_sdk/client.py +36 -0
  99. infrahub_sdk/ctl/cli_commands.py +2 -1
  100. infrahub_sdk/ctl/graphql.py +15 -4
  101. infrahub_sdk/ctl/utils.py +2 -2
  102. infrahub_sdk/enums.py +6 -0
  103. infrahub_sdk/graphql/renderers.py +21 -0
  104. infrahub_sdk/graphql/utils.py +85 -0
  105. infrahub_sdk/node/attribute.py +12 -2
  106. infrahub_sdk/node/constants.py +11 -0
  107. infrahub_sdk/node/metadata.py +69 -0
  108. infrahub_sdk/node/node.py +65 -14
  109. infrahub_sdk/node/property.py +3 -0
  110. infrahub_sdk/node/related_node.py +24 -1
  111. infrahub_sdk/node/relationship.py +10 -1
  112. infrahub_sdk/operation.py +2 -2
  113. infrahub_sdk/schema/repository.py +1 -2
  114. infrahub_sdk/transforms.py +2 -2
  115. infrahub_sdk/types.py +18 -2
  116. {infrahub_server-1.7.0rc0.dist-info → infrahub_server-1.7.2.dist-info}/METADATA +8 -8
  117. {infrahub_server-1.7.0rc0.dist-info → infrahub_server-1.7.2.dist-info}/RECORD +123 -114
  118. {infrahub_server-1.7.0rc0.dist-info → infrahub_server-1.7.2.dist-info}/entry_points.txt +0 -1
  119. infrahub_testcontainers/docker-compose-cluster.test.yml +16 -10
  120. infrahub_testcontainers/docker-compose.test.yml +11 -10
  121. infrahub_testcontainers/performance_test.py +1 -1
  122. infrahub/pools/address.py +0 -16
  123. {infrahub_server-1.7.0rc0.dist-info → infrahub_server-1.7.2.dist-info}/WHEEL +0 -0
  124. {infrahub_server-1.7.0rc0.dist-info → infrahub_server-1.7.2.dist-info}/licenses/LICENSE.txt +0 -0
@@ -0,0 +1,229 @@
1
+ from __future__ import annotations
2
+
3
+ import ipaddress
4
+ from typing import TYPE_CHECKING, Iterable
5
+
6
+ from infrahub.core.query.ipam import (
7
+ IPAddressData,
8
+ IPPrefixData,
9
+ IPPrefixIPAddressFetch,
10
+ IPPrefixIPAddressFetchFree,
11
+ IPPrefixSubnetFetch,
12
+ IPPrefixSubnetFetchFree,
13
+ IPv6PrefixIPAddressFetchFree,
14
+ IPv6PrefixSubnetFetchFree,
15
+ )
16
+
17
+ if TYPE_CHECKING:
18
+ from infrahub.core.branch import Branch
19
+ from infrahub.core.ipam.constants import IPAddressType, IPNetworkType
20
+ from infrahub.core.node import Node
21
+ from infrahub.core.timestamp import Timestamp
22
+ from infrahub.database import InfrahubDatabase
23
+
24
+
25
+ class IPAMResourceAllocator:
26
+ """Allocator for IPAM resources (prefixes and addresses) within pools.
27
+
28
+ This class provides optimized methods for finding the next available
29
+ IP prefix or address within a parent prefix. It uses database-side
30
+ Cypher computation for performance, which is especially important
31
+ for IPv6 allocations where the address space is very large.
32
+ """
33
+
34
+ def __init__(
35
+ self,
36
+ db: InfrahubDatabase,
37
+ namespace: Node | str | None = None,
38
+ branch: Branch | None = None,
39
+ branch_agnostic: bool = False,
40
+ ) -> None:
41
+ """Initialize the IPAM resource allocator.
42
+
43
+ Args:
44
+ db: Database connection to use for queries.
45
+ namespace: IP namespace node or its ID. If None, uses the default namespace.
46
+ branch: Branch to query. If None, uses the default branch.
47
+ branch_agnostic: If True, queries across all branches.
48
+ """
49
+ self.db = db
50
+ self.namespace = namespace
51
+ self.branch = branch
52
+ self.branch_agnostic = branch_agnostic
53
+
54
+ async def _get_next_ipv4_prefix(
55
+ self, ip_prefix: IPNetworkType, target_prefix_length: int, at: Timestamp | str | None = None
56
+ ) -> IPNetworkType | None:
57
+ """Get the next available free IPv4 prefix.
58
+
59
+ Uses integer arithmetic in Cypher for efficient gap detection in the
60
+ IPv4 address space.
61
+
62
+ Args:
63
+ ip_prefix: Parent prefix to allocate from.
64
+ target_prefix_length: Desired prefix length for the new prefix (0-32).
65
+ at: Optional timestamp for point-in-time queries.
66
+
67
+ Returns:
68
+ The next available IPv4 prefix, or None if no space is available
69
+ or if the target_prefix_length is invalid.
70
+ """
71
+ if target_prefix_length < 0 or target_prefix_length > 32:
72
+ return None
73
+ if target_prefix_length < ip_prefix.prefixlen:
74
+ return None
75
+
76
+ query = await IPPrefixSubnetFetchFree.init(
77
+ db=self.db,
78
+ branch=self.branch,
79
+ obj=ip_prefix,
80
+ target_prefixlen=target_prefix_length,
81
+ namespace=self.namespace,
82
+ at=at,
83
+ branch_agnostic=self.branch_agnostic,
84
+ )
85
+ await query.execute(db=self.db)
86
+
87
+ result_data = query.get_prefix_data()
88
+ if not result_data:
89
+ return None
90
+
91
+ network_address = ipaddress.IPv4Address(result_data.free_start)
92
+ return ipaddress.ip_network(f"{network_address}/{target_prefix_length}")
93
+
94
+ async def _get_next_ipv6_prefix(
95
+ self, ip_prefix: IPNetworkType, target_prefix_length: int, at: Timestamp | str | None = None
96
+ ) -> IPNetworkType | None:
97
+ """Get the next available free IPv6 prefix.
98
+
99
+ Uses binary string operations in Cypher to handle IPv6's 128-bit address
100
+ space, as integer values would overflow Neo4j's 64-bit integer type.
101
+
102
+ Args:
103
+ ip_prefix: Parent prefix to allocate from.
104
+ target_prefix_length: Desired prefix length for the new prefix (0-128).
105
+ at: Optional timestamp for point-in-time queries.
106
+
107
+ Returns:
108
+ The next available IPv6 prefix, or None if no space is available
109
+ or if the target_prefix_length is invalid.
110
+ """
111
+ if target_prefix_length < 0 or target_prefix_length > 128:
112
+ return None
113
+ if target_prefix_length < ip_prefix.prefixlen:
114
+ return None
115
+
116
+ query = await IPv6PrefixSubnetFetchFree.init(
117
+ db=self.db,
118
+ branch=self.branch,
119
+ obj=ip_prefix,
120
+ target_prefixlen=target_prefix_length,
121
+ namespace=self.namespace,
122
+ at=at,
123
+ branch_agnostic=self.branch_agnostic,
124
+ )
125
+ await query.execute(db=self.db)
126
+
127
+ result_data = query.get_prefix_data()
128
+ if not result_data:
129
+ return None
130
+
131
+ # Convert binary string to IPv6 address
132
+ addr_int = int(result_data.free_start_bin, 2)
133
+ network_address = ipaddress.IPv6Address(addr_int)
134
+ return ipaddress.ip_network(f"{network_address}/{target_prefix_length}")
135
+
136
+ async def get_next_prefix(
137
+ self, ip_prefix: IPNetworkType, target_prefix_length: int, at: Timestamp | str | None = None
138
+ ) -> IPNetworkType | None:
139
+ """Get the next available free prefix of specified length within a parent prefix.
140
+
141
+ Automatically selects the appropriate method based on IP version (IPv4 vs IPv6).
142
+
143
+ Args:
144
+ ip_prefix: Parent prefix to allocate from.
145
+ target_prefix_length: Desired prefix length for the new prefix.
146
+ at: Optional timestamp for point-in-time queries.
147
+
148
+ Returns:
149
+ The next available prefix, or None if no space is available.
150
+ """
151
+ if ip_prefix.version == 4:
152
+ return await self._get_next_ipv4_prefix(
153
+ ip_prefix=ip_prefix, target_prefix_length=target_prefix_length, at=at
154
+ )
155
+ return await self._get_next_ipv6_prefix(ip_prefix=ip_prefix, target_prefix_length=target_prefix_length, at=at)
156
+
157
+ async def get_next_address(
158
+ self, ip_prefix: IPNetworkType, at: Timestamp | str | None = None, is_pool: bool = False
159
+ ) -> IPAddressType | None:
160
+ """Get the next available free IP address within a prefix.
161
+
162
+ Automatically selects the appropriate query based on IP version (IPv4 vs IPv6).
163
+
164
+ Args:
165
+ ip_prefix: Prefix to allocate an address from.
166
+ at: Optional timestamp for point-in-time queries.
167
+ is_pool: If True, includes network and broadcast addresses as allocatable.
168
+ If False (default), reserves the first and last addresses.
169
+
170
+ Returns:
171
+ The next available IP address, or None if no addresses are available.
172
+ """
173
+ # Use IPv6-specific query for IPv6 to avoid 64-bit integer overflow
174
+ query_class = IPv6PrefixIPAddressFetchFree if ip_prefix.version == 6 else IPPrefixIPAddressFetchFree
175
+ query = await query_class.init(
176
+ db=self.db,
177
+ branch=self.branch,
178
+ obj=ip_prefix,
179
+ namespace=self.namespace,
180
+ at=at,
181
+ branch_agnostic=self.branch_agnostic,
182
+ is_pool=is_pool,
183
+ )
184
+ await query.execute(db=self.db)
185
+ return query.get_address()
186
+
187
+ async def get_subnets(self, ip_prefix: IPNetworkType, at: Timestamp | str | None = None) -> Iterable[IPPrefixData]:
188
+ """Get all subnets within a parent prefix.
189
+
190
+ Args:
191
+ ip_prefix: Parent prefix to query.
192
+ at: Optional timestamp for point-in-time queries.
193
+
194
+ Returns:
195
+ Iterable of IPPrefixData objects representing child subnets.
196
+ """
197
+ query = await IPPrefixSubnetFetch.init(
198
+ db=self.db,
199
+ branch=self.branch,
200
+ obj=ip_prefix,
201
+ namespace=self.namespace,
202
+ at=at,
203
+ branch_agnostic=self.branch_agnostic,
204
+ )
205
+ await query.execute(db=self.db)
206
+ return query.get_subnets()
207
+
208
+ async def get_ip_addresses(
209
+ self, ip_prefix: IPNetworkType, at: Timestamp | str | None = None
210
+ ) -> Iterable[IPAddressData]:
211
+ """Get all IP addresses within a prefix.
212
+
213
+ Args:
214
+ ip_prefix: Prefix to query.
215
+ at: Optional timestamp for point-in-time queries.
216
+
217
+ Returns:
218
+ Iterable of IPAddressData objects representing addresses in the prefix.
219
+ """
220
+ query = await IPPrefixIPAddressFetch.init(
221
+ db=self.db,
222
+ branch=self.branch,
223
+ obj=ip_prefix,
224
+ namespace=self.namespace,
225
+ at=at,
226
+ branch_agnostic=self.branch_agnostic,
227
+ )
228
+ await query.execute(db=self.db)
229
+ return query.get_addresses()
@@ -52,6 +52,11 @@ from .m047_backfill_or_null_display_label import Migration047
52
52
  from .m048_undelete_rel_props import Migration048
53
53
  from .m049_remove_is_visible_relationship import Migration049
54
54
  from .m050_backfill_vertex_metadata import Migration050
55
+ from .m051_subtract_branched_from_microsecond import Migration051
56
+ from .m052_fix_global_branch_level import Migration052
57
+ from .m053_fix_branch_level_zero import Migration053
58
+ from .m054_cleanup_orphaned_nodes import Migration054
59
+ from .m055_remove_webhook_validate_certificates_default import Migration055
55
60
 
56
61
  if TYPE_CHECKING:
57
62
  from ..shared import MigrationTypes
@@ -108,6 +113,11 @@ MIGRATIONS: list[type[MigrationTypes]] = [
108
113
  Migration048,
109
114
  Migration049,
110
115
  Migration050,
116
+ Migration051,
117
+ Migration052,
118
+ Migration053,
119
+ Migration054,
120
+ Migration055,
111
121
  ]
112
122
 
113
123
 
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  from typing import TYPE_CHECKING, Sequence
4
4
 
5
5
  from infrahub.constants.database import IndexType
6
- from infrahub.core.migrations.shared import MigrationResult
6
+ from infrahub.core.migrations.shared import MigrationInput, MigrationResult
7
7
  from infrahub.core.query import Query # noqa: TC001
8
8
  from infrahub.database import DatabaseType
9
9
  from infrahub.database.index import IndexItem
@@ -23,7 +23,8 @@ class Migration014(GraphMigration):
23
23
  queries: Sequence[type[Query]] = []
24
24
  minimum_version: int = 13
25
25
 
26
- async def execute(self, db: InfrahubDatabase) -> MigrationResult:
26
+ async def execute(self, migration_input: MigrationInput) -> MigrationResult:
27
+ db = migration_input.db
27
28
  result = MigrationResult()
28
29
 
29
30
  # Only execute this migration for Neo4j
@@ -4,7 +4,7 @@ from typing import TYPE_CHECKING
4
4
 
5
5
  from infrahub.core import registry
6
6
  from infrahub.core.diff.repository.repository import DiffRepository
7
- from infrahub.core.migrations.shared import MigrationResult
7
+ from infrahub.core.migrations.shared import MigrationInput, MigrationResult
8
8
  from infrahub.dependencies.registry import build_component_registry, get_component_registry
9
9
  from infrahub.log import get_logger
10
10
 
@@ -25,7 +25,8 @@ class Migration015(ArbitraryMigration):
25
25
 
26
26
  return result
27
27
 
28
- async def execute(self, db: InfrahubDatabase) -> MigrationResult:
28
+ async def execute(self, migration_input: MigrationInput) -> MigrationResult:
29
+ db = migration_input.db
29
30
  default_branch = registry.get_branch_from_registry()
30
31
  build_component_registry()
31
32
  component_registry = get_component_registry()
@@ -4,7 +4,7 @@ from typing import TYPE_CHECKING
4
4
 
5
5
  from infrahub.core import registry
6
6
  from infrahub.core.diff.repository.repository import DiffRepository
7
- from infrahub.core.migrations.shared import MigrationResult
7
+ from infrahub.core.migrations.shared import MigrationInput, MigrationResult
8
8
  from infrahub.dependencies.registry import build_component_registry, get_component_registry
9
9
  from infrahub.log import get_logger
10
10
 
@@ -25,7 +25,8 @@ class Migration016(ArbitraryMigration):
25
25
 
26
26
  return result
27
27
 
28
- async def execute(self, db: InfrahubDatabase) -> MigrationResult:
28
+ async def execute(self, migration_input: MigrationInput) -> MigrationResult:
29
+ db = migration_input.db
29
30
  default_branch = registry.get_branch_from_registry()
30
31
  build_component_registry()
31
32
  component_registry = get_component_registry()
@@ -3,8 +3,7 @@ from __future__ import annotations
3
3
  from typing import TYPE_CHECKING, Sequence
4
4
 
5
5
  from infrahub.core import registry
6
- from infrahub.core.constants import SYSTEM_USER_ID
7
- from infrahub.core.migrations.shared import MigrationResult
6
+ from infrahub.core.migrations.shared import MigrationInput, MigrationResult
8
7
  from infrahub.core.schema.definitions.core import core_profile_schema_definition
9
8
  from infrahub.core.schema.manager import SchemaManager
10
9
  from infrahub.log import get_logger
@@ -27,17 +26,20 @@ class Migration017(InternalSchemaMigration):
27
26
 
28
27
  return result
29
28
 
30
- async def execute(self, db: InfrahubDatabase, user_id: str = SYSTEM_USER_ID) -> MigrationResult:
29
+ async def execute(self, migration_input: MigrationInput) -> MigrationResult:
31
30
  """
32
31
  Load CoreProfile schema node in db.
33
32
  """
33
+ db = migration_input.db
34
+ at = migration_input.at
35
+ user_id = migration_input.user_id
34
36
  default_branch = registry.get_branch_from_registry()
35
37
  manager = SchemaManager()
36
38
  manager.set_schema_branch(name=default_branch.name, schema=self.get_internal_schema())
37
39
 
38
40
  db.add_schema(manager.get_schema_branch(default_branch.name))
39
41
  await manager.load_node_to_db(
40
- node=core_profile_schema_definition, db=db, branch=default_branch, user_id=user_id
42
+ node=core_profile_schema_definition, db=db, branch=default_branch, user_id=user_id, at=at
41
43
  )
42
44
 
43
45
  return MigrationResult()
@@ -4,9 +4,8 @@ from collections import defaultdict
4
4
  from typing import TYPE_CHECKING, Sequence
5
5
 
6
6
  from infrahub.core import registry
7
- from infrahub.core.constants import SYSTEM_USER_ID
8
7
  from infrahub.core.diff.payload_builder import get_display_labels_per_kind
9
- from infrahub.core.migrations.shared import MigrationResult
8
+ from infrahub.core.migrations.shared import MigrationInput, MigrationResult
10
9
  from infrahub.core.schema import GenericSchema, NodeSchema, SchemaRoot, internal_schema
11
10
  from infrahub.core.schema.manager import SchemaManager
12
11
  from infrahub.core.validators.uniqueness.checker import UniquenessChecker
@@ -96,5 +95,5 @@ class Migration018(InternalSchemaMigration):
96
95
  async def validate_migration(self, db: InfrahubDatabase) -> MigrationResult: # noqa: ARG002
97
96
  return MigrationResult()
98
97
 
99
- async def execute(self, db: InfrahubDatabase, user_id: str = SYSTEM_USER_ID) -> MigrationResult: # noqa: ARG002
100
- return await validate_nulls_in_uniqueness_constraints(db=db)
98
+ async def execute(self, migration_input: MigrationInput) -> MigrationResult:
99
+ return await validate_nulls_in_uniqueness_constraints(db=migration_input.db)
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  from typing import TYPE_CHECKING, Any, Sequence
4
4
 
5
5
  from infrahub.core.constants.database import DatabaseEdgeType
6
- from infrahub.core.migrations.shared import GraphMigration, MigrationResult
6
+ from infrahub.core.migrations.shared import GraphMigration, MigrationInput, MigrationResult
7
7
  from infrahub.log import get_logger
8
8
 
9
9
  from ...query import Query, QueryType
@@ -140,9 +140,9 @@ class Migration020(GraphMigration):
140
140
  DeleteDuplicateIsProtectedEdgesQuery,
141
141
  ]
142
142
 
143
- async def execute(self, db: InfrahubDatabase) -> MigrationResult:
143
+ async def execute(self, migration_input: MigrationInput) -> MigrationResult:
144
144
  # skip the transaction b/c it will run out of memory on a large database
145
- return await self.do_execute(db=db)
145
+ return await self.do_execute(migration_input=migration_input)
146
146
 
147
147
  async def validate_migration(self, db: InfrahubDatabase) -> MigrationResult: # noqa: ARG002
148
148
  result = MigrationResult()
@@ -2,8 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from typing import TYPE_CHECKING, Sequence
4
4
 
5
- from infrahub.core.constants import SYSTEM_USER_ID
6
- from infrahub.core.migrations.shared import MigrationResult
5
+ from infrahub.core.migrations.shared import MigrationInput, MigrationResult
7
6
  from infrahub.log import get_logger
8
7
 
9
8
  from ..shared import InternalSchemaMigration, SchemaMigration
@@ -23,5 +22,5 @@ class Migration025(InternalSchemaMigration):
23
22
  async def validate_migration(self, db: InfrahubDatabase) -> MigrationResult: # noqa: ARG002
24
23
  return MigrationResult()
25
24
 
26
- async def execute(self, db: InfrahubDatabase, user_id: str = SYSTEM_USER_ID) -> MigrationResult: # noqa: ARG002
27
- return await validate_nulls_in_uniqueness_constraints(db=db)
25
+ async def execute(self, migration_input: MigrationInput) -> MigrationResult:
26
+ return await validate_nulls_in_uniqueness_constraints(db=migration_input.db)
@@ -4,12 +4,10 @@ import ipaddress
4
4
  from typing import TYPE_CHECKING, Sequence
5
5
 
6
6
  from infrahub.core.branch.models import Branch
7
- from infrahub.core.constants import SYSTEM_USER_ID
8
7
  from infrahub.core.initialization import initialization
9
8
  from infrahub.core.ipam.reconciler import IpamReconciler
10
9
  from infrahub.core.manager import NodeManager
11
- from infrahub.core.migrations.shared import MigrationResult
12
- from infrahub.core.timestamp import Timestamp
10
+ from infrahub.core.migrations.shared import MigrationInput, MigrationResult
13
11
  from infrahub.lock import initialize_lock
14
12
  from infrahub.log import get_logger
15
13
 
@@ -29,12 +27,13 @@ class Migration026(InternalSchemaMigration):
29
27
  async def validate_migration(self, db: InfrahubDatabase) -> MigrationResult: # noqa: ARG002
30
28
  return MigrationResult()
31
29
 
32
- async def execute(self, db: InfrahubDatabase, user_id: str = SYSTEM_USER_ID) -> MigrationResult: # noqa: ARG002
30
+ async def execute(self, migration_input: MigrationInput) -> MigrationResult:
31
+ db = migration_input.db
32
+ at = migration_input.at
33
33
  # load schemas from database into registry
34
34
  initialize_lock()
35
35
  await initialization(db=db)
36
36
 
37
- at = Timestamp()
38
37
  for branch in await Branch.get_list(db=db):
39
38
  prefix_0000s = await NodeManager.query(
40
39
  db=db, schema="BuiltinIPPrefix", branch=branch, filters={"prefix__values": ["0.0.0.0/0", "::/0"]}
@@ -4,7 +4,7 @@ from typing import TYPE_CHECKING
4
4
 
5
5
  from infrahub.core import registry
6
6
  from infrahub.core.diff.repository.repository import DiffRepository
7
- from infrahub.core.migrations.shared import MigrationResult
7
+ from infrahub.core.migrations.shared import MigrationInput, MigrationResult
8
8
  from infrahub.dependencies.registry import build_component_registry, get_component_registry
9
9
  from infrahub.log import get_logger
10
10
 
@@ -27,7 +27,8 @@ class Migration028(ArbitraryMigration):
27
27
 
28
28
  return result
29
29
 
30
- async def execute(self, db: InfrahubDatabase) -> MigrationResult:
30
+ async def execute(self, migration_input: MigrationInput) -> MigrationResult:
31
+ db = migration_input.db
31
32
  default_branch = registry.get_branch_from_registry()
32
33
  build_component_registry()
33
34
  component_registry = get_component_registry()
@@ -4,7 +4,7 @@ from typing import TYPE_CHECKING, Any, Literal
4
4
 
5
5
  from infrahub.core.constants import RelationshipDirection
6
6
  from infrahub.core.constants.database import DatabaseEdgeType
7
- from infrahub.core.migrations.shared import MigrationResult
7
+ from infrahub.core.migrations.shared import MigrationInput, MigrationResult
8
8
  from infrahub.core.query import Query, QueryType
9
9
  from infrahub.log import get_logger
10
10
 
@@ -574,8 +574,9 @@ class Migration029(ArbitraryMigration):
574
574
 
575
575
  return result
576
576
 
577
- async def execute(self, db: InfrahubDatabase) -> MigrationResult:
577
+ async def execute(self, migration_input: MigrationInput) -> MigrationResult:
578
578
  migration_result = MigrationResult()
579
+ db = migration_input.db
579
580
  limit = self.limit
580
581
  offset = 0
581
582
  more_nodes_to_process = True
@@ -5,9 +5,9 @@ from typing import TYPE_CHECKING, Sequence
5
5
  from infrahub import config
6
6
  from infrahub.core import registry
7
7
  from infrahub.core.branch import Branch
8
- from infrahub.core.constants import SYSTEM_USER_ID, SchemaPathType
8
+ from infrahub.core.constants import SchemaPathType
9
9
  from infrahub.core.initialization import initialization
10
- from infrahub.core.migrations.shared import InternalSchemaMigration, MigrationResult, SchemaMigration
10
+ from infrahub.core.migrations.shared import InternalSchemaMigration, MigrationInput, MigrationResult, SchemaMigration
11
11
  from infrahub.core.path import SchemaPath
12
12
  from infrahub.core.schema import GenericSchema, NodeSchema
13
13
  from infrahub.core.schema.attribute_parameters import NumberAttributeParameters
@@ -35,7 +35,7 @@ class Migration031(InternalSchemaMigration):
35
35
  minimum_version: int = 30
36
36
  migrations: Sequence[SchemaMigration] = []
37
37
 
38
- async def execute(self, db: InfrahubDatabase, user_id: str = SYSTEM_USER_ID) -> MigrationResult: # noqa: ARG002
38
+ async def execute(self, migration_input: MigrationInput) -> MigrationResult:
39
39
  """Retrieve all number attributes that have a min/max/excluded_values
40
40
  For any of these attributes, check if corresponding existing nodes are valid."""
41
41
 
@@ -43,6 +43,7 @@ class Migration031(InternalSchemaMigration):
43
43
  return MigrationResult()
44
44
 
45
45
  # load schemas from database into registry
46
+ db = migration_input.db
46
47
  initialize_lock()
47
48
  await initialization(db=db)
48
49
 
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from typing import TYPE_CHECKING, Any
4
4
 
5
- from infrahub.core.migrations.shared import MigrationResult
5
+ from infrahub.core.migrations.shared import MigrationInput, MigrationResult
6
6
  from infrahub.core.query import Query, QueryType
7
7
  from infrahub.core.query.branch import DeleteBranchRelationshipsQuery
8
8
  from infrahub.log import get_logger
@@ -68,7 +68,8 @@ class Migration032(ArbitraryMigration):
68
68
  async def validate_migration(self, db: InfrahubDatabase) -> MigrationResult: # noqa: ARG002
69
69
  return MigrationResult()
70
70
 
71
- async def execute(self, db: InfrahubDatabase) -> MigrationResult:
71
+ async def execute(self, migration_input: MigrationInput) -> MigrationResult:
72
+ db = migration_input.db
72
73
  migration_result = MigrationResult()
73
74
 
74
75
  try:
@@ -5,7 +5,7 @@ from typing import TYPE_CHECKING, Any, Sequence
5
5
 
6
6
  from infrahub.core.initialization import initialization
7
7
  from infrahub.core.manager import NodeManager
8
- from infrahub.core.migrations.shared import ArbitraryMigration, MigrationResult
8
+ from infrahub.core.migrations.shared import ArbitraryMigration, MigrationInput, MigrationResult
9
9
  from infrahub.core.timestamp import Timestamp
10
10
  from infrahub.lock import initialize_lock
11
11
  from infrahub.log import get_logger
@@ -59,7 +59,8 @@ class Migration034(ArbitraryMigration):
59
59
  async def validate_migration(self, db: InfrahubDatabase) -> MigrationResult: # noqa: ARG002
60
60
  return MigrationResult()
61
61
 
62
- async def execute(self, db: InfrahubDatabase) -> MigrationResult:
62
+ async def execute(self, migration_input: MigrationInput) -> MigrationResult:
63
+ db = migration_input.db
63
64
  try:
64
65
  initialize_lock()
65
66
  await initialization(db=db)
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from typing import TYPE_CHECKING, Any, Sequence
4
4
 
5
- from infrahub.core.migrations.shared import GraphMigration, MigrationResult
5
+ from infrahub.core.migrations.shared import GraphMigration, MigrationInput, MigrationResult
6
6
 
7
7
  from ...query import Query, QueryType
8
8
 
@@ -38,6 +38,6 @@ class Migration035(GraphMigration):
38
38
  async def validate_migration(self, db: InfrahubDatabase) -> MigrationResult: # noqa: ARG002
39
39
  return MigrationResult()
40
40
 
41
- async def execute(self, db: InfrahubDatabase) -> MigrationResult:
41
+ async def execute(self, migration_input: MigrationInput) -> MigrationResult:
42
42
  # overrides parent class to skip transaction in case there are a lot of relationships to delete
43
- return await self.do_execute(db=db)
43
+ return await self.do_execute(migration_input=migration_input)
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  from typing import TYPE_CHECKING, Sequence
4
4
 
5
5
  from infrahub.constants.database import IndexType
6
- from infrahub.core.migrations.shared import MigrationResult
6
+ from infrahub.core.migrations.shared import MigrationInput, MigrationResult
7
7
  from infrahub.core.query import Query # noqa: TC001
8
8
  from infrahub.database import DatabaseType
9
9
  from infrahub.database.index import IndexItem
@@ -23,7 +23,8 @@ class Migration036(GraphMigration):
23
23
  queries: Sequence[type[Query]] = []
24
24
  minimum_version: int = 35
25
25
 
26
- async def execute(self, db: InfrahubDatabase) -> MigrationResult:
26
+ async def execute(self, migration_input: MigrationInput) -> MigrationResult:
27
+ db = migration_input.db
27
28
  result = MigrationResult()
28
29
 
29
30
  # Only execute this migration for Neo4j
@@ -5,7 +5,7 @@ from typing import TYPE_CHECKING, Any
5
5
 
6
6
  from infrahub.constants.database import IndexType
7
7
  from infrahub.core.attribute import MAX_STRING_LENGTH
8
- from infrahub.core.migrations.shared import MigrationResult, get_migration_console
8
+ from infrahub.core.migrations.shared import MigrationInput, MigrationResult, get_migration_console
9
9
  from infrahub.core.query import Query, QueryType
10
10
  from infrahub.database.index import IndexItem
11
11
  from infrahub.database.neo4j import IndexManagerNeo4j
@@ -463,8 +463,9 @@ class Migration037(ArbitraryMigration):
463
463
 
464
464
  return result
465
465
 
466
- async def execute(self, db: InfrahubDatabase) -> MigrationResult: # noqa: PLR0915
466
+ async def execute(self, migration_input: MigrationInput) -> MigrationResult: # noqa: PLR0915
467
467
  console = get_migration_console()
468
+ db = migration_input.db
468
469
  result = MigrationResult()
469
470
 
470
471
  # find the active schema attributes that have a LARGE_ATTRIBUTE_TYPE kind on all branches
@@ -4,12 +4,10 @@ import ipaddress
4
4
  from typing import TYPE_CHECKING, Sequence
5
5
 
6
6
  from infrahub.core.branch.models import Branch
7
- from infrahub.core.constants import SYSTEM_USER_ID
8
7
  from infrahub.core.initialization import initialization
9
8
  from infrahub.core.ipam.reconciler import IpamReconciler
10
9
  from infrahub.core.manager import NodeManager
11
- from infrahub.core.migrations.shared import MigrationResult
12
- from infrahub.core.timestamp import Timestamp
10
+ from infrahub.core.migrations.shared import MigrationInput, MigrationResult
13
11
  from infrahub.lock import initialize_lock
14
12
  from infrahub.log import get_logger
15
13
 
@@ -38,12 +36,13 @@ class Migration038(InternalSchemaMigration):
38
36
  async def validate_migration(self, db: InfrahubDatabase) -> MigrationResult: # noqa: ARG002
39
37
  return MigrationResult()
40
38
 
41
- async def execute(self, db: InfrahubDatabase, user_id: str = SYSTEM_USER_ID) -> MigrationResult: # noqa: ARG002
39
+ async def execute(self, migration_input: MigrationInput) -> MigrationResult:
40
+ db = migration_input.db
41
+ at = migration_input.at
42
42
  # load schemas from database into registry
43
43
  initialize_lock()
44
44
  await initialization(db=db)
45
45
 
46
- at = Timestamp()
47
46
  for branch in await Branch.get_list(db=db):
48
47
  prefix_0000s = await NodeManager.query(
49
48
  db=db, schema="BuiltinIPPrefix", branch=branch, filters={"prefix__values": ["0.0.0.0/0", "::/0"]}
@@ -10,7 +10,7 @@ from infrahub.core.branch.models import Branch
10
10
  from infrahub.core.constants import InfrahubKind
11
11
  from infrahub.core.initialization import initialization
12
12
  from infrahub.core.ipam.reconciler import IpamReconciler
13
- from infrahub.core.migrations.shared import MigrationResult, get_migration_console
13
+ from infrahub.core.migrations.shared import MigrationInput, MigrationResult, get_migration_console
14
14
  from infrahub.core.query import Query, QueryType
15
15
  from infrahub.lock import initialize_lock
16
16
  from infrahub.log import get_logger
@@ -233,7 +233,8 @@ class Migration039(ArbitraryMigration):
233
233
  async def validate_migration(self, db: InfrahubDatabase) -> MigrationResult: # noqa: ARG002
234
234
  return MigrationResult()
235
235
 
236
- async def execute(self, db: InfrahubDatabase) -> MigrationResult:
236
+ async def execute(self, migration_input: MigrationInput) -> MigrationResult:
237
+ db = migration_input.db
237
238
  console = get_migration_console()
238
239
  result = MigrationResult()
239
240
  # load schemas from database into registry