Skip to content

Commit 313fb32

Browse files
authored
Merge pull request #7598 from opsmill/stable
Merge stable into release-1.5
2 parents 87f6d8e + 08e2b0f commit 313fb32

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+929
-74
lines changed

.vale/styles/spelling-exceptions.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ pseudocode
177177
psutil
178178
PyPI
179179
query_peers
180+
quiescing
180181
rebase
181182
rebased
182183
rebasing
@@ -197,6 +198,7 @@ sdk
197198
SLA
198199
SLAs
199200
Slurp'it
201+
snapshotting
200202
streamlit
201203
Streamlit
202204
subcommand

CHANGELOG.md

Lines changed: 378 additions & 0 deletions
Large diffs are not rendered by default.

backend/infrahub/core/query/ipam.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -450,12 +450,23 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG
450450
// ------------------
451451
CALL (ip_node) {
452452
OPTIONAL MATCH parent_prefix_path = (ip_node)-[r1:IS_RELATED]->(:Relationship {name: "parent__child"})-[r2:IS_RELATED]->(current_parent:%(ip_prefix_kind)s)
453-
WHERE all(r IN relationships(parent_prefix_path) WHERE (%(branch_filter)s))
453+
WHERE $is_prefix = TRUE
454+
AND all(r IN relationships(parent_prefix_path) WHERE (%(branch_filter)s))
454455
RETURN current_parent, (r1.status = "active" AND r2.status = "active") AS parent_is_active
455456
ORDER BY r1.branch_level DESC, r1.from DESC, r1.status ASC, r2.branch_level DESC, r2.from DESC, r2.status ASC
456457
LIMIT 1
457458
}
458-
WITH ip_namespace, ip_node, CASE WHEN parent_is_active THEN current_parent ELSE NULL END as current_parent
459+
WITH ip_namespace, ip_node, CASE WHEN parent_is_active THEN current_parent ELSE NULL END as prefix_parent
460+
CALL (ip_node) {
461+
OPTIONAL MATCH parent_prefix_path = (ip_node)-[r1:IS_RELATED]->(:Relationship {name: "ip_prefix__ip_address"})<-[r2:IS_RELATED]-(current_parent:%(ip_prefix_kind)s)
462+
WHERE $is_prefix = FALSE
463+
AND all(r IN relationships(parent_prefix_path) WHERE (%(branch_filter)s))
464+
RETURN current_parent, (r1.status = "active" AND r2.status = "active") AS parent_is_active
465+
ORDER BY r1.branch_level DESC, r1.from DESC, r1.status ASC, r2.branch_level DESC, r2.from DESC, r2.status ASC
466+
LIMIT 1
467+
}
468+
WITH ip_namespace, ip_node, prefix_parent, CASE WHEN parent_is_active THEN current_parent ELSE NULL END as address_parent
469+
WITH ip_namespace, ip_node, COALESCE(prefix_parent, address_parent) AS current_parent
459470
""" % {
460471
"branch_filter": branch_filter,
461472
"ip_prefix_kind": InfrahubKind.IPPREFIX,
@@ -467,7 +478,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG
467478
// Get prefix node's current prefix children, if any exist
468479
// ------------------
469480
CALL (ip_node) {
470-
OPTIONAL MATCH child_prefix_path = (ip_node)<-[r1:IS_RELATED]-(:Relationship {name: "parent__child"})<-[r2:IS_RELATED]-(current_prefix_child:%(ip_prefix_kind)s)
481+
OPTIONAL MATCH child_prefix_path = (ip_node:%(ip_prefix_kind)s)<-[r1:IS_RELATED]-(:Relationship {name: "parent__child"})<-[r2:IS_RELATED]-(current_prefix_child:%(ip_prefix_kind)s)
471482
WHERE all(r IN relationships(child_prefix_path) WHERE (%(branch_filter)s))
472483
WITH current_prefix_child, (r1.status = "active" AND r2.status = "active") AS is_active
473484
ORDER BY current_prefix_child.uuid, r1.branch_level DESC, r1.from DESC, r2.branch_level DESC, r2.from DESC
@@ -479,7 +490,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG
479490
// Get prefix node's current address children, if any exist
480491
// ------------------
481492
CALL (ip_node) {
482-
OPTIONAL MATCH child_address_path = (ip_node)-[r1:IS_RELATED]-(:Relationship {name: "ip_prefix__ip_address"})-[r2:IS_RELATED]-(current_address_child:%(ip_address_kind)s)
493+
OPTIONAL MATCH child_address_path = (ip_node:%(ip_prefix_kind)s)-[r1:IS_RELATED]->(:Relationship {name: "ip_prefix__ip_address"})<-[r2:IS_RELATED]-(current_address_child:%(ip_address_kind)s)
483494
WHERE all(r IN relationships(child_address_path) WHERE (%(branch_filter)s))
484495
WITH current_address_child, (r1.status = "active" AND r2.status = "active") AS is_active
485496
ORDER BY current_address_child.uuid, r1.branch_level DESC, r1.from DESC, r2.branch_level DESC, r2.from DESC

backend/infrahub/core/schema/definitions/core/check.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
Attr(name="description", kind="Text", optional=True),
3030
Attr(name="file_path", kind="Text"),
3131
Attr(name="class_name", kind="Text"),
32-
Attr(name="timeout", kind="Number", default_value=10),
32+
Attr(name="timeout", kind="Number", default_value=60),
3333
Attr(name="parameters", kind="JSON", optional=True),
3434
],
3535
relationships=[

backend/infrahub/core/schema/definitions/core/transform.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
Attr(name="name", kind="Text", unique=True),
3030
Attr(name="label", kind="Text", optional=True),
3131
Attr(name="description", kind="Text", optional=True),
32-
Attr(name="timeout", kind="Number", default_value=10),
32+
Attr(name="timeout", kind="Number", default_value=60),
3333
],
3434
relationships=[
3535
Rel(

backend/tests/unit/core/ipam/test_ipam_reconcile_query.py

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,25 @@
11
import ipaddress
2+
from uuid import uuid4
23

34
from infrahub.core import registry
45
from infrahub.core.branch import Branch
56
from infrahub.core.constants import InfrahubKind, SchemaPathType
7+
from infrahub.core.diff.coordinator import DiffCoordinator
8+
from infrahub.core.diff.merger.merger import DiffMerger
69
from infrahub.core.initialization import create_branch, get_default_ipnamespace
710
from infrahub.core.manager import NodeManager
811
from infrahub.core.migrations.schema.node_kind_update import NodeKindUpdateMigration
912
from infrahub.core.node import Node
1013
from infrahub.core.path import SchemaPath
1114
from infrahub.core.query.ipam import IPPrefixReconcileQuery
1215
from infrahub.core.schema.schema_branch import SchemaBranch
16+
from infrahub.core.timestamp import Timestamp
1317
from infrahub.database import InfrahubDatabase
18+
from infrahub.dependencies.registry import get_component_registry
19+
20+
21+
def randomized_branch_name(branch_name: str) -> str:
22+
return f"{branch_name}_{uuid4().hex[:8]}"
1423

1524

1625
async def test_ipprefix_reconcile_query_simple(db: InfrahubDatabase, default_branch: Branch, ip_dataset_01):
@@ -241,7 +250,7 @@ async def test_ipprefix_reconcile_query_get_deleted_node_by_uuid(
241250
async def test_ipprefix_reconcile_query_deleted_children_ignored_on_branch(
242251
db: InfrahubDatabase, ip_dataset_01: dict[str, Node]
243252
):
244-
branch = await create_branch(db=db, branch_name="branch2")
253+
branch = await create_branch(db=db, branch_name=randomized_branch_name("branch2"))
245254

246255
ns1_id = ip_dataset_01["ns1"].id
247256
net140_branch = await NodeManager.get_one(db=db, branch=branch, id=ip_dataset_01["net140"].id)
@@ -276,7 +285,7 @@ async def test_ipprefix_reconcile_query_deleted_children_ignored_on_branch(
276285
async def test_ipprefix_reconcile_query_deleted_parent_ignored_on_branch(
277286
db: InfrahubDatabase, ip_dataset_01: dict[str, Node]
278287
):
279-
branch = await create_branch(db=db, branch_name="branch2")
288+
branch = await create_branch(db=db, branch_name=randomized_branch_name("branch2"))
280289

281290
ns1_id = ip_dataset_01["ns1"].id
282291
net140_branch = await NodeManager.get_one(db=db, branch=branch, id=ip_dataset_01["net140"].id)
@@ -309,7 +318,7 @@ async def test_branch_updates_respected(db: InfrahubDatabase, default_branch: Br
309318
prefix_schema = registry.schema.get_node_schema(name="IpamIPPrefix", branch=default_branch)
310319
address_schema = registry.schema.get_node_schema(name="IpamIPAddress", branch=default_branch)
311320

312-
branch2 = await create_branch(branch_name="branch2", db=db)
321+
branch2 = await create_branch(branch_name=randomized_branch_name("branch2"), db=db)
313322

314323
ns1_id = ip_dataset_01["ns1"].id
315324
net140 = ip_dataset_01["net140"]
@@ -343,6 +352,16 @@ async def test_branch_updates_respected(db: InfrahubDatabase, default_branch: Br
343352
new_address_branch.id,
344353
}
345354
assert set(query.get_calculated_children_uuids()) == expected_children
355+
query = await IPPrefixReconcileQuery.init(
356+
db=db, branch=branch2, ip_value=ipaddress.ip_interface("10.10.0.1"), namespace=ns1_id
357+
)
358+
await query.execute(db=db)
359+
360+
assert query.get_ip_node_uuid() == new_address_branch.id
361+
assert query.get_current_parent_uuid() is None
362+
assert query.get_current_children_uuids() == []
363+
assert query.get_calculated_parent_uuid() == new_parent_branch.id
364+
assert query.get_calculated_children_uuids() == []
346365

347366
await branch2.rebase(db=db)
348367

@@ -364,6 +383,16 @@ async def test_branch_updates_respected(db: InfrahubDatabase, default_branch: Br
364383
new_address_main.id,
365384
}
366385
assert set(query.get_calculated_children_uuids()) == expected_children_after_rebase
386+
query = await IPPrefixReconcileQuery.init(
387+
db=db, branch=branch2, ip_value=ipaddress.ip_interface("10.10.0.2"), namespace=ns1_id
388+
)
389+
await query.execute(db=db)
390+
391+
assert query.get_ip_node_uuid() == new_address_main.id
392+
assert query.get_current_parent_uuid() is None
393+
assert query.get_current_children_uuids() == []
394+
assert query.get_calculated_parent_uuid() == new_parent_branch.id
395+
assert query.get_calculated_children_uuids() == []
367396

368397

369398
async def test_reconcile_parent_child_identification(
@@ -615,7 +644,7 @@ async def test_reconcile_query_on_migrated_kind_node(db: InfrahubDatabase, defau
615644
prefix_140 = ip_dataset_01["net140"]
616645
namespace = ip_dataset_01["ns1"]
617646

618-
branch = await create_branch(db=db, branch_name="migrated-branch")
647+
branch = await create_branch(db=db, branch_name=randomized_branch_name("migrated-branch"))
619648

620649
# update IpamIPPrefix schema name
621650
prefix_schema = registry.schema.get_node_schema(name="IpamIPPrefix", branch=default_branch, duplicate=True)
@@ -657,3 +686,40 @@ async def test_reconcile_query_on_migrated_kind_node(db: InfrahubDatabase, defau
657686
ip_dataset_01["net145"].id,
658687
ip_dataset_01["address10"].id,
659688
}
689+
690+
691+
async def test_reconcile_query_for_address_with_prefix_added_on_branch_and_merged(
692+
db: InfrahubDatabase, default_branch: Branch, ip_dataset_01
693+
):
694+
"""
695+
Test for bug that could cause an IP address to be its own parent after an update on a branch was merged
696+
"""
697+
default_ipnamespace = await get_default_ipnamespace(db=db)
698+
registry.default_ipnamespace = default_ipnamespace.id
699+
address_10 = ip_dataset_01["address10"]
700+
namespace = ip_dataset_01["ns1"]
701+
702+
branch = await create_branch(db=db, branch_name=randomized_branch_name("address-parent"))
703+
704+
prefix_schema = registry.schema.get_node_schema(name="IpamIPPrefix", branch=branch)
705+
new_prefix = await Node.init(db=db, branch=branch, schema=prefix_schema)
706+
await new_prefix.new(db=db, prefix="10.10.0.0/28", ip_namespace=namespace, ip_addresses=[address_10.id])
707+
await new_prefix.save(db=db)
708+
709+
component_registry = get_component_registry()
710+
diff_coordinator = await component_registry.get_component(DiffCoordinator, db=db, branch=branch)
711+
diff_merger = await component_registry.get_component(DiffMerger, db=db, branch=branch)
712+
await diff_coordinator.update_branch_diff(base_branch=default_branch, diff_branch=branch)
713+
await diff_merger.merge_graph(at=Timestamp())
714+
# get branch to make sure branched_from is refreshed
715+
branch = await Branch.get_by_name(db=db, name=branch.name)
716+
717+
ip_interface = ipaddress.ip_interface(address_10.address.value)
718+
query = await IPPrefixReconcileQuery.init(db=db, branch=branch, ip_value=ip_interface, namespace=namespace)
719+
await query.execute(db=db)
720+
721+
assert query.get_ip_node_uuid() == address_10.id
722+
assert query.get_current_parent_uuid() == new_prefix.id
723+
assert query.get_current_children_uuids() == []
724+
assert query.get_calculated_parent_uuid() == new_prefix.id
725+
assert query.get_calculated_children_uuids() == []

changelog/+298e7542.changed.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

changelog/+45c6002b.added.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

changelog/+4968885a.added.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

changelog/+IFC-1905.added.md

Lines changed: 0 additions & 10 deletions
This file was deleted.

0 commit comments

Comments
 (0)