infrahub-server 1.4.4__py3-none-any.whl → 1.4.6__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.
@@ -118,6 +118,12 @@ class ValueMatch(DropdownEnum):
118
118
  description="Match against both the current and previous values",
119
119
  color="#5ac8fa",
120
120
  )
121
+ ANY = DropdownChoice(
122
+ name="any",
123
+ label="Any",
124
+ description="Match against any value",
125
+ color="#276cc2",
126
+ )
121
127
 
122
128
 
123
129
  NODES_THAT_TRIGGER_ACTION_RULES_SETUP = [
infrahub/api/query.py CHANGED
@@ -40,7 +40,7 @@ router = APIRouter(prefix="/query")
40
40
 
41
41
 
42
42
  class QueryPayload(BaseModel):
43
- variables: dict[str, str] = Field(default_factory=dict)
43
+ variables: dict[str, Any] = Field(default_factory=dict)
44
44
 
45
45
 
46
46
  async def execute_query(
@@ -48,7 +48,7 @@ async def execute_query(
48
48
  request: Request,
49
49
  branch_params: BranchParams,
50
50
  query_id: str,
51
- params: dict[str, str],
51
+ params: dict[str, Any],
52
52
  update_group: bool,
53
53
  subscribers: list[str],
54
54
  permission_checker: GraphQLQueryPermissionChecker,
infrahub/core/account.py CHANGED
@@ -5,9 +5,10 @@ from typing import TYPE_CHECKING, Any
5
5
 
6
6
  from typing_extensions import Self
7
7
 
8
- from infrahub.core.constants import InfrahubKind, PermissionDecision
8
+ from infrahub.core.constants import NULL_VALUE, InfrahubKind, PermissionDecision
9
9
  from infrahub.core.query import Query, QueryType
10
10
  from infrahub.core.registry import registry
11
+ from infrahub.core.timestamp import Timestamp
11
12
 
12
13
  if TYPE_CHECKING:
13
14
  from infrahub.core.branch import Branch
@@ -519,47 +520,72 @@ class AccountTokenValidateQuery(Query):
519
520
  super().__init__(**kwargs)
520
521
 
521
522
  async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa: ARG002
522
- token_filter_perms, token_params = self.branch.get_query_filter_relationships(
523
- rel_labels=["r1", "r2"], at=self.at, include_outside_parentheses=True
523
+ branch_filter, branch_params = self.branch.get_query_filter_path(
524
+ at=self.at.to_string(), branch_agnostic=self.branch_agnostic, is_isolated=False
524
525
  )
525
- self.params.update(token_params)
526
-
527
- account_filter_perms, account_params = self.branch.get_query_filter_relationships(
528
- rel_labels=["r31", "r41", "r5", "r6"], at=self.at, include_outside_parentheses=True
526
+ self.params.update(branch_params)
527
+ self.params.update(
528
+ {
529
+ "token_attr_name": "token",
530
+ "token_relationship_name": "account__token",
531
+ "token_value": self.token,
532
+ "null_value": NULL_VALUE,
533
+ }
529
534
  )
530
- self.params.update(account_params)
531
535
 
532
- self.params["token_value"] = self.token
533
-
534
- # ruff: noqa: E501
535
536
  query = """
536
- MATCH (at:InternalAccountToken)-[r1:HAS_ATTRIBUTE]-(a:Attribute {name: "token"})-[r2:HAS_VALUE]-(av:AttributeValue { value: $token_value })
537
- WHERE %s
538
- WITH at
539
- MATCH (at)-[r31]-(:Relationship)-[r41]-(acc:CoreGenericAccount)-[r5:HAS_ATTRIBUTE]-(an:Attribute {name: "name"})-[r6:HAS_VALUE]-(av:AttributeValue)
540
- WHERE %s
541
- """ % (
542
- "\n AND ".join(token_filter_perms),
543
- "\n AND ".join(account_filter_perms),
544
- )
545
-
537
+ // --------------
538
+ // get the active token node for this token value, if it exists
539
+ // --------------
540
+ MATCH (token_node:%(token_node_kind)s)-[r1:HAS_ATTRIBUTE]->(:Attribute {name: $token_attr_name})
541
+ -[r2:HAS_VALUE]->(av:AttributeValueIndexed { value: $token_value })
542
+ WHERE all(r in [r1, r2] WHERE (%(branch_filter)s))
543
+ ORDER BY r1.branch_level DESC, r1.from DESC, r1.status ASC, r2.branch_level DESC, r2.from DESC, r2.status ASC
544
+ LIMIT 1
545
+ WITH token_node
546
+ WHERE r1.status = "active" AND r2.status = "active"
547
+ // --------------
548
+ // get the expiration time
549
+ // --------------
550
+ OPTIONAL MATCH (token_node)-[r1:HAS_ATTRIBUTE]->(:Attribute {name: "expiration"})
551
+ -[r2:HAS_VALUE]->(av)
552
+ WHERE all(r in [r1, r2] WHERE (%(branch_filter)s))
553
+ ORDER BY r1.branch_level DESC, r1.from DESC, r1.status ASC, r2.branch_level DESC, r2.from DESC, r2.status ASC
554
+ LIMIT 1
555
+ WITH token_node, CASE
556
+ WHEN r1.status = "active" AND r2.status = "active" AND av.value <> $null_value THEN av.value
557
+ ELSE NULL
558
+ END AS expiration
559
+ // --------------
560
+ // get the linked account node from the token node
561
+ // --------------
562
+ MATCH (token_node)-[r1:IS_RELATED]-(:Relationship {name: $token_relationship_name})-[r2:IS_RELATED]-(account_node:%(account_node_kind)s)
563
+ WHERE all(r in [r1, r2] WHERE (%(branch_filter)s))
564
+ ORDER BY r1.branch_level DESC, r1.from DESC, r1.status ASC, r2.branch_level DESC, r2.from DESC, r2.status ASC
565
+ LIMIT 1
566
+ WITH expiration, account_node
567
+ WHERE r1.status = "active" AND r2.status = "active"
568
+ """ % {
569
+ "branch_filter": branch_filter,
570
+ "token_node_kind": InfrahubKind.ACCOUNTTOKEN,
571
+ "account_node_kind": InfrahubKind.GENERICACCOUNT,
572
+ }
546
573
  self.add_to_query(query)
547
-
548
- self.return_labels = ["at", "av", "acc"]
549
-
550
- def get_account_name(self) -> str | None:
551
- """Return the account name that matched the query or None."""
552
- if result := self.get_result():
553
- return result.get("av").get("value")
554
-
555
- return None
574
+ self.return_labels = ["account_node.uuid AS account_uuid", "expiration"]
556
575
 
557
576
  def get_account_id(self) -> str | None:
558
577
  """Return the account id that matched the query or a None."""
559
- if result := self.get_result():
560
- return result.get("acc").get("uuid")
561
-
562
- return None
578
+ result = self.get_result()
579
+ if not result:
580
+ return None
581
+ account_uuid = result.get_as_str(label="account_uuid")
582
+ expiration_with_tz = result.get_as_str(label="expiration")
583
+ if expiration_with_tz is None:
584
+ return account_uuid
585
+ expiration = Timestamp(expiration_with_tz)
586
+ if expiration < Timestamp():
587
+ return None
588
+ return account_uuid
563
589
 
564
590
 
565
591
  async def validate_token(token: str, db: InfrahubDatabase, branch: Branch | str | None = None) -> str | None:
@@ -375,6 +375,10 @@ class IPPrefixReconcileQuery(Query):
375
375
  // ------------------
376
376
  MATCH (ip_namespace:%(namespace_kind)s {uuid: $namespace_id})-[r:IS_PART_OF]->(root:Root)
377
377
  WHERE %(branch_filter)s
378
+ ORDER BY r.branch_level DESC, r.from DESC, r.status ASC
379
+ LIMIT 1
380
+ WITH ip_namespace
381
+ WHERE r.status = "active"
378
382
  """ % {"branch_filter": branch_filter, "namespace_kind": self.params["namespace_kind"]}
379
383
  self.add_to_query(namespace_query)
380
384
 
@@ -384,8 +388,13 @@ class IPPrefixReconcileQuery(Query):
384
388
  // ------------------
385
389
  // Get IP Prefix node by UUID
386
390
  // ------------------
387
- MATCH (ip_node:%(ip_kind)s {uuid: $node_uuid})
391
+ OPTIONAL MATCH (ip_node:%(ip_kind)s {uuid: $node_uuid})-[r:IS_PART_OF]->(:Root)
392
+ WHERE %(branch_filter)s
393
+ ORDER BY r.branch_level DESC, r.from DESC, r.status ASC
394
+ LIMIT 1
395
+ WITH ip_namespace, ip_node
388
396
  """ % {
397
+ "branch_filter": branch_filter,
389
398
  "ip_kind": InfrahubKind.IPADDRESS
390
399
  if isinstance(self.ip_value, IPAddressType)
391
400
  else InfrahubKind.IPPREFIX,
@@ -395,17 +404,35 @@ class IPPrefixReconcileQuery(Query):
395
404
  else:
396
405
  get_node_by_prefix_query = """
397
406
  // ------------------
398
- // Get IP Prefix node by prefix value
407
+ // Get IP node with the correct value on this branch
399
408
  // ------------------
400
- OPTIONAL MATCH ip_node_path = (:Root)<-[:IS_PART_OF]-(ip_node:%(ip_kind)s)
401
- -[:HAS_ATTRIBUTE]->(a:Attribute)-[:HAS_VALUE]->(aipn:%(ip_attribute_kind)s),
402
- (ip_namespace)-[:IS_RELATED]-(nsr:Relationship)
403
- -[:IS_RELATED]-(ip_node)
404
- WHERE nsr.name IN ["ip_namespace__ip_prefix", "ip_namespace__ip_address"]
405
- AND aipn.binary_address = $prefix_binary_full
409
+ OPTIONAL MATCH (:Root)<-[r1:IS_PART_OF]-(ip_node:%(ip_kind)s)
410
+ -[r2:HAS_ATTRIBUTE]->(a:Attribute)-[r3:HAS_VALUE]->(aipn:%(ip_attribute_kind)s)
411
+ WHERE aipn.binary_address = $prefix_binary_full
406
412
  AND aipn.prefixlen = $prefixlen
407
413
  AND aipn.version = $ip_version
408
- AND all(r IN relationships(ip_node_path) WHERE (%(branch_filter)s) and r.status = "active")
414
+ AND all(r IN [r1, r2, r3] WHERE (%(branch_filter)s))
415
+ ORDER BY r3.branch_level DESC, r3.from DESC, r3.status ASC,
416
+ r2.branch_level DESC, r2.from DESC, r2.status ASC,
417
+ r1.branch_level DESC, r1.from DESC, r1.status ASC
418
+ LIMIT 1
419
+ WITH ip_namespace, CASE
420
+ WHEN ip_node IS NOT NULL AND r1.status = "active" AND r2.status = "active" AND r3.status = "active" THEN ip_node
421
+ ELSE NULL
422
+ END AS ip_node
423
+ // ------------------
424
+ // Filter to only those that are in the correct namespace
425
+ // ------------------
426
+ OPTIONAL MATCH (ip_namespace)-[r1:IS_RELATED]-(nsr:Relationship)-[r2:IS_RELATED]-(ip_node)
427
+ WHERE nsr.name IN ["ip_namespace__ip_prefix", "ip_namespace__ip_address"]
428
+ AND all(r IN [r1, r2] WHERE (%(branch_filter)s))
429
+ ORDER BY r1.branch_level DESC, r1.from DESC, r1.status ASC,
430
+ r2.branch_level DESC, r2.from DESC, r2.status ASC
431
+ LIMIT 1
432
+ WITH ip_namespace, CASE
433
+ WHEN ip_node IS NOT NULL AND r1.status = "active" AND r2.status = "active" THEN ip_node
434
+ ELSE NULL
435
+ END as ip_node
409
436
  """ % {
410
437
  "branch_filter": branch_filter,
411
438
  "ip_kind": InfrahubKind.IPADDRESS
@@ -425,7 +452,7 @@ class IPPrefixReconcileQuery(Query):
425
452
  OPTIONAL MATCH parent_prefix_path = (ip_node)-[r1:IS_RELATED]->(:Relationship {name: "parent__child"})-[r2:IS_RELATED]->(current_parent:%(ip_prefix_kind)s)
426
453
  WHERE all(r IN relationships(parent_prefix_path) WHERE (%(branch_filter)s))
427
454
  RETURN current_parent, (r1.status = "active" AND r2.status = "active") AS parent_is_active
428
- ORDER BY r1.branch_level DESC, r2.branch_level DESC, r1.from DESC, r2.from DESC
455
+ ORDER BY r1.branch_level DESC, r1.from DESC, r1.status ASC, r2.branch_level DESC, r2.from DESC, r2.status ASC
429
456
  LIMIT 1
430
457
  }
431
458
  WITH ip_namespace, ip_node, CASE WHEN parent_is_active THEN current_parent ELSE NULL END as current_parent
@@ -474,28 +501,66 @@ class IPPrefixReconcileQuery(Query):
474
501
  // Identify the correct parent, if any, for the prefix node
475
502
  // ------------------
476
503
  CALL (ip_namespace) {
477
- OPTIONAL MATCH parent_path = (ip_namespace)-[pr1:IS_RELATED {status: "active"}]-(ns_rel:Relationship {name: "ip_namespace__ip_prefix"})
478
- -[pr2:IS_RELATED {status: "active"}]-(maybe_new_parent:%(ip_prefix_kind)s)
479
- -[har:HAS_ATTRIBUTE]->(:Attribute {name: "prefix"})
480
- -[hvr:HAS_VALUE]->(av:%(ip_prefix_attribute_kind)s)
481
- USING INDEX av:%(ip_prefix_attribute_kind)s(binary_address)
482
- WHERE all(r IN relationships(parent_path) WHERE (%(branch_filter)s))
483
- AND av.version = $ip_version
504
+ // ------------------
505
+ // start with just the AttributeValue vertices b/c we have an index on them
506
+ // ------------------
507
+ OPTIONAL MATCH (av:%(ip_prefix_attribute_kind)s)
508
+ WHERE av.version = $ip_version
484
509
  AND av.binary_address IN $possible_prefix_list
485
510
  AND any(prefix_and_length IN $possible_prefix_and_length_list WHERE av.binary_address = prefix_and_length[0] AND av.prefixlen <= prefix_and_length[1])
511
+ // ------------------
512
+ // now get all the possible IPPrefix nodes for these AttributeValues
513
+ // ------------------
514
+ OPTIONAL MATCH parent_path = (ip_namespace)-[:IS_RELATED]-(:Relationship {name: "ip_namespace__ip_prefix"})
515
+ -[:IS_RELATED]-(maybe_new_parent:%(ip_prefix_kind)s)
516
+ -[:HAS_ATTRIBUTE]->(:Attribute {name: "prefix"})
517
+ -[:HAS_VALUE]->(av:AttributeValue)
518
+ WHERE all(r IN relationships(parent_path) WHERE (%(branch_filter)s))
519
+ RETURN DISTINCT maybe_new_parent
520
+ }
521
+ CALL (ip_namespace, maybe_new_parent) {
522
+ // ------------------
523
+ // filter to only active maybe_new_parent Nodes in the correct namespace
524
+ // ------------------
525
+ OPTIONAL MATCH (ip_namespace)-[r1:IS_RELATED]-(:Relationship {name: "ip_namespace__ip_prefix"})-[r2:IS_RELATED]-(maybe_new_parent)
526
+ WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s))
527
+ WITH maybe_new_parent, r1, r2, r1.status = "active" AND r2.status = "active" AS is_active
528
+ ORDER BY elementId(maybe_new_parent), r1.branch_level DESC, r1.from DESC, r1.status ASC, r2.branch_level DESC, r2.from DESC, r2.status ASC
529
+ WITH maybe_new_parent, head(collect(is_active)) AS is_active
530
+ RETURN is_active = TRUE AS parent_in_namespace
531
+ }
532
+ CALL (maybe_new_parent) {
533
+ // ------------------
534
+ // filter to only active maybe_new_parent Nodes currently linked to one of the allowed AttributeValues
535
+ // ------------------
536
+ OPTIONAL MATCH (maybe_new_parent)-[r1:HAS_ATTRIBUTE]->(:Attribute {name: "prefix"})-[r2:HAS_VALUE]->(av:AttributeValue)
537
+ WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s))
538
+ WITH maybe_new_parent, av, r1, r2, r1.status = "active" AND r2.status = "active" AS is_active
539
+ ORDER BY elementId(maybe_new_parent), r1.branch_level DESC, r1.from DESC, r1.status ASC, r2.branch_level DESC, r2.from DESC, r2.status ASC
540
+ // ------------------
541
+ // get the latest active attribute value for the maybe_new_parent
542
+ // ------------------
543
+ WITH maybe_new_parent, head(collect([av, is_active])) AS av_is_active
486
544
  WITH
487
- maybe_new_parent,
488
- har,
489
- hvr,
490
- av.prefixlen as prefixlen,
491
- (har.status = "active" AND hvr.status = "active") AS is_active,
492
- har.branch_level + hvr.branch_level AS branch_level
493
- ORDER BY branch_level DESC, har.from DESC, hvr.from DESC
494
- WITH maybe_new_parent, prefixlen, is_active
495
- RETURN maybe_new_parent, head(collect(prefixlen)) AS mnp_prefixlen, head(collect(is_active)) AS mnp_is_active
545
+ av_is_active[0] AS av,
546
+ av_is_active[1] AS is_active
547
+ // ------------------
548
+ // return NULL if the value is not allowed or if it is not active
549
+ // ------------------
550
+ WITH av, is_active, (
551
+ av.version = $ip_version
552
+ AND av.binary_address IN $possible_prefix_list
553
+ AND any(prefix_and_length IN $possible_prefix_and_length_list WHERE av.binary_address = prefix_and_length[0] AND av.prefixlen <= prefix_and_length[1])
554
+ ) AS is_allowed_value
555
+ RETURN CASE WHEN is_active = TRUE AND is_allowed_value = TRUE THEN av ELSE NULL END AS allowed_av
496
556
  }
497
- WITH ip_namespace, ip_node, current_parent, current_children, mnp_prefixlen,
498
- CASE WHEN mnp_is_active THEN maybe_new_parent ELSE NULL END AS maybe_new_parent
557
+ // ------------------
558
+ // set inactive maybe_new_parents to NULL
559
+ // ------------------
560
+ WITH ip_namespace, ip_node, current_parent, current_children, allowed_av.prefixlen AS mnp_prefixlen,
561
+ CASE WHEN parent_in_namespace = TRUE AND allowed_av IS NOT NULL
562
+ THEN maybe_new_parent ELSE NULL
563
+ END AS maybe_new_parent
499
564
  WITH ip_namespace, ip_node, current_parent, current_children, maybe_new_parent, mnp_prefixlen
500
565
  ORDER BY ip_node.uuid, mnp_prefixlen DESC
501
566
  WITH ip_namespace, ip_node, current_parent, current_children, head(collect(maybe_new_parent)) as new_parent
@@ -511,19 +576,18 @@ class IPPrefixReconcileQuery(Query):
511
576
  // Identify the correct children, if any, for the prefix node
512
577
  // ------------------
513
578
  CALL (ip_namespace, ip_node) {
579
+ // ------------------
514
580
  // Get ALL possible children for the prefix node
515
- OPTIONAL MATCH child_path = (
516
- (ip_namespace)-[r1:IS_RELATED]
517
- -(ns_rel:Relationship)-[r2:IS_RELATED]
518
- -(maybe_new_child:%(ip_prefix_kind)s|%(ip_address_kind)s)-[har:HAS_ATTRIBUTE]
519
- ->(a:Attribute)-[hvr:HAS_VALUE]
520
- ->(av:%(ip_prefix_attribute_kind)s|%(ip_address_attribute_kind)s)
581
+ // ------------------
582
+ OPTIONAL MATCH (
583
+ (ip_namespace)-[:IS_RELATED]-(ns_rel:Relationship)-[:IS_RELATED]
584
+ -(maybe_new_child:%(ip_prefix_kind)s|%(ip_address_kind)s)-[:HAS_ATTRIBUTE]
585
+ ->(a:Attribute)-[:HAS_VALUE]->(av:%(ip_prefix_attribute_kind)s|%(ip_address_attribute_kind)s)
521
586
  )
522
587
  USING INDEX av:%(ip_prefix_attribute_kind)s(binary_address)
523
588
  USING INDEX av:%(ip_address_attribute_kind)s(binary_address)
524
589
  WHERE $is_prefix // only prefix nodes can have children
525
590
  AND ns_rel.name IN ["ip_namespace__ip_prefix", "ip_namespace__ip_address"]
526
- AND any(child_kind IN [$ip_prefix_kind, $ip_address_kind] WHERE child_kind IN labels(maybe_new_child))
527
591
  AND a.name in ["prefix", "address"]
528
592
  AND (ip_node IS NULL OR maybe_new_child.uuid <> ip_node.uuid)
529
593
  AND (
@@ -532,22 +596,58 @@ class IPPrefixReconcileQuery(Query):
532
596
  )
533
597
  AND av.version = $ip_version
534
598
  AND av.binary_address STARTS WITH $prefix_binary_host
535
- AND all(r IN relationships(child_path) WHERE (%(branch_filter)s))
599
+ RETURN DISTINCT maybe_new_child
600
+ }
601
+ CALL (ip_namespace, maybe_new_child) {
602
+ // ------------------
603
+ // filter to only active maybe_new_child Nodes in the correct namespace
604
+ // ------------------
605
+ OPTIONAL MATCH (ip_namespace)-[r1:IS_RELATED]-(ns_rel:Relationship)-[r2:IS_RELATED]-(maybe_new_child)
606
+ WHERE ns_rel.name IN ["ip_namespace__ip_prefix", "ip_namespace__ip_address"]
607
+ AND all(r IN [r1, r2] WHERE (%(branch_filter)s))
608
+ WITH maybe_new_child, r1, r2, r1.status = "active" AND r2.status = "active" AS is_active
609
+ ORDER BY elementId(maybe_new_child), r1.branch_level DESC, r1.from DESC, r1.status ASC, r2.branch_level DESC, r2.from DESC, r2.status ASC
610
+ WITH maybe_new_child, head(collect(is_active)) AS is_active
611
+ RETURN is_active = TRUE AS child_in_namespace
612
+ }
613
+ CALL (maybe_new_child) {
614
+ // ------------------
615
+ // filter to only active maybe_new_child Nodes currently linked to a possible child AttributeValue
616
+ // ------------------
617
+ OPTIONAL MATCH (maybe_new_child:%(ip_prefix_kind)s|%(ip_address_kind)s)-[r1:HAS_ATTRIBUTE]->(a:Attribute)-[r2:HAS_VALUE]->(av:AttributeValue)
618
+ WHERE a.name in ["prefix", "address"]
619
+ AND all(r IN [r1, r2] WHERE (%(branch_filter)s))
620
+ WITH maybe_new_child, av, r1, r2, r1.status = "active" AND r2.status = "active" AS is_active
621
+ ORDER BY elementId(maybe_new_child), r1.branch_level DESC, r1.from DESC, r1.status ASC, r2.branch_level DESC, r2.from DESC, r2.status ASC
622
+ // ------------------
623
+ // get the latest active attribute value for the maybe_new_child
624
+ // ------------------
625
+ WITH maybe_new_child, head(collect([av, is_active])) AS av_is_active
536
626
  WITH
537
- maybe_new_child,
538
- av AS mnc_attribute,
539
- r1,
540
- r2,
541
- har,
542
- hvr,
543
- all(r in relationships(child_path) WHERE r.status = "active") AS is_active,
544
- reduce(br_lvl = 0, r in relationships(child_path) | br_lvl + r.branch_level) AS branch_level
545
- ORDER BY maybe_new_child.uuid, branch_level DESC, hvr.from DESC, har.from DESC, r2.from DESC, r1.from DESC
546
- WITH maybe_new_child, head(collect([mnc_attribute, is_active])) AS latest_mnc_details
547
- RETURN maybe_new_child, latest_mnc_details[0] AS latest_mnc_attribute, latest_mnc_details[1] AS mnc_is_active
627
+ av_is_active[0] AS av,
628
+ av_is_active[1] AS is_active
629
+ // ------------------
630
+ // return NULL if the value is not allowed or if it is not active
631
+ // ------------------
632
+ WITH av, is_active, (
633
+ (
634
+ ($ip_prefix_kind IN labels(maybe_new_child) AND av.prefixlen > $prefixlen)
635
+ OR ($ip_address_kind IN labels(maybe_new_child) AND av.prefixlen >= $prefixlen)
636
+ )
637
+ AND av.version = $ip_version
638
+ AND av.binary_address STARTS WITH $prefix_binary_host
639
+ ) AS is_allowed_value
640
+ RETURN CASE WHEN is_active = TRUE AND is_allowed_value = TRUE THEN av ELSE NULL END AS latest_mnc_attribute
548
641
  }
549
- WITH ip_namespace, ip_node, current_parent, current_children, new_parent, latest_mnc_attribute,
550
- CASE WHEN mnc_is_active IN [TRUE, NULL] THEN maybe_new_child ELSE NULL END AS maybe_new_child
642
+ // ------------------
643
+ // set inactive/illegal value/wrong namespace maybe_new_children to NULL
644
+ // ------------------
645
+ WITH ip_namespace, ip_node, current_parent, current_children, new_parent,
646
+ CASE
647
+ WHEN child_in_namespace = TRUE AND latest_mnc_attribute IS NOT NULL THEN maybe_new_child
648
+ ELSE NULL
649
+ END AS maybe_new_child,
650
+ CASE WHEN child_in_namespace = TRUE THEN latest_mnc_attribute ELSE NULL END AS latest_mnc_attribute
551
651
  WITH ip_namespace, ip_node, current_parent, current_children, new_parent, collect([maybe_new_child, latest_mnc_attribute]) AS maybe_children_ips
552
652
  WITH ip_namespace, ip_node, current_parent, current_children, new_parent, maybe_children_ips, range(0, size(maybe_children_ips) - 1) AS child_indices
553
653
  UNWIND child_indices as ind
@@ -581,9 +681,9 @@ class IPPrefixReconcileQuery(Query):
581
681
  new_parent,
582
682
  collect(new_child) as new_children
583
683
  """ % {
584
- "branch_filter": branch_filter,
585
684
  "ip_prefix_kind": InfrahubKind.IPPREFIX,
586
685
  "ip_address_kind": InfrahubKind.IPADDRESS,
686
+ "branch_filter": branch_filter,
587
687
  "ip_prefix_attribute_kind": PREFIX_ATTRIBUTE_LABEL,
588
688
  "ip_address_attribute_kind": ADDRESS_ATTRIBUTE_LABEL,
589
689
  }
@@ -168,6 +168,15 @@ async def request_generator_definition_run(
168
168
 
169
169
  client = get_client()
170
170
 
171
+ # Needs to be fetched before fetching group members otherwise `object` relationship would override
172
+ # existing node in client store without the `name` attribute due to #521
173
+ existing_instances = await client.filters(
174
+ kind=InfrahubKind.GENERATORINSTANCE,
175
+ definition__ids=[model.generator_definition.definition_id],
176
+ include=["object"],
177
+ branch=model.branch,
178
+ )
179
+
171
180
  group = await client.get(
172
181
  kind=InfrahubKind.GENERICGROUP,
173
182
  prefetch_relationships=True,
@@ -177,12 +186,6 @@ async def request_generator_definition_run(
177
186
  )
178
187
  await group.members.fetch()
179
188
 
180
- existing_instances = await client.filters(
181
- kind=InfrahubKind.GENERATORINSTANCE,
182
- definition__ids=[model.generator_definition.definition_id],
183
- include=["object"],
184
- branch=model.branch,
185
- )
186
189
  instance_by_member = {}
187
190
  for instance in existing_instances:
188
191
  instance_by_member[instance.object.peer.id] = instance.id
infrahub/git/tasks.py CHANGED
@@ -310,6 +310,15 @@ async def generate_request_artifact_definition(
310
310
 
311
311
  client = get_client()
312
312
 
313
+ # Needs to be fetched before fetching group members otherwise `object` relationship would override
314
+ # existing node in client store without the `name` attribute due to #521
315
+ existing_artifacts = await client.filters(
316
+ kind=CoreArtifact,
317
+ definition__ids=[model.artifact_definition_id],
318
+ include=["object"],
319
+ branch=model.branch,
320
+ )
321
+
313
322
  artifact_definition = await client.get(
314
323
  kind=CoreArtifactDefinition, id=model.artifact_definition_id, branch=model.branch
315
324
  )
@@ -319,12 +328,6 @@ async def generate_request_artifact_definition(
319
328
  await group.members.fetch()
320
329
  current_members = [member.id for member in group.members.peers]
321
330
 
322
- existing_artifacts = await client.filters(
323
- kind=CoreArtifact,
324
- definition__ids=[model.artifact_definition_id],
325
- include=["object"],
326
- branch=model.branch,
327
- )
328
331
  artifacts_by_member = {}
329
332
  for artifact in existing_artifacts:
330
333
  if artifact.object.id in current_members:
@@ -646,16 +646,19 @@ async def validate_artifacts_generation(model: RequestArtifactDefinitionCheck, c
646
646
  context=context,
647
647
  )
648
648
 
649
- await artifact_definition.targets.fetch()
650
- group = artifact_definition.targets.peer
651
- await group.members.fetch()
652
-
649
+ # Needs to be fetched before fetching group members otherwise `object` relationship would override
650
+ # existing node in client store without the `name` attribute due to #521
653
651
  existing_artifacts = await client.filters(
654
652
  kind=InfrahubKind.ARTIFACT,
655
653
  definition__ids=[model.artifact_definition.definition_id],
656
654
  include=["object"],
657
655
  branch=model.source_branch,
658
656
  )
657
+
658
+ await artifact_definition.targets.fetch()
659
+ group = artifact_definition.targets.peer
660
+ await group.members.fetch()
661
+
659
662
  artifacts_by_member = {}
660
663
  for artifact in existing_artifacts:
661
664
  artifacts_by_member[artifact.object.peer.id] = artifact.id
@@ -907,6 +910,15 @@ async def request_generator_definition_check(model: RequestGeneratorDefinitionCh
907
910
  context=context,
908
911
  )
909
912
 
913
+ # Needs to be fetched before fetching group members otherwise `object` relationship would override
914
+ # existing node in client store without the `name` attribute due to #521
915
+ existing_instances = await client.filters(
916
+ kind=InfrahubKind.GENERATORINSTANCE,
917
+ definition__ids=[model.generator_definition.definition_id],
918
+ include=["object"],
919
+ branch=model.source_branch,
920
+ )
921
+
910
922
  group = await client.get(
911
923
  kind=InfrahubKind.GENERICGROUP,
912
924
  prefetch_relationships=True,
@@ -916,12 +928,6 @@ async def request_generator_definition_check(model: RequestGeneratorDefinitionCh
916
928
  )
917
929
  await group.members.fetch()
918
930
 
919
- existing_instances = await client.filters(
920
- kind=InfrahubKind.GENERATORINSTANCE,
921
- definition__ids=[model.generator_definition.definition_id],
922
- include=["object"],
923
- branch=model.source_branch,
924
- )
925
931
  instance_by_member = {}
926
932
  for instance in existing_instances:
927
933
  instance_by_member[instance.object.peer.id] = instance.id
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: infrahub-server
3
- Version: 1.4.4
3
+ Version: 1.4.6
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
@@ -1,6 +1,6 @@
1
1
  infrahub/__init__.py,sha256=OF6hovR3975Zu6-9DOL_Nh_FTgGn8kS_yOfQ-xp-chg,87
2
2
  infrahub/actions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- infrahub/actions/constants.py,sha256=lNj6Jhe9Sz1LD7mxTpcFu0K9wE0RbYNYzEL5HErMfCI,3645
3
+ infrahub/actions/constants.py,sha256=xrVNdwBwCzG20eXfowV3bia3LW8Kwx-DazS6vALPbEg,3790
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
@@ -21,7 +21,7 @@ infrahub/api/internal.py,sha256=ZlE5BkdGcrmLq1RZOCvv8OBBL7iT7wHKGG9Kqc-TTKg,5339
21
21
  infrahub/api/menu.py,sha256=xp5bj5JXQZA6ZEPWoTSGGSfTXZ1sVmehMxr3VSG7FlQ,1216
22
22
  infrahub/api/oauth2.py,sha256=wFsWrwfyoNBC1JYzbt1nzU-OjjxWPARIBbE_14jzFmI,5493
23
23
  infrahub/api/oidc.py,sha256=3fU-fNOoMkqEzoLuTmlhCVaZvL6M3sAub8RP1_LvCO8,8299
24
- infrahub/api/query.py,sha256=6I95AxNS9O8aIopfObk9hYxlZHawRqESOKjjEDax6-g,7312
24
+ infrahub/api/query.py,sha256=xc5aAY0TLHnswdjiIpvThG974EKGVIXvZCbtdiiZkPw,7312
25
25
  infrahub/api/schema.py,sha256=dUSB51YXaWELZuXYI7UNemd60MJPPBv4m6-MexXOE0k,17450
26
26
  infrahub/api/static/redoc.standalone.js,sha256=77kGx7mVN9EcdER2ZM4gQ-E-ra_N6AZq9QseAeD6kt0,1042008
27
27
  infrahub/api/static/swagger-ui-bundle.js,sha256=wuSp7wgUSDn_R8FCAgY-z-TlnnCk5xVKJr1Q2IDIi6E,1452753
@@ -61,7 +61,7 @@ infrahub/constants/database.py,sha256=WmV1iuOk4xulxZHOVvO3sS_VF1eTf7fKh0TPe_RnfV
61
61
  infrahub/constants/environment.py,sha256=ry-6qsBzSumOjjiq1D3XNoquf1LWqFKiQSJj8t6nET4,32
62
62
  infrahub/context.py,sha256=8SZRKSECkkcsNNzDaKEUJ7Nyr0EzUfToAy969LXjQVk,1554
63
63
  infrahub/core/__init__.py,sha256=z6EJBZyCYCBqinoBtX9li6BTBbbGV8WCkE_4CrEsmDA,104
64
- infrahub/core/account.py,sha256=s8ZC7J8rtEvQZQjbVuiKMlPhl6aQjtAjbZhBejLC0X8,26182
64
+ infrahub/core/account.py,sha256=6f1cIDWvL-HsbzL0UwWoCbDTzx55wzd_SkpQXiKDjcE,27477
65
65
  infrahub/core/attribute.py,sha256=f1-XLuRzbpG7T8y6pqQQqxQkbGDWhS5AZA2_r_mzY-A,44537
66
66
  infrahub/core/branch/__init__.py,sha256=h0oIj0gHp1xI-N1cYW8_N6VZ81CBOmLuiUt5cS5nKuk,49
67
67
  infrahub/core/branch/enums.py,sha256=vGnaTCzikvMcLikKN25TJ8uCmhnD448dp1ve1_tLjwQ,186
@@ -241,7 +241,7 @@ infrahub/core/query/attribute.py,sha256=xojZIHX-XfXlN_jgM1TQ1Bp4dXr4oLEWlr2A7igT
241
241
  infrahub/core/query/branch.py,sha256=7gj83jDWPWjFUZud7lMQ0xwl9ag3FL-ZOlmY5Kuq7UU,4307
242
242
  infrahub/core/query/delete.py,sha256=7tPP1qtNV6QGYtmgE1RKsuQ9oxENnMTVkttLvJ2PiKg,1927
243
243
  infrahub/core/query/diff.py,sha256=jJCkZRo5jGaf-yPAnQ_5ju6sCnknDK0E7vGpqEnaU_k,36881
244
- infrahub/core/query/ipam.py,sha256=dvP5K34Oj5cA1B42YhJml0fwSsnt-rt_ZWgcun8bFNU,28728
244
+ infrahub/core/query/ipam.py,sha256=dOs_LZr-DONrCPw6t5Ug9mBPn8a-S2NKja3Vr-zIeaM,34523
245
245
  infrahub/core/query/node.py,sha256=OfWS9PfltP89aU4n0KhEjrvAkhAGj9Vl4hcfKcE9LD8,70969
246
246
  infrahub/core/query/relationship.py,sha256=KmS9zrcr-RViXxiITXOjq1t0s-AfsICHk3wyyirZBfA,47817
247
247
  infrahub/core/query/resource_manager.py,sha256=uSvs1WZmdbyt_PjaUi9lXnYdPt-lhJV1RjYoUHYjQdk,16620
@@ -434,7 +434,7 @@ infrahub/events/validator_action.py,sha256=nQJH-RWcgr3-tzmIldvPmu5O7dUAmv1qQnuxx
434
434
  infrahub/exceptions.py,sha256=cbM-f_2U-5ZFVZ_MaaXgs64k4M7uJ7fqDU2iCRoWlYY,11861
435
435
  infrahub/generators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
436
436
  infrahub/generators/models.py,sha256=9qhSfsoG-uYux35HClAxSq7TRfkosqN3i_eQkeTokLs,1916
437
- infrahub/generators/tasks.py,sha256=br1-1quQvcnTUtSIArVqG8ZjD09K7i65s11B8lOer1A,9382
437
+ infrahub/generators/tasks.py,sha256=Ci6lIbnUS6faGzbUjw1ggROpv17guZ-Z9HH9f6cAZv4,9563
438
438
  infrahub/git/__init__.py,sha256=KeQ9U8UI5jDj6KB6j00Oal7MZmtOD9vKqVgiezG_EQA,281
439
439
  infrahub/git/base.py,sha256=RNXow4RzTBJyjTmT1vZO9_DZSx4Dyv12M-bK_xTBTbg,38657
440
440
  infrahub/git/constants.py,sha256=XpzcAkXbsgXZgrXey74id1sXV8Q6EHb_4FNw7BndxyY,106
@@ -442,7 +442,7 @@ infrahub/git/directory.py,sha256=fozxLXXJPweHG95yQwQkR5yy3sfTdmHiczCAJnsUX54,861
442
442
  infrahub/git/integrator.py,sha256=C9h1qo8EVE8FjwzGWHhTD50I8TuCTH9asgC8-z5eK-g,62818
443
443
  infrahub/git/models.py,sha256=ozk9alxQ8Ops1lw1g8iR3O7INuw1VPsEUr5Wceh9HQY,12152
444
444
  infrahub/git/repository.py,sha256=wPsJAA9aHTHdfw0gqCfkNHvcivs7JabsDf-uazptZt0,10928
445
- infrahub/git/tasks.py,sha256=W9CcF7pw5WXEEIFY4sMaSTWETe7eZcLtIKHlwz6FFYI,37334
445
+ infrahub/git/tasks.py,sha256=aBFN7yV72UshcxFljrmHAKGSDoe0e1eVjrnyPDXQEM8,37515
446
446
  infrahub/git/utils.py,sha256=xhWxlu_FbMqbrwanpPkex4hKRS_d2AFzlxI_6kVQllw,1741
447
447
  infrahub/git/worktree.py,sha256=8IYJWOBytKUWwhMmMVehR4ceeO9e13nV-mvn3iVEgZY,1727
448
448
  infrahub/git_credential/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -622,7 +622,7 @@ infrahub/proposed_change/branch_diff.py,sha256=IdMxf5zPmhybQKPPz7AlruNmLCKf5VISP
622
622
  infrahub/proposed_change/checker.py,sha256=ZhNEVJKsQbHH2UE1O35MfOVa8cK1QGEqGyn6MsOuqSQ,1558
623
623
  infrahub/proposed_change/constants.py,sha256=auifG94Oo2cJ4RwZx4P-XDPDpKYPtEVxh013KPfiEdU,2080
624
624
  infrahub/proposed_change/models.py,sha256=ivWJmEAihprKmwgaBGDJ4Koq4ETciE5GfDp86KHDnns,5892
625
- infrahub/proposed_change/tasks.py,sha256=-9-V7Waya7ClZsSQeWQdh-vVksE6Ozn0vEF7eAmPLE8,63629
625
+ infrahub/proposed_change/tasks.py,sha256=M1vdCE1J_IBxGwSnQLWwobxhOSDaaxuvEScgZuYbus8,63991
626
626
  infrahub/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
627
627
  infrahub/pytest_plugin.py,sha256=u3t0WgLMo9XmuQYeb28mccQ3xbnyv2Fv173YWl1zBiM,6678
628
628
  infrahub/schema/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -827,8 +827,8 @@ infrahub_testcontainers/models.py,sha256=ASYyvl7d_WQz_i7y8-3iab9hwwmCl3OCJavqVbe
827
827
  infrahub_testcontainers/performance_test.py,sha256=hvwiy6tc_lWniYqGkqfOXVGAmA_IV15VOZqbiD9ezno,6149
828
828
  infrahub_testcontainers/plugin.py,sha256=I3RuZQ0dARyKHuqCf0y1Yj731P2Mwf3BJUehRJKeWrs,5645
829
829
  infrahub_testcontainers/prometheus.yml,sha256=610xQEyj3xuVJMzPkC4m1fRnCrjGpiRBrXA2ytCLa54,599
830
- infrahub_server-1.4.4.dist-info/LICENSE.txt,sha256=7GQO7kxVoQYnZtFrjZBKLRXbrGwwwimHPPOJtqXsozQ,11340
831
- infrahub_server-1.4.4.dist-info/METADATA,sha256=FO70Jv93bMA5iuHIz3mW36epeZJC6wHgKttC65vvzMU,8277
832
- infrahub_server-1.4.4.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
833
- infrahub_server-1.4.4.dist-info/entry_points.txt,sha256=UXIeFWDsrV-4IllNvUEd6KieYGzQfn9paga2YyABOQI,393
834
- infrahub_server-1.4.4.dist-info/RECORD,,
830
+ infrahub_server-1.4.6.dist-info/LICENSE.txt,sha256=7GQO7kxVoQYnZtFrjZBKLRXbrGwwwimHPPOJtqXsozQ,11340
831
+ infrahub_server-1.4.6.dist-info/METADATA,sha256=O5wCV3t2TuX9o4kj49ujsXIigL20YFpkMBU6-PWY7kE,8277
832
+ infrahub_server-1.4.6.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
833
+ infrahub_server-1.4.6.dist-info/entry_points.txt,sha256=UXIeFWDsrV-4IllNvUEd6KieYGzQfn9paga2YyABOQI,393
834
+ infrahub_server-1.4.6.dist-info/RECORD,,