From aceca6bcc8f901826c794d326d9f0c6846a28b03 Mon Sep 17 00:00:00 2001 From: Matthias Veit Date: Wed, 30 Oct 2024 14:54:02 +0100 Subject: [PATCH] [core][fix] Use id and name for descendant count (#2271) --- fixcore/fixcore/model/graph_access.py | 30 +++++++++++++++--------- fixcore/tests/fixcore/db/graphdb_test.py | 2 +- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/fixcore/fixcore/model/graph_access.py b/fixcore/fixcore/model/graph_access.py index 2a4395e449..f9cd771583 100644 --- a/fixcore/fixcore/model/graph_access.py +++ b/fixcore/fixcore/model/graph_access.py @@ -488,31 +488,39 @@ def resolve(self) -> None: def __resolve_count_descendants(self) -> None: empty_set: Set[str] = set() - def count_descendants_of(identifier: str, ancestor_kind: str, path: List[str]) -> Dict[str, int]: + def count_descendants_of(rid: str, rname: str, ancestor_kind: str, path: List[str]) -> Dict[str, int]: result: DefaultDict[str, int] = defaultdict(int) - ancestor_path = ["ancestors", ancestor_kind, "reported", "id"] + rid_path = ["ancestors", ancestor_kind, "reported", "id"] + rname_path = ["ancestors", ancestor_kind, "reported", "name"] for _, elem in self.g.nodes(data=True): - if value_in_path(elem, ancestor_path) == identifier: + if value_in_path(elem, rid_path) == rid and value_in_path(elem, rname_path) == rname: kinds_set = elem.get("kinds_set", empty_set) extracted = value_in_path(elem, path) if "phantom_resource" not in kinds_set and isinstance(extracted, str): result[extracted] += 1 return result - for on_kind, prop in GraphResolver.count_successors.items(): - for _, node in self.g.nodes(data=True): - kinds = node.get("kinds_set") - if kinds and on_kind in kinds: - if rid := value_in_path(node, NodePath.reported_id): - # descendant summary - summary = count_descendants_of(rid, on_kind, prop.extract_path) + empty_set = set() + for _, node in self.g.nodes(data=True): + kinds = node.get("kinds_set", empty_set) + for on_kind, prop in GraphResolver.count_successors.items(): + if on_kind in kinds: + if (rid := value_in_path(node, NodePath.reported_id)) and ( + rname := value_in_path(node, NodePath.reported_name) + ): + # Descendant summary: we need to compare id and name. + # Example AWS global region: id=us-east-1, name=global + summary = count_descendants_of(rid, rname, on_kind, prop.extract_path) set_value_in_path(summary, prop.to_path, node) # descendant count total = reduce(lambda left, right: left + right, summary.values(), 0) set_value_in_path(total, NodePath.descendant_count, node) # update hash node["hash"] = GraphBuilder.content_hash( - node["reported"], node.get("desired"), node.get("metadata"), node.get("kinds") + node["reported"], + desired=node.get("desired"), + metadata=node.get("metadata"), + kinds=node.get("kinds"), ) def __resolve(self, node_id: NodeId, node: Json) -> Json: diff --git a/fixcore/tests/fixcore/db/graphdb_test.py b/fixcore/tests/fixcore/db/graphdb_test.py index 3562faf058..be59e387c1 100644 --- a/fixcore/tests/fixcore/db/graphdb_test.py +++ b/fixcore/tests/fixcore/db/graphdb_test.py @@ -354,7 +354,7 @@ def create( # adding another account without org_root does not delete the old root: _, update = await graph_db.merge_graph(create("yes or no", org_root_id=None, account_id="aws_account_2"), foo_model) - assert GraphUpdate(111, 1, 0, 211, 0, 0) == update + assert GraphUpdate(111, 0, 0, 211, 0, 0) == update assert await graph_db.by_id(NodeId("org_root")) is not None