infrahub-server 1.4.7__py3-none-any.whl → 1.4.9__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.
@@ -50,7 +50,7 @@ core_trigger_rule = GenericSchema(
50
50
  description="Indicates if this trigger is enabled or if it's just prepared, could be useful as you are setting up a trigger",
51
51
  optional=False,
52
52
  default_value=True,
53
- order_weight=200,
53
+ order_weight=250,
54
54
  ),
55
55
  Attr(
56
56
  name="branch_scope",
@@ -59,7 +59,7 @@ core_trigger_rule = GenericSchema(
59
59
  choices=BranchScope.available_types(),
60
60
  default_value=BranchScope.DEFAULT_BRANCH.value.name,
61
61
  optional=False,
62
- order_weight=200,
62
+ order_weight=260,
63
63
  allow_override=AllowOverrideType.NONE,
64
64
  ),
65
65
  ],
@@ -270,8 +270,10 @@ core_node_trigger_attribute_match = NodeSchema(
270
270
  label="Node Trigger Attribute Match",
271
271
  branch=BranchSupportType.AGNOSTIC,
272
272
  generate_profile=False,
273
- inherit_from=["CoreNodeTriggerMatch"],
273
+ inherit_from=[core_node_trigger_match.kind],
274
274
  display_labels=["attribute_name__value"],
275
+ uniqueness_constraints=[["trigger", "attribute_name__value"]],
276
+ human_friendly_id=["trigger__name__value", "attribute_name__value"],
275
277
  attributes=[
276
278
  Attr(
277
279
  name="attribute_name",
@@ -319,8 +321,10 @@ core_node_trigger_relationship_match = NodeSchema(
319
321
  label="Node Trigger Relationship Match",
320
322
  branch=BranchSupportType.AGNOSTIC,
321
323
  generate_profile=False,
322
- inherit_from=["CoreNodeTriggerMatch"],
324
+ inherit_from=[core_node_trigger_match.kind],
323
325
  display_labels=["relationship_name__value", "modification_type__value"],
326
+ uniqueness_constraints=[["trigger", "relationship_name__value"]],
327
+ human_friendly_id=["trigger__name__value", "relationship_name__value"],
324
328
  attributes=[
325
329
  Attr(
326
330
  name="relationship_name",
infrahub/config.py CHANGED
@@ -281,7 +281,6 @@ class DatabaseSettings(BaseSettings):
281
281
  query_size_limit: int = Field(
282
282
  default=5_000,
283
283
  ge=1,
284
- le=20_000,
285
284
  description="The max number of records to fetch in a single query before performing internal pagination.",
286
285
  )
287
286
  max_depth_search_hierarchy: int = Field(
@@ -1 +1 @@
1
- GRAPH_VERSION = 38
1
+ GRAPH_VERSION = 39
@@ -40,6 +40,7 @@ from .m035_orphan_relationships import Migration035
40
40
  from .m036_drop_attr_value_index import Migration036
41
41
  from .m037_index_attr_vals import Migration037
42
42
  from .m038_redo_0000_prefix_fix import Migration038
43
+ from .m039_ipam_reconcile import Migration039
43
44
 
44
45
  if TYPE_CHECKING:
45
46
  from infrahub.core.root import Root
@@ -85,6 +86,7 @@ MIGRATIONS: list[type[GraphMigration | InternalSchemaMigration | ArbitraryMigrat
85
86
  Migration036,
86
87
  Migration037,
87
88
  Migration038,
89
+ Migration039,
88
90
  ]
89
91
 
90
92
 
@@ -0,0 +1,274 @@
1
+ from __future__ import annotations
2
+
3
+ import ipaddress
4
+ from dataclasses import dataclass
5
+ from typing import TYPE_CHECKING, Any
6
+
7
+ from rich.console import Console
8
+ from rich.progress import Progress
9
+
10
+ from infrahub.core.branch.models import Branch
11
+ from infrahub.core.constants import InfrahubKind
12
+ from infrahub.core.initialization import initialization
13
+ from infrahub.core.ipam.reconciler import IpamReconciler
14
+ from infrahub.core.migrations.shared import MigrationResult
15
+ from infrahub.core.query import Query, QueryType
16
+ from infrahub.lock import initialize_lock
17
+ from infrahub.log import get_logger
18
+
19
+ from ..shared import ArbitraryMigration
20
+
21
+ if TYPE_CHECKING:
22
+ from infrahub.core.ipam.constants import AllIPTypes
23
+ from infrahub.database import InfrahubDatabase
24
+
25
+ log = get_logger()
26
+
27
+
28
+ @dataclass
29
+ class IpNodeDetails:
30
+ branch: str
31
+ ip_value: AllIPTypes
32
+ namespace: str
33
+ node_uuid: str
34
+
35
+
36
+ class FindNodesToReconcileQuery(Query):
37
+ name = "find_nodes_to_reconcile_query"
38
+ type = QueryType.READ
39
+ insert_return = False
40
+
41
+ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
42
+ self.params.update(
43
+ {
44
+ "prefix_kind": InfrahubKind.IPPREFIX,
45
+ "address_kind": InfrahubKind.IPADDRESS,
46
+ "prefix_attribute_name": "prefix",
47
+ "address_attribute_name": "address",
48
+ "attr_names": ["prefix", "address"],
49
+ "namespace_relationship_names": ["ip_namespace__ip_prefix", "ip_namespace__ip_address"],
50
+ }
51
+ )
52
+ query = """
53
+ MATCH (root:Root)
54
+ LIMIT 1
55
+ WITH root.default_branch AS default_branch
56
+ // ------------------
57
+ // find prefixes and addresses that exist on the default branch
58
+ // ------------------
59
+ MATCH (ip_node:%(prefix_kind)s|%(address_kind)s)-[e:IS_PART_OF {branch: default_branch, status: "active"}]->(:Root)
60
+ WHERE e.to IS NULL
61
+ AND NOT exists((ip_node)-[:IS_PART_OF {branch: default_branch, status: "deleted"}]->(:Root))
62
+ // ------------------
63
+ // check if this node has its prefix/address updated on a branch (or branches)
64
+ // ------------------
65
+ CALL (ip_node, default_branch) {
66
+ OPTIONAL MATCH (ip_node)-[:HAS_ATTRIBUTE {branch: default_branch, status: "active"}]->
67
+ (attr:Attribute)-[has_value_e:HAS_VALUE {status: "active"}]->(attr_val)
68
+ WHERE attr.name IN $attr_names
69
+ AND has_value_e.branch_level = 2
70
+ AND (
71
+ ($prefix_kind IN labels(ip_node) AND attr.name = $prefix_attribute_name)
72
+ OR ($address_kind IN labels(ip_node) AND attr.name = $address_attribute_name)
73
+ )
74
+ RETURN collect(DISTINCT has_value_e.branch) AS attr_update_branches
75
+ }
76
+ CALL (ip_node, default_branch) {
77
+ OPTIONAL MATCH (ip_node)-[:IS_RELATED {status: "active"}]-
78
+ (rel:Relationship)-[e2:IS_RELATED {status: "active"}]-(peer:Node)
79
+ WHERE rel.name IN $namespace_relationship_names
80
+ AND e2.branch_level = 2
81
+ RETURN collect(DISTINCT e2.branch) AS namespace_update_branches
82
+ }
83
+ // ------------------
84
+ // filter to only those prefixes/addresses with an update that we care about on a branch
85
+ // ------------------
86
+ WITH DISTINCT ip_node, default_branch, attr_update_branches, namespace_update_branches
87
+ WHERE size(attr_update_branches) > 0 OR size(namespace_update_branches) > 0
88
+ // ------------------
89
+ // deduplicate branch lists and return one row for each branch
90
+ // ------------------
91
+ CALL (attr_update_branches, namespace_update_branches) {
92
+ UNWIND attr_update_branches + namespace_update_branches AS branch
93
+ RETURN DISTINCT branch
94
+ }
95
+ WITH default_branch, branch, ip_node
96
+ // ------------------
97
+ // confirm node is still active on this branch
98
+ // ------------------
99
+ MATCH (ip_node)
100
+ WHERE NOT exists((ip_node)-[:IS_PART_OF {branch: branch, status: "deleted"}]->(:Root))
101
+ // ------------------
102
+ // get branched_from time for each branch
103
+ // ------------------
104
+ CALL (branch) {
105
+ MATCH (b:Branch {name: branch})
106
+ RETURN b.branched_from AS branched_from
107
+ }
108
+ // ------------------
109
+ // get latest namespace on this branch
110
+ // ------------------
111
+ CALL (default_branch, branch, branched_from, ip_node) {
112
+ MATCH (ip_node)-[e1:IS_RELATED]-(rel:Relationship)-[e2:IS_RELATED]-(peer:%(namespace_kind)s)
113
+ WHERE rel.name IN $namespace_relationship_names
114
+ AND (
115
+ e1.branch = branch
116
+ OR (e1.branch = default_branch AND e1.from < branched_from)
117
+ )
118
+ AND e1.to IS NULL
119
+ AND (
120
+ e2.branch = branch
121
+ OR (e2.branch = default_branch AND e2.from < branched_from)
122
+ )
123
+ AND e2.to IS NULL
124
+ WITH peer, e1.status = "active" AND e2.status = "active" AS is_active
125
+ ORDER BY e2.branch_level DESC, e2.from DESC, e2.status ASC, e1.branch_level DESC, e1.from DESC, e1.status ASC
126
+ LIMIT 1
127
+ WITH peer
128
+ WHERE is_active = TRUE
129
+ RETURN peer.uuid AS namespace_uuid
130
+ }
131
+ // ------------------
132
+ // get latest prefix/address value on this branch
133
+ // ------------------
134
+ CALL (default_branch, branch, branched_from, ip_node) {
135
+ MATCH (ip_node)-[e1:HAS_ATTRIBUTE]->(attr:Attribute)-[e2:HAS_VALUE]->(av)
136
+ WHERE attr.name IN $attr_names
137
+ AND (
138
+ ($prefix_kind IN labels(ip_node) AND attr.name = $prefix_attribute_name)
139
+ OR ($address_kind IN labels(ip_node) AND attr.name = $address_attribute_name)
140
+ )
141
+ AND (
142
+ e1.branch = branch
143
+ OR (e1.branch = default_branch AND e1.from < branched_from)
144
+ )
145
+ AND e1.to IS NULL
146
+ AND (
147
+ e2.branch = branch
148
+ OR (e2.branch = default_branch AND e2.from < branched_from)
149
+ )
150
+ AND e2.to IS NULL
151
+ WITH attr, av, e1.status = "active" AND e2.status = "active" AS is_active
152
+ ORDER BY e2.branch_level DESC, e2.from DESC, e2.status ASC, e1.branch_level DESC, e1.from DESC, e1.status ASC
153
+ LIMIT 1
154
+ WITH attr, av
155
+ WHERE is_active = TRUE
156
+ RETURN CASE
157
+ WHEN attr.name = $prefix_attribute_name THEN av.value
158
+ ELSE NULL
159
+ END AS prefix_value,
160
+ CASE
161
+ WHEN attr.name = $address_attribute_name THEN av.value
162
+ ELSE NULL
163
+ END AS address_value
164
+ }
165
+ RETURN branch, namespace_uuid, ip_node.uuid AS node_uuid, prefix_value, address_value
166
+ """ % {
167
+ "prefix_kind": InfrahubKind.IPPREFIX,
168
+ "address_kind": InfrahubKind.IPADDRESS,
169
+ "namespace_kind": InfrahubKind.IPNAMESPACE,
170
+ }
171
+ self.add_to_query(query)
172
+ self.return_labels = ["branch", "namespace_uuid", "node_uuid", "prefix_value", "address_value"]
173
+
174
+ def get_nodes_to_reconcile(self) -> list[IpNodeDetails]:
175
+ ip_node_details = []
176
+ for result in self.get_results():
177
+ prefix_value = result.get_as_str("prefix_value")
178
+ address_value = result.get_as_str("address_value")
179
+ if prefix_value:
180
+ ip_value: AllIPTypes = ipaddress.ip_network(address=prefix_value)
181
+ elif address_value:
182
+ ip_value = ipaddress.ip_interface(address=address_value)
183
+ else:
184
+ continue
185
+ ip_node_details.append(
186
+ IpNodeDetails(
187
+ branch=result.get_as_type("branch", str),
188
+ ip_value=ip_value,
189
+ namespace=result.get_as_type("namespace_uuid", str),
190
+ node_uuid=result.get_as_type("node_uuid", str),
191
+ )
192
+ )
193
+ return ip_node_details
194
+
195
+
196
+ class DeleteSelfParentRelationshipsQuery(Query):
197
+ name = "delete_self_parent_relationships"
198
+ type = QueryType.WRITE
199
+ insert_return = False
200
+
201
+ def __init__(self, uuids_to_check: list[str], **kwargs: Any) -> None:
202
+ super().__init__(**kwargs)
203
+ self.uuids_to_check = uuids_to_check
204
+
205
+ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
206
+ self.params["uuids_to_check"] = self.uuids_to_check
207
+ query = """
208
+ MATCH (n:Node)-[e1:IS_RELATED]->(:Relationship {name: "parent__child"})-[e2:IS_RELATED {branch: e1.branch, status: e1.status, from: e1.from}]->(n)
209
+ WHERE n.uuid IN $uuids_to_check
210
+ DELETE e1, e2
211
+ """
212
+ self.add_to_query(query)
213
+
214
+
215
+ class Migration039(ArbitraryMigration):
216
+ """
217
+ Identify all IP prefixes/addresses that have been updated on a branch and reconcile them on that branch
218
+ If any of the identified IP prefixes/addresses are their own parent/child, delete those illegal edges before reconciling.
219
+ """
220
+
221
+ name: str = "039_ipam_reconcile_updated"
222
+ minimum_version: int = 38
223
+
224
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
225
+ super().__init__(*args, **kwargs)
226
+ self._reconcilers_by_branch: dict[str, IpamReconciler] = {}
227
+
228
+ async def _get_reconciler(self, db: InfrahubDatabase, branch_name: str) -> IpamReconciler:
229
+ if branch_name not in self._reconcilers_by_branch:
230
+ branch = await Branch.get_by_name(db=db, name=branch_name)
231
+ self._reconcilers_by_branch[branch_name] = IpamReconciler(db=db, branch=branch)
232
+ return self._reconcilers_by_branch[branch_name]
233
+
234
+ async def validate_migration(self, db: InfrahubDatabase) -> MigrationResult: # noqa: ARG002
235
+ return MigrationResult()
236
+
237
+ async def execute(self, db: InfrahubDatabase) -> MigrationResult:
238
+ console = Console()
239
+ result = MigrationResult()
240
+ # load schemas from database into registry
241
+ initialize_lock()
242
+ await initialization(db=db)
243
+
244
+ console.print("Identifying IP prefixes/addresses to reconcile...", end="")
245
+ find_nodes_query = await FindNodesToReconcileQuery.init(db=db)
246
+ await find_nodes_query.execute(db=db)
247
+ console.print("done")
248
+
249
+ # we need to delete the self-parent relationships before reconciling b/c the
250
+ # reconciler cannot correctly handle a prefix that is its own parent
251
+ ip_node_details_list = find_nodes_query.get_nodes_to_reconcile()
252
+ uuids_to_check = {ip_node_details.node_uuid for ip_node_details in ip_node_details_list}
253
+ console.print(f"{len(ip_node_details_list)} IP prefixes/addresses will be reconciled")
254
+
255
+ console.print("Deleting any self-parent relationships...", end="")
256
+ delete_self_parent_relationships_query = await DeleteSelfParentRelationshipsQuery.init(
257
+ db=db, uuids_to_check=list(uuids_to_check)
258
+ )
259
+ await delete_self_parent_relationships_query.execute(db=db)
260
+ console.print("done")
261
+
262
+ with Progress() as progress:
263
+ reconcile_task = progress.add_task("Reconciling IP prefixes/addresses...", total=len(ip_node_details_list))
264
+
265
+ for ip_node_details in ip_node_details_list:
266
+ reconciler = await self._get_reconciler(db=db, branch_name=ip_node_details.branch)
267
+ await reconciler.reconcile(
268
+ ip_value=ip_node_details.ip_value,
269
+ namespace=ip_node_details.namespace,
270
+ node_uuid=ip_node_details.node_uuid,
271
+ )
272
+ progress.update(reconcile_task, advance=1)
273
+
274
+ return result
@@ -31,7 +31,7 @@ WHERE e.branch = $branch_name
31
31
  CALL (n) {
32
32
  OPTIONAL MATCH (n)-[:IS_RELATED {branch: $global_branch_name}]-(rel:Relationship)
33
33
  DETACH DELETE rel
34
- } IN TRANSACTIONS
34
+ } IN TRANSACTIONS OF 500 ROWS
35
35
 
36
36
  // reduce the results to a single row
37
37
  WITH 1 AS one
@@ -44,7 +44,7 @@ MATCH (s)-[r]->(d)
44
44
  WHERE r.branch = $branch_name
45
45
  CALL (r) {
46
46
  DELETE r
47
- } IN TRANSACTIONS
47
+ } IN TRANSACTIONS OF 500 ROWS
48
48
 
49
49
  // --------------
50
50
  // get the database IDs of every vertex linked to a deleted edge
@@ -61,7 +61,7 @@ CALL (vertex_id) {
61
61
  WHERE elementId(n) = vertex_id
62
62
  AND NOT exists((n)--())
63
63
  DELETE n
64
- } IN TRANSACTIONS
64
+ } IN TRANSACTIONS OF 500 ROWS
65
65
  """
66
66
  self.params["branch_name"] = self.branch_name
67
67
  self.params["global_branch_name"] = GLOBAL_BRANCH_NAME
@@ -871,6 +871,9 @@ class RelationshipGetQuery(RelationshipQuery):
871
871
  query = """
872
872
  MATCH (s)%s(rl:Relationship { name: $name })%s(d)
873
873
  WHERE %s
874
+ ORDER BY r1.branch_level DESC, r1.from DESC, r1.status ASC, r2.branch_level DESC, r2.from DESC, r2.status ASC
875
+ WITH *, r1.status = "active" AND r2.status = "active" AS is_active
876
+ LIMIT 1
874
877
  """ % (
875
878
  r1,
876
879
  r2,
@@ -880,7 +883,20 @@ class RelationshipGetQuery(RelationshipQuery):
880
883
  self.params["at"] = self.at.to_string()
881
884
 
882
885
  self.add_to_query(query)
883
- self.return_labels = ["s", "d", "rl", "r1", "r2"]
886
+ self.return_labels = ["s", "d", "rl", "r2", "is_active"]
887
+
888
+ def is_already_deleted(self) -> bool:
889
+ result = self.get_result()
890
+ if not result:
891
+ return False
892
+ return result.get("is_active") is False
893
+
894
+ def get_relationships_ids_for_branch(self, branch_name: str) -> list[str] | None:
895
+ result = self.get_result()
896
+ if not result:
897
+ return None
898
+
899
+ return [rel.element_id for rel in result.get_rels() if rel.get("branch") == branch_name]
884
900
 
885
901
 
886
902
  class RelationshipGetByIdentifierQuery(Query):
@@ -90,7 +90,7 @@ async def build_subquery_filter(
90
90
  {branch_level_str} AS branch_level,
91
91
  {froms_str} AS froms,
92
92
  all(r IN relationships(path) WHERE r.status = "active") AS is_active{with_extra}
93
- ORDER BY branch_level DESC, froms[-1] DESC, froms[-2] DESC
93
+ ORDER BY branch_level DESC, froms[-1] DESC, froms[-2] DESC, is_active DESC
94
94
  WITH head(collect([is_active, {node_alias}{with_extra}])) AS latest_node_details
95
95
  WHERE {is_active_filter}
96
96
  WITH latest_node_details[1] AS {prefix}{final_with_extra}
@@ -176,7 +176,7 @@ async def build_subquery_order(
176
176
  OPTIONAL MATCH path = {filter_str}
177
177
  WHERE {where_str}
178
178
  WITH {with_str_to_alias}
179
- ORDER BY branch_level DESC, froms[-1] DESC, froms[-2] DESC
179
+ ORDER BY branch_level DESC, froms[-1] DESC, froms[-2] DESC, is_active DESC
180
180
  WITH head(collect([is_active, {with_str_alias}])) AS latest_node_details
181
181
  WITH {with_str_from_list}
182
182
  RETURN {to_return_str}
@@ -404,17 +404,21 @@ class Relationship(FlagPropertyMixin, NodePropertyMixin):
404
404
  db=db, source=node, destination=peer, rel=self, branch=self.branch, at=delete_at
405
405
  )
406
406
  await get_query.execute(db=db)
407
- result = get_query.get_result()
408
- if not result:
407
+
408
+ rel_ids_to_update = get_query.get_relationships_ids_for_branch(branch_name=branch.name)
409
+ if rel_ids_to_update is None:
409
410
  raise Error(
410
411
  f"Unable to find the relationship to delete. id: {self.id}, source: {node.id}, destination: {peer.id}"
411
412
  )
412
413
 
414
+ if get_query.is_already_deleted():
415
+ return
416
+
413
417
  # when we remove a relationship we need to :
414
418
  # - Update the existing relationship if we are on the same branch
415
419
  # - Create a new rel of type DELETED in the right branch
416
420
 
417
- if rel_ids_to_update := [rel.element_id for rel in result.get_rels() if rel.get("branch") == branch.name]:
421
+ if rel_ids_to_update:
418
422
  await update_relationships_to(rel_ids_to_update, to=delete_at, db=db)
419
423
 
420
424
  delete_query = await RelationshipDeleteQuery.init(
@@ -28,6 +28,9 @@ from typing_extensions import Self
28
28
  from infrahub import config, lock
29
29
  from infrahub.constants.database import DatabaseType, Neo4jRuntime
30
30
  from infrahub.core import registry
31
+ from infrahub.core.constants import (
32
+ GLOBAL_BRANCH_NAME,
33
+ )
31
34
  from infrahub.core.query import QueryType
32
35
  from infrahub.exceptions import DatabaseError
33
36
  from infrahub.log import get_logger
@@ -125,9 +128,14 @@ class DatabaseSchemaManager:
125
128
  return self.get_full(branch=branch, duplicate=duplicate)
126
129
 
127
130
  def get_schema_branch(self, name: str) -> SchemaBranch:
128
- if name not in self._db._schemas:
129
- return registry.schema.get_schema_branch(name=name)
130
- return self._db._schemas[name]
131
+ """Return a schema branch object based on its name.
132
+
133
+ If the branch is the global one, the default branch will be returned.
134
+ """
135
+ branch_name = registry.default_branch if name == GLOBAL_BRANCH_NAME else name
136
+ if branch_name not in self._db._schemas:
137
+ return registry.schema.get_schema_branch(name=branch_name)
138
+ return self._db._schemas[branch_name]
131
139
 
132
140
 
133
141
  class InfrahubDatabase:
infrahub/git/base.py CHANGED
@@ -716,7 +716,7 @@ class InfrahubRepositoryBase(BaseModel, ABC):
716
716
 
717
717
  repo = self.get_git_repo_main()
718
718
  try:
719
- repo.remotes.origin.fetch()
719
+ repo.remotes.origin.fetch(prune=True)
720
720
  except GitCommandError as exc:
721
721
  await self._raise_enriched_error(error=exc)
722
722
 
@@ -44,6 +44,11 @@ async def validate_namespace(
44
44
  db=db, branch=branch, kind=InfrahubKind.IPNAMESPACE, id=data["ip_namespace"]["id"]
45
45
  )
46
46
  namespace_id = namespace.id
47
+ elif "hfid" in data["ip_namespace"]:
48
+ namespace = await registry.manager.get_one_by_hfid(
49
+ db=db, branch=branch, kind=InfrahubKind.IPNAMESPACE, hfid=data["ip_namespace"]["hfid"]
50
+ )
51
+ namespace_id = namespace.id
47
52
  else:
48
53
  raise ValidationError(
49
54
  "A valid ip_namespace must be provided or ip_namespace should be left empty in order to use the default value."
@@ -441,9 +441,6 @@ async def run_proposed_change_schema_integrity_check(model: RequestProposedChang
441
441
  )
442
442
  )
443
443
 
444
- if not conflicts:
445
- return
446
-
447
444
  database = await get_database()
448
445
  async with database.start_transaction() as db:
449
446
  object_conflict_validator_recorder = ObjectConflictValidatorRecorder(
infrahub/worker.py CHANGED
@@ -1,3 +1,14 @@
1
1
  import uuid
2
2
 
3
+ from prometheus_client import Gauge
4
+
5
+ from infrahub import __version__ as infrahub_version
6
+
3
7
  WORKER_IDENTITY = str(uuid.uuid4())
8
+
9
+ INFO_METRIC = Gauge(
10
+ "infrahub_info",
11
+ "Information about this Infrahub instance",
12
+ labelnames=["version", "worker_id"],
13
+ )
14
+ INFO_METRIC.labels(version=infrahub_version, worker_id=WORKER_IDENTITY).set(1)
@@ -299,7 +299,7 @@ PROPOSED_CHANGE_MERGE = WorkflowDefinition(
299
299
 
300
300
  GRAPHQL_QUERY_GROUP_UPDATE = WorkflowDefinition(
301
301
  name="graphql-query-group-update",
302
- type=WorkflowType.CORE,
302
+ type=WorkflowType.INTERNAL,
303
303
  module="infrahub.groups.tasks",
304
304
  function="update_graphql_query_group",
305
305
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: infrahub-server
3
- Version: 1.4.7
3
+ Version: 1.4.9
4
4
  Summary: Infrahub is taking a new approach to Infrastructure Management by providing a new generation of datastore to organize and control all the data that defines how an infrastructure should run.
5
5
  License: Apache-2.0
6
6
  Author: OpsMill
@@ -4,7 +4,7 @@ infrahub/actions/constants.py,sha256=xrVNdwBwCzG20eXfowV3bia3LW8Kwx-DazS6vALPbEg
4
4
  infrahub/actions/gather.py,sha256=s6RaegkD9zx7WL8ePS6eGam8TlUA3TH38tarLmQeT98,4746
5
5
  infrahub/actions/models.py,sha256=7EVJuGLqEy71sop1XEDLpuAZfLc9ei3hxXPy2FeyY4U,8558
6
6
  infrahub/actions/parsers.py,sha256=L0ZE2gvhSoBZHuHok0wO4UeWo8fyhbnpuMTHHZX_W7c,3997
7
- infrahub/actions/schema.py,sha256=rWZL7TXoPAwQr6olIRs_3G63DHpjIwTTxgSgyl2AAVU,12813
7
+ infrahub/actions/schema.py,sha256=tFLVFEOckxIdtrNqZVdVGuhf7UVACG6CIM6QG-Nj3ks,13111
8
8
  infrahub/actions/tasks.py,sha256=Oaz6sku7E_2aadh4fFIjDeZn9YUGIY6zhzVlctQ3xbw,3820
9
9
  infrahub/actions/triggers.py,sha256=5BKt8NkafArs8tdSQUb2uBtJVXfZrYUePByOn9d7-1Y,772
10
10
  infrahub/api/__init__.py,sha256=dtRtBRpEgt7Y9Zdwy85jpSr8qfO_2xNTgTQLCJPQiZI,2182
@@ -55,7 +55,7 @@ infrahub/computed_attribute/gather.py,sha256=xhH4dsgCjRFyFshns4Iu3sloe5m1bVMRdeQ
55
55
  infrahub/computed_attribute/models.py,sha256=P_MijLwCVd7394oyTTfYQ3HmX5wIF966jdchuZaLRbs,17361
56
56
  infrahub/computed_attribute/tasks.py,sha256=FMNJYPuLp2tBKP-ENNUlZhc6nkq78yl7817mCKTBt2g,17415
57
57
  infrahub/computed_attribute/triggers.py,sha256=ve1cUj0CZ7dU1VtZkxET9LD8StszKIL9mCkTZpCeUaI,2304
58
- infrahub/config.py,sha256=nRGw9pTxRnfDgXh54tRTdHbatiOF8CuX-_MP2fpAuOI,38976
58
+ infrahub/config.py,sha256=XV_dLvHnpb5zvgi_jkVZdsId481Jbs6VGWvNwYMkTTw,38957
59
59
  infrahub/constants/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
60
60
  infrahub/constants/database.py,sha256=WmV1iuOk4xulxZHOVvO3sS_VF1eTf7fKh0TPe_RnfV4,507
61
61
  infrahub/constants/environment.py,sha256=ry-6qsBzSumOjjiq1D3XNoquf1LWqFKiQSJj8t6nET4,32
@@ -139,7 +139,7 @@ infrahub/core/diff/repository/deserializer.py,sha256=bhN9ao8HxqKyRz273QGLNV9z9_S
139
139
  infrahub/core/diff/repository/repository.py,sha256=u0QTMY1e2dknG_DuRAwzFt-Lp1_mdj5lqF2ymt77k9E,25581
140
140
  infrahub/core/diff/tasks.py,sha256=jSXlenTJ5Fc189Xvm971e3-gBDRnfN19cxNaWvEFwAE,3306
141
141
  infrahub/core/enums.py,sha256=qGbhRVoH43Xi0iDkUfWdQiKapJbLT9UKsCobFk_paIk,491
142
- infrahub/core/graph/__init__.py,sha256=O8Xci_50VdpSOWWUsegCGQvL7gUWJAJNc1ompQbvhf0,19
142
+ infrahub/core/graph/__init__.py,sha256=pqEHefyIWiA492sH7qk0HW4SxWc4ugXBFIhpI4DyvFY,19
143
143
  infrahub/core/graph/constraints.py,sha256=lmuzrKDFoeSKRiLtycB9PXi6zhMYghczKrPYvfWyy90,10396
144
144
  infrahub/core/graph/index.py,sha256=A9jzEE_wldBJsEsflODeMt4GM8sPmmbHAJRNdFioR1k,1736
145
145
  infrahub/core/graph/schema.py,sha256=o50Jcy6GBRk55RkDJSMIDDwHhLD7y_RWOirI9rCex4A,10776
@@ -158,7 +158,7 @@ infrahub/core/ipam/utilization.py,sha256=d-zpXCaWsHgJxBLopCDd7y4sJYvHcIzzpYhbTMI
158
158
  infrahub/core/manager.py,sha256=xMXPwlaGNnghkRUW0ILwJAUlBQJZqo9cGp9GVyqkqYk,47564
159
159
  infrahub/core/merge.py,sha256=TNZpxjNYcl3dnvE8eYXaWSXFDYeEa8DDsS9XbR2XKlA,11217
160
160
  infrahub/core/migrations/__init__.py,sha256=dIExw90CrdTByeJqpiWkaZBclpAfzatG2H6fXx54su0,1305
161
- infrahub/core/migrations/graph/__init__.py,sha256=8NNpXMWWxKbuliktUJg7JllIePGERZxOnumC-UmkpX0,4161
161
+ infrahub/core/migrations/graph/__init__.py,sha256=nCm3XHpKwSrekrOU0WFMVJlnIdJmf9KayjjERIYGx7Q,4225
162
162
  infrahub/core/migrations/graph/m001_add_version_to_graph.py,sha256=YcLN6cFjE6IGheXR4Ujb6CcyY8bJ7WE289hcKJaENOc,1515
163
163
  infrahub/core/migrations/graph/m002_attribute_is_default.py,sha256=wB6f2N_ChTvGajqHD-OWCG5ahRMDhhXZuwo79ieq_II,1036
164
164
  infrahub/core/migrations/graph/m003_relationship_parent_optional.py,sha256=Aya-s98XfE9C7YluOwEjilwgnjaBnZxp27w_Xdv_NmU,2330
@@ -197,6 +197,7 @@ infrahub/core/migrations/graph/m035_orphan_relationships.py,sha256=K0J5gzFF5gY-Q
197
197
  infrahub/core/migrations/graph/m036_drop_attr_value_index.py,sha256=z2BplzX0mue3lOxrM7xnWDNrs7N3TGdFKHZR-u0wDDY,1439
198
198
  infrahub/core/migrations/graph/m037_index_attr_vals.py,sha256=bJB4yPWE73XA_ErUcnY90CR09_jbtA0jW6tE5U0GvQ4,22730
199
199
  infrahub/core/migrations/graph/m038_redo_0000_prefix_fix.py,sha256=8seWnXQhgEJDFLWxYHVcnMNDPcHq5C24c0RYrtn_WGE,2411
200
+ infrahub/core/migrations/graph/m039_ipam_reconcile.py,sha256=gUf4Fo3CrzJ2hwbaKlQclripTDrI7cVk_GHsBlBNMKE,10916
200
201
  infrahub/core/migrations/query/__init__.py,sha256=JoWOUWlV6IzwxWxObsfCnAAKUOHJkE7dZlOsfB64ZEo,876
201
202
  infrahub/core/migrations/query/attribute_add.py,sha256=oitzB-PPAclfyNtcwCWJY3RdI5Zi4oEnR62BDzn1UQk,4835
202
203
  infrahub/core/migrations/query/attribute_rename.py,sha256=onb9Nanht1Tz47JgneAcFsuhqqvPS6dvI2nNjRupLLo,6892
@@ -238,15 +239,15 @@ infrahub/core/protocols.py,sha256=CXwYfHHUgJIFMZvsv9Fc8VBAfvXDzy7Bu4RJvQNj6no,12
238
239
  infrahub/core/protocols_base.py,sha256=cEi6giHtEUmaD0JWfDfWHJhEv_6wjaBA3oJRJCbvc6Q,3411
239
240
  infrahub/core/query/__init__.py,sha256=2qIMaODLwJ6pK6BUd5vODTlA15Aecf5I8_-J44UlCso,23089
240
241
  infrahub/core/query/attribute.py,sha256=xojZIHX-XfXlN_jgM1TQ1Bp4dXr4oLEWlr2A7igTvIg,12658
241
- infrahub/core/query/branch.py,sha256=7gj83jDWPWjFUZud7lMQ0xwl9ag3FL-ZOlmY5Kuq7UU,4307
242
+ infrahub/core/query/branch.py,sha256=aIYyDxpnw_Zw2lqTnMEVlhPUaYckZtJJJU1SFUht1o0,4343
242
243
  infrahub/core/query/delete.py,sha256=7tPP1qtNV6QGYtmgE1RKsuQ9oxENnMTVkttLvJ2PiKg,1927
243
244
  infrahub/core/query/diff.py,sha256=jJCkZRo5jGaf-yPAnQ_5ju6sCnknDK0E7vGpqEnaU_k,36881
244
245
  infrahub/core/query/ipam.py,sha256=dOs_LZr-DONrCPw6t5Ug9mBPn8a-S2NKja3Vr-zIeaM,34523
245
246
  infrahub/core/query/node.py,sha256=OfWS9PfltP89aU4n0KhEjrvAkhAGj9Vl4hcfKcE9LD8,70969
246
- infrahub/core/query/relationship.py,sha256=KmS9zrcr-RViXxiITXOjq1t0s-AfsICHk3wyyirZBfA,47817
247
+ infrahub/core/query/relationship.py,sha256=GpaEcf8YRiVpqTxrp10NFOUCHeyE7SqhOFyf3F44eNo,48474
247
248
  infrahub/core/query/resource_manager.py,sha256=uSvs1WZmdbyt_PjaUi9lXnYdPt-lhJV1RjYoUHYjQdk,16620
248
249
  infrahub/core/query/standard_node.py,sha256=mPBXyqk4RzoWRUX4NoojoVi8zk-sJ03GmzmUaWqOgSI,4825
249
- infrahub/core/query/subquery.py,sha256=UE071w3wccdU_dtKLV-7mdeQ53DKXjPmNxDV0zd5Tpg,7588
250
+ infrahub/core/query/subquery.py,sha256=5ckxREMrlrELWKCcN_JqwmSHRRE7U3ry2iT_WKI7ARE,7620
250
251
  infrahub/core/query/task.py,sha256=tLgn8S_KaLYLuOB66D1YM155teHZIHNThkt2iUiKKD4,3137
251
252
  infrahub/core/query/task_log.py,sha256=2RdthOAQrmpKZU8uhV_dJCPqwdsSA_1CYSKpL_eZ_yk,1120
252
253
  infrahub/core/query/utils.py,sha256=t9LMvZWdmi10c3E0HAU_5m7x5zMHhYXsUjX7ZBl2RpU,1091
@@ -259,7 +260,7 @@ infrahub/core/relationship/constraints/peer_kind.py,sha256=Bropiav4y6r0iU2KfWJ_k
259
260
  infrahub/core/relationship/constraints/peer_parent.py,sha256=z7elpC8xS_ovAF28Haq-RNpFtTEiUehzowiDgYGT68U,2343
260
261
  infrahub/core/relationship/constraints/peer_relatives.py,sha256=Ye79l7njaWxZkU2chTOaptIjvKBIawsNCl0IQxCTDtM,2737
261
262
  infrahub/core/relationship/constraints/profiles_kind.py,sha256=nEZPGtGcmelZ1Nb8EPcQ-7_zCLCNIYwwWbU6C9fLj5E,2464
262
- infrahub/core/relationship/model.py,sha256=mVptkvzEQJXORagSPK-FUjIWito1Sx6BlIMskp_EgxY,47173
263
+ infrahub/core/relationship/model.py,sha256=pfx6BXu3OG_Ew0mk5U3F1VuXBRjGlAqYhaQ9aUwdhLQ,47223
263
264
  infrahub/core/root.py,sha256=8ZLSOtnmjQcrjqX2vxNO-AGopEUArmBPo_X5NeZBdP0,416
264
265
  infrahub/core/schema/__init__.py,sha256=Tif-BUwYWVQ0PJGZHFog6lFgnwZevXk3iBcr3zK__BU,4192
265
266
  infrahub/core/schema/attribute_parameters.py,sha256=ABL1GEsOl4_CcDvK9_NucGMaF6LUeOjAxbDQVm_G7eg,6516
@@ -351,7 +352,7 @@ infrahub/core/validators/uniqueness/checker.py,sha256=5WbYjS4yfezsK0Ez35Vp9soJ9K
351
352
  infrahub/core/validators/uniqueness/index.py,sha256=Jw1o-UVinQquNduZ5vCCzt8GUfIEdVzBo-1XyRti8F8,5068
352
353
  infrahub/core/validators/uniqueness/model.py,sha256=Z5CyYOQfhyAnwNIev4AFjfXnfOoUWc4uR04Wz3C6Cy4,5617
353
354
  infrahub/core/validators/uniqueness/query.py,sha256=0LXhPqRpV4Ho2CLxHP2fDs8AFvKJPKpUfHiW4SwFccg,22254
354
- infrahub/database/__init__.py,sha256=EFr0jC-PB-TKo4LkDXjW2rvN_PMWyQYKBneJ-g79wnk,20848
355
+ infrahub/database/__init__.py,sha256=8d-SCvRddc0pszhr2NxBOdv-NjvC3TxxuB6GZKnySws,21170
355
356
  infrahub/database/index.py,sha256=ATLqw9Grqbq7haGGm14VSEPmcPniid--YATiffo4sA0,1676
356
357
  infrahub/database/memgraph.py,sha256=Fg3xHP9s0MiBBmMvcEmsJvuIUSq8U_XCS362HDE9d1s,1742
357
358
  infrahub/database/metrics.py,sha256=xU4OSKFbsxcw_yZlt_39PmGtF7S7yPbPuOIlSCu5sI0,739
@@ -436,7 +437,7 @@ infrahub/generators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSu
436
437
  infrahub/generators/models.py,sha256=9qhSfsoG-uYux35HClAxSq7TRfkosqN3i_eQkeTokLs,1916
437
438
  infrahub/generators/tasks.py,sha256=Ci6lIbnUS6faGzbUjw1ggROpv17guZ-Z9HH9f6cAZv4,9563
438
439
  infrahub/git/__init__.py,sha256=KeQ9U8UI5jDj6KB6j00Oal7MZmtOD9vKqVgiezG_EQA,281
439
- infrahub/git/base.py,sha256=5zfBUDY9s7nZJsSw0LOFItVDZBep9Z0LmIsbvd_47IE,38706
440
+ infrahub/git/base.py,sha256=tEfhxYNc8bAcq1Pld7ZSK41w1fm48eMsF5QnMSKz50E,38716
440
441
  infrahub/git/constants.py,sha256=XpzcAkXbsgXZgrXey74id1sXV8Q6EHb_4FNw7BndxyY,106
441
442
  infrahub/git/directory.py,sha256=fozxLXXJPweHG95yQwQkR5yy3sfTdmHiczCAJnsUX54,861
442
443
  infrahub/git/integrator.py,sha256=fpeOC1ycVYZixPcrR-TwmZXHgaAvXpPd50ys04GFXdg,62889
@@ -488,7 +489,7 @@ infrahub/graphql/mutations/diff.py,sha256=UfEkgIeKsxr79U0_ih7mhl0986rFITM_GDXevs
488
489
  infrahub/graphql/mutations/diff_conflict.py,sha256=JngQfyKXCVlmtlqQ_VyabmrOEDOEKYsoWbyYSc9TT5c,3147
489
490
  infrahub/graphql/mutations/generator.py,sha256=Ulw4whZm8Gc8lJjwfUFoFSsR0cOUliFKl87Oca4B9O0,3579
490
491
  infrahub/graphql/mutations/graphql_query.py,sha256=a8tCTrjJipwIghmxlcUkH1Hx_7tem5QhzrTczcwpuZM,3644
491
- infrahub/graphql/mutations/ipam.py,sha256=wIN8OcTNCHVy32YgatWZi2Of-snFYBd4wlxOAJvE-AY,15961
492
+ infrahub/graphql/mutations/ipam.py,sha256=KnfIq6TD9Q649T8BI-pvUmtH5P7GX4UEsz0P22et0MI,16207
492
493
  infrahub/graphql/mutations/main.py,sha256=Zqq2zi24ZR8S8ikZ21F2_3kIqYc8tXtvDyit1Xz27vw,21938
493
494
  infrahub/graphql/mutations/menu.py,sha256=NSdtUobZ-5dsQdBFfD1xyoE9dKw9FS62T_6UQM0cEUY,3790
494
495
  infrahub/graphql/mutations/models.py,sha256=ilkSLr8OxVO9v3Ra_uDyUTJT9qPOmdPMqQbuWIydJMo,264
@@ -622,7 +623,7 @@ infrahub/proposed_change/branch_diff.py,sha256=IdMxf5zPmhybQKPPz7AlruNmLCKf5VISP
622
623
  infrahub/proposed_change/checker.py,sha256=ZhNEVJKsQbHH2UE1O35MfOVa8cK1QGEqGyn6MsOuqSQ,1558
623
624
  infrahub/proposed_change/constants.py,sha256=auifG94Oo2cJ4RwZx4P-XDPDpKYPtEVxh013KPfiEdU,2080
624
625
  infrahub/proposed_change/models.py,sha256=ivWJmEAihprKmwgaBGDJ4Koq4ETciE5GfDp86KHDnns,5892
625
- infrahub/proposed_change/tasks.py,sha256=8KCZ33DZFESfCVOlLzTiK5DY7SiPtWn4AU1lzN0_MyM,64075
626
+ infrahub/proposed_change/tasks.py,sha256=-jAIhul4RCqx5MRWM1ITHoa1S7CEmQC06vsBKXfvTLk,64037
626
627
  infrahub/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
627
628
  infrahub/pytest_plugin.py,sha256=u3t0WgLMo9XmuQYeb28mccQ3xbnyv2Fv173YWl1zBiM,6678
628
629
  infrahub/schema/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -693,13 +694,13 @@ infrahub/webhook/gather.py,sha256=XNaIGiHDiMjjtSjsVbswOze7cLaL0MKJmvSbZBS-WT0,69
693
694
  infrahub/webhook/models.py,sha256=6oiwCV4iayTWDKmSTpcFx83WA23paMXLsw4fFw15KHM,10477
694
695
  infrahub/webhook/tasks.py,sha256=2msOOqqFStQbNje7Eq0glAdlprs-ASHii3qQXFIEyzE,7255
695
696
  infrahub/webhook/triggers.py,sha256=v1dzFV4wX0GO2n5hft_qzp-oJOA2P_9Q2eTcSP-i0pk,1574
696
- infrahub/worker.py,sha256=JtTM-temURUbpEy-bkKJuTt-GKoiHFDrOe9SyVTIXEM,49
697
+ infrahub/worker.py,sha256=zV9vLXtJzyqeTGtVolwZEHlLaBvGiUZv00qWpE-lnOM,353
697
698
  infrahub/workers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
698
699
  infrahub/workers/dependencies.py,sha256=byuliu9WrOGtQ-Zws8NSTq3LJwnqxIqQ7dcWP3KNlAg,4850
699
700
  infrahub/workers/infrahub_async.py,sha256=9itLnky6BuqWR92fuU-SShaSI-33eoSRfhOEZy0TH0g,7973
700
701
  infrahub/workers/utils.py,sha256=m6FOKrYo53Aoj-JcEyQ7-J4Dc20R9JtHMDzTcqXiRpg,2407
701
702
  infrahub/workflows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
702
- infrahub/workflows/catalogue.py,sha256=n25f3MCHxpbpepQbTejL87kIbxXod_mYRJYqsYgKof0,18279
703
+ infrahub/workflows/catalogue.py,sha256=cHV51ZQXQhyoEgCahppv--vyDYbjo-Duu2LemeRho_k,18283
703
704
  infrahub/workflows/constants.py,sha256=7je2FF7tJH6x_ZNqHKZfQX91X7I5gmD8OECN3dE_eqI,651
704
705
  infrahub/workflows/initialization.py,sha256=Aj3tTD4tL9qhNgSnzFIMkTHab8FWWgL0JINaON9wjj0,3224
705
706
  infrahub/workflows/models.py,sha256=eCra3PFbX-GpiNLDG6WyqVXvSqRTz1eF4REm0doJFDY,3534
@@ -827,8 +828,8 @@ infrahub_testcontainers/models.py,sha256=ASYyvl7d_WQz_i7y8-3iab9hwwmCl3OCJavqVbe
827
828
  infrahub_testcontainers/performance_test.py,sha256=hvwiy6tc_lWniYqGkqfOXVGAmA_IV15VOZqbiD9ezno,6149
828
829
  infrahub_testcontainers/plugin.py,sha256=I3RuZQ0dARyKHuqCf0y1Yj731P2Mwf3BJUehRJKeWrs,5645
829
830
  infrahub_testcontainers/prometheus.yml,sha256=610xQEyj3xuVJMzPkC4m1fRnCrjGpiRBrXA2ytCLa54,599
830
- infrahub_server-1.4.7.dist-info/LICENSE.txt,sha256=7GQO7kxVoQYnZtFrjZBKLRXbrGwwwimHPPOJtqXsozQ,11340
831
- infrahub_server-1.4.7.dist-info/METADATA,sha256=JDolBgNRWQnhM2j2I-v1sINa1PVuDN3YUX58Zd6PB1A,8277
832
- infrahub_server-1.4.7.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
833
- infrahub_server-1.4.7.dist-info/entry_points.txt,sha256=UXIeFWDsrV-4IllNvUEd6KieYGzQfn9paga2YyABOQI,393
834
- infrahub_server-1.4.7.dist-info/RECORD,,
831
+ infrahub_server-1.4.9.dist-info/LICENSE.txt,sha256=7GQO7kxVoQYnZtFrjZBKLRXbrGwwwimHPPOJtqXsozQ,11340
832
+ infrahub_server-1.4.9.dist-info/METADATA,sha256=8IccC-o3SIdkcjcI9izHZN10hsoSgLlqhquqpG5y26g,8277
833
+ infrahub_server-1.4.9.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
834
+ infrahub_server-1.4.9.dist-info/entry_points.txt,sha256=UXIeFWDsrV-4IllNvUEd6KieYGzQfn9paga2YyABOQI,393
835
+ infrahub_server-1.4.9.dist-info/RECORD,,