Skip to content

Commit 9508b80

Browse files
authored
Merge pull request #5853 from opsmill/pog-group-event-ancestors-IFC-1073
Add ancestors to group events
2 parents 29223e6 + fe52320 commit 9508b80

File tree

7 files changed

+204
-23
lines changed

7 files changed

+204
-23
lines changed

backend/infrahub/core/manager.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ async def query_hierarchy(
451451
limit: Optional[int] = None,
452452
at: Optional[Union[Timestamp, str]] = None,
453453
branch: Optional[Union[Branch, str]] = None,
454-
) -> dict[str, Any]:
454+
) -> dict[str, Node]:
455455
branch = await registry.get_branch(branch=branch, db=db)
456456
at = Timestamp(at)
457457

backend/infrahub/events/group_action.py

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ class GroupMutatedEvent(InfrahubEvent):
1616
node_id: str = Field(..., description="The ID of the updated group")
1717
action: MutationAction = Field(..., description="The action taken on the node")
1818
members: list[EventNode] = Field(default_factory=list, description="Updated members during this event.")
19+
ancestors: list[EventNode] = Field(
20+
default_factory=list, description="A list of groups that are ancestors of this group."
21+
)
1922

2023
def get_related(self) -> list[dict[str, str]]:
2124
related = super().get_related()
@@ -26,7 +29,22 @@ def get_related(self) -> list[dict[str, str]]:
2629
"infrahub.node.kind": self.kind,
2730
}
2831
)
32+
related.append(
33+
{
34+
"prefect.resource.id": self.node_id,
35+
"prefect.resource.role": "infrahub.group.update",
36+
"infrahub.node.kind": self.kind,
37+
}
38+
)
39+
2940
for member in self.members:
41+
related.append(
42+
{
43+
"prefect.resource.id": member.id,
44+
"prefect.resource.role": "infrahub.group.member",
45+
"infrahub.node.kind": member.kind,
46+
}
47+
)
3048
related.append(
3149
{
3250
"prefect.resource.id": member.id,
@@ -35,6 +53,29 @@ def get_related(self) -> list[dict[str, str]]:
3553
}
3654
)
3755

56+
for ancestor in self.ancestors:
57+
related.append(
58+
{
59+
"prefect.resource.id": ancestor.id,
60+
"prefect.resource.role": "infrahub.group.ancestor",
61+
"infrahub.node.kind": ancestor.kind,
62+
}
63+
)
64+
related.append(
65+
{
66+
"prefect.resource.id": ancestor.id,
67+
"prefect.resource.role": "infrahub.related.node",
68+
"infrahub.node.kind": ancestor.kind,
69+
}
70+
)
71+
related.append(
72+
{
73+
"prefect.resource.id": ancestor.id,
74+
"prefect.resource.role": "infrahub.group.update",
75+
"infrahub.node.kind": ancestor.kind,
76+
}
77+
)
78+
3879
return related
3980

4081
@computed_field
@@ -51,7 +92,10 @@ def get_resource(self) -> dict[str, str]:
5192
}
5293

5394
def get_payload(self) -> dict[str, Any]:
54-
return {"members": [member.model_dump() for member in self.members]}
95+
return {
96+
"ancestors": [ancestor.model_dump() for ancestor in self.ancestors],
97+
"members": [member.model_dump() for member in self.members],
98+
}
5599

56100
def get_messages(self) -> list[InfrahubMessage]:
57101
return []

backend/infrahub/graphql/mutations/relationship.py

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
PermissionAction,
1616
PermissionDecision,
1717
RelationshipCardinality,
18+
RelationshipHierarchyDirection,
1819
)
1920
from infrahub.core.manager import NodeManager
2021
from infrahub.core.query.node import NodeGetKindQuery
@@ -23,6 +24,7 @@
2324
RelationshipPeerData,
2425
)
2526
from infrahub.core.relationship import Relationship
27+
from infrahub.core.schema import NodeSchema
2628
from infrahub.database import retry_db_transaction
2729
from infrahub.events import EventMeta, NodeMutatedEvent
2830
from infrahub.events.group_action import GroupMemberAddedEvent, GroupMemberRemovedEvent
@@ -89,6 +91,10 @@ async def mutate(
8991

9092
existing_peers = await _collect_current_peers(info=info, data=data, source_node=source)
9193

94+
group_event_type = _get_group_event_type(
95+
node=source, relationship_schema=rel_schema, relationship_name=relationship_name
96+
)
97+
9298
async with graphql_context.db.start_transaction() as db:
9399
peers: list[EventNode] = []
94100
for node_data in data.get("nodes"):
@@ -99,19 +105,19 @@ async def mutate(
99105
await rel.resolve(db=db)
100106
# Save it only if it does not exist
101107
if rel.get_peer_id() not in existing_peers.keys():
102-
peers.append(EventNode(id=rel.get_peer_id(), kind=rel.get_peer_kind()))
108+
if group_event_type != GroupUpdateType.NONE:
109+
peers.append(EventNode(id=rel.get_peer_id(), kind=nodes[rel.get_peer_id()].get_kind()))
103110
node_changelog.create_relationship(relationship=rel)
104111
await rel.save(db=db)
105112

106113
if config.SETTINGS.broker.enable and graphql_context.background and node_changelog.has_changes:
107-
group_event_type = _get_group_event_type(
108-
node=source, relationship_schema=rel_schema, relationship_name=relationship_name
109-
)
110114
if group_event_type == GroupUpdateType.MEMBERS:
115+
ancestors = await _collect_ancestors(info=info, node_kind=source.get_schema().kind, node_id=source.id)
111116
group_add_event = GroupMemberAddedEvent(
112117
node_id=source.id,
113118
kind=source.get_schema().kind,
114119
members=peers,
120+
ancestors=ancestors,
115121
meta=EventMeta(branch=graphql_context.branch, context=graphql_context.get_context()),
116122
)
117123
graphql_context.background.add_task(graphql_context.active_service.event.send, group_add_event)
@@ -124,9 +130,11 @@ async def mutate(
124130
node_kind_map = await node_kind_query.get_node_kind_map()
125131

126132
for node_id, node_kind in node_kind_map.items():
133+
ancestors = await _collect_ancestors(info=info, node_kind=node_kind, node_id=node_id)
127134
group_add_event = GroupMemberAddedEvent(
128135
node_id=node_id,
129136
kind=node_kind,
137+
ancestors=ancestors,
130138
members=[EventNode(id=source.get_id(), kind=source.get_kind())],
131139
meta=EventMeta(branch=graphql_context.branch, context=graphql_context.get_context()),
132140
)
@@ -175,6 +183,9 @@ async def mutate(
175183
)
176184

177185
existing_peers = await _collect_current_peers(info=info, data=data, source_node=source)
186+
group_event_type = _get_group_event_type(
187+
node=source, relationship_schema=rel_schema, relationship_name=relationship_name
188+
)
178189

179190
async with graphql_context.db.start_transaction() as db:
180191
peers: list[EventNode] = []
@@ -186,19 +197,19 @@ async def mutate(
186197
# it would be more query efficient
187198
rel = Relationship(schema=rel_schema, branch=graphql_context.branch, node=source)
188199
await rel.load(db=db, data=existing_peers[node_data.get("id")])
189-
peers.append(EventNode(id=rel.get_peer_id(), kind=rel.get_peer_kind()))
200+
if group_event_type != GroupUpdateType.NONE:
201+
peers.append(EventNode(id=rel.get_peer_id(), kind=nodes[rel.get_peer_id()].get_kind()))
190202
node_changelog.delete_relationship(relationship=rel)
191203
await rel.delete(db=db)
192204

193205
if config.SETTINGS.broker.enable and graphql_context.background and node_changelog.has_changes:
194-
group_event_type = _get_group_event_type(
195-
node=source, relationship_schema=rel_schema, relationship_name=relationship_name
196-
)
197206
if group_event_type == GroupUpdateType.MEMBERS:
207+
ancestors = await _collect_ancestors(info=info, node_kind=source.get_schema().kind, node_id=source.id)
198208
group_remove_event = GroupMemberRemovedEvent(
199209
node_id=source.id,
200210
kind=source.get_schema().kind,
201211
members=peers,
212+
ancestors=ancestors,
202213
meta=EventMeta(branch=graphql_context.branch, context=graphql_context.get_context()),
203214
)
204215
graphql_context.background.add_task(graphql_context.active_service.event.send, group_remove_event)
@@ -210,6 +221,7 @@ async def mutate(
210221
node_kind_map = await node_kind_query.get_node_kind_map()
211222

212223
for node_id, node_kind in node_kind_map.items():
224+
ancestors = await _collect_ancestors(info=info, node_kind=node_kind, node_id=node_id)
213225
group_remove_event = GroupMemberRemovedEvent(
214226
node_id=node_id,
215227
kind=node_kind,
@@ -332,6 +344,24 @@ async def _validate_peer_types(
332344
)
333345

334346

347+
async def _collect_ancestors(info: GraphQLResolveInfo, node_kind: str, node_id: str) -> list[EventNode]:
348+
graphql_context: GraphqlContext = info.context
349+
schema = graphql_context.db.schema.get(name=node_kind, branch=graphql_context.branch)
350+
351+
if not isinstance(schema, NodeSchema):
352+
return []
353+
354+
ancestors = await NodeManager.query_hierarchy(
355+
db=graphql_context.db,
356+
branch=graphql_context.branch,
357+
direction=RelationshipHierarchyDirection.ANCESTORS,
358+
id=node_id,
359+
node_schema=schema,
360+
filters={"id": None},
361+
)
362+
return [EventNode(id=ancestor.get_id(), kind=ancestor.get_kind()) for ancestor in ancestors.values()]
363+
364+
335365
async def _collect_current_peers(
336366
info: GraphQLResolveInfo, data: RelationshipNodesInput, source_node: Node
337367
) -> dict[str, RelationshipPeerData]:

backend/infrahub/graphql/types/event.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,14 @@ class Meta:
113113
attributes = Field(List(of_type=NonNull(InfrahubMutatedAttribute), required=True), required=True)
114114

115115

116+
class GroupEvent(ObjectType):
117+
class Meta:
118+
interfaces = (EventNodeInterface,)
119+
120+
members = List(NonNull(RelatedNode), required=True, description="Group members modified in this event")
121+
ancestors = List(NonNull(RelatedNode), required=True, description="Ancestor groups of this impacted group")
122+
123+
116124
class StandardEvent(ObjectType):
117125
class Meta:
118126
interfaces = (EventNodeInterface,)
@@ -128,5 +136,7 @@ class Meta:
128136
"infrahub.branch.merged": BranchMergedEvent,
129137
"infrahub.branch.rebased": BranchRebasedEvent,
130138
"infrahub.branch.deleted": BranchDeletedEvent,
139+
"infrahub.group.member_added": GroupEvent,
140+
"infrahub.group.member_removed": GroupEvent,
131141
"undefined": StandardEvent,
132142
}

backend/infrahub/task_manager/event.py

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -125,21 +125,38 @@ def _return_branch_merged(self) -> dict[str, Any]:
125125
def _return_branch_rebased(self) -> dict[str, Any]:
126126
return {"rebased_branch": self._get_branch_name_from_resource()}
127127

128+
def _return_group_event(self) -> dict[str, Any]:
129+
members = []
130+
ancestors = []
131+
132+
for resource in self.related:
133+
if resource.role == "infrahub.group.member" and resource.get("infrahub.node.kind"):
134+
members.append({"id": resource.id, "kind": resource.get("infrahub.node.kind")})
135+
elif resource.role == "infrahub.group.ancestor" and resource.get("infrahub.node.kind"):
136+
ancestors.append({"id": resource.id, "kind": resource.get("infrahub.node.kind")})
137+
138+
return {"members": members, "ancestors": ancestors}
139+
128140
def _return_event_specifics(self) -> dict[str, Any]:
129141
"""Return event specific data based on the type of event being processed"""
142+
143+
event_specifics = {}
144+
130145
match self.event:
131146
case "infrahub.node.created" | "infrahub.node.updated" | "infrahub.node.deleted":
132-
return self._return_node_mutation()
147+
event_specifics = self._return_node_mutation()
133148
case "infrahub.branch.created":
134-
return self._return_branch_created()
149+
event_specifics = self._return_branch_created()
135150
case "infrahub.branch.deleted":
136-
return self._return_branch_deleted()
151+
event_specifics = self._return_branch_deleted()
137152
case "infrahub.branch.merged":
138-
return self._return_branch_merged()
153+
event_specifics = self._return_branch_merged()
139154
case "infrahub.branch.rebased":
140-
return self._return_branch_rebased()
155+
event_specifics = self._return_branch_rebased()
156+
case "infrahub.group.member_added" | "infrahub.group.member_removed":
157+
event_specifics = self._return_group_event()
141158

142-
return {}
159+
return event_specifics
143160

144161
def to_graphql(self) -> dict[str, Any]:
145162
response = {

0 commit comments

Comments
 (0)