Skip to content

Commit dd3a4f1

Browse files
authored
Merge pull request #6470 from opsmill/pog-multiple-related-matches
Multiple related resources for triggers
2 parents 76a8827 + e3ceec3 commit dd3a4f1

File tree

3 files changed

+122
-53
lines changed

3 files changed

+122
-53
lines changed

backend/infrahub/actions/models.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -116,32 +116,36 @@ def _from_node_trigger(
116116
case BranchScope.OTHER_BRANCHES:
117117
event_trigger.match["infrahub.branch.name"] = f"!{registry.default_branch}"
118118

119+
related_matches: list[dict[str, str | list[str]]] = []
119120
for match in trigger_rule.matches:
120121
if isinstance(match, CoreNodeTriggerAttributeMatch):
121-
event_trigger.match_related = {
122+
match_related: dict[str, str | list[str]] = {
122123
"prefect.resource.role": "infrahub.node.attribute_update",
123124
"infrahub.field.name": match.attribute_name,
124125
"infrahub.attribute.action": ["added", "updated", "removed"],
125126
}
126127

127128
match match.value_match:
128129
case ValueMatch.VALUE:
129-
event_trigger.match_related["infrahub.attribute.value"] = match.value or ""
130+
match_related["infrahub.attribute.value"] = match.value or ""
130131
case ValueMatch.VALUE_PREVIOUS:
131-
event_trigger.match_related["infrahub.attribute.value_previous"] = match.value_previous or ""
132+
match_related["infrahub.attribute.value_previous"] = match.value_previous or ""
132133
case ValueMatch.VALUE_FULL:
133-
event_trigger.match_related["infrahub.attribute.value"] = match.value or ""
134-
event_trigger.match_related["infrahub.attribute.value_previous"] = match.value_previous or ""
134+
match_related["infrahub.attribute.value"] = match.value or ""
135+
match_related["infrahub.attribute.value_previous"] = match.value_previous or ""
135136

136137
elif isinstance(match, CoreNodeTriggerRelationshipMatch):
137138
peer_status = "added" if match.added else "removed"
138-
event_trigger.match_related = {
139+
match_related = {
139140
"prefect.resource.role": "infrahub.node.relationship_update",
140141
"infrahub.field.name": match.relationship_name,
141142
"infrahub.relationship.peer_status": peer_status,
142143
}
143144
if isinstance(match.peer, str):
144-
event_trigger.match_related["infrahub.relationship.peer_id"] = match.peer
145+
match_related["infrahub.relationship.peer_id"] = match.peer
146+
related_matches.append(match_related)
147+
148+
event_trigger.match_related = related_matches or {}
145149

146150
if isinstance(trigger_rule.action, CoreGeneratorAction):
147151
workflow = ExecuteWorkflow(

backend/infrahub/trigger/models.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,21 +39,36 @@ class TriggerType(str, Enum):
3939
# OBJECT = "object"
4040

4141

42+
def _match_related_dict() -> dict:
43+
# Make Mypy happy as match related is a dict[str, Any] | list[dict[str, Any]]
44+
return {}
45+
46+
4247
class EventTrigger(BaseModel):
4348
events: set = Field(default_factory=set)
4449
match: dict[str, Any] = Field(default_factory=dict)
45-
match_related: dict[str, Any] = Field(default_factory=dict)
50+
match_related: dict[str, Any] | list[dict[str, Any]] = Field(default_factory=_match_related_dict)
4651

4752
def get_prefect(self) -> PrefectEventTrigger:
4853
return PrefectEventTrigger(
4954
posture=Posture.Reactive,
5055
expect=self.events,
5156
within=timedelta(0),
5257
match=ResourceSpecification(self.match),
53-
match_related=ResourceSpecification(self.match_related),
58+
match_related=self.related_resource_specification,
5459
threshold=1,
5560
)
5661

62+
@property
63+
def related_resource_specification(self) -> ResourceSpecification | list[ResourceSpecification]:
64+
if isinstance(self.match_related, dict):
65+
return ResourceSpecification(self.match_related)
66+
67+
if len(self.match_related) == 1:
68+
return ResourceSpecification(self.match_related[0])
69+
70+
return [ResourceSpecification(related_match) for related_match in self.match_related]
71+
5772

5873
class ExecuteWorkflow(BaseModel):
5974
workflow: WorkflowDefinition

backend/tests/unit/actions/test_gather.py

Lines changed: 94 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,14 @@ async def test_gather_trigger_gather_trigger_action_rules_node_attribute(
7575
assert automation.trigger == EventTrigger(
7676
events={"infrahub.node.updated"},
7777
match={"infrahub.node.kind": "BuiltinTag", "infrahub.branch.name": "main"},
78-
match_related={
79-
"prefect.resource.role": "infrahub.node.attribute_update",
80-
"infrahub.field.name": "description",
81-
"infrahub.attribute.action": ["added", "updated", "removed"],
82-
"infrahub.attribute.value": "something_new",
83-
},
78+
match_related=[
79+
{
80+
"prefect.resource.role": "infrahub.node.attribute_update",
81+
"infrahub.field.name": "description",
82+
"infrahub.attribute.action": ["added", "updated", "removed"],
83+
"infrahub.attribute.value": "something_new",
84+
}
85+
],
8486
)
8587

8688
attribute_match.value_match.value = "value_previous"
@@ -92,12 +94,14 @@ async def test_gather_trigger_gather_trigger_action_rules_node_attribute(
9294
assert automation.trigger == EventTrigger(
9395
events={"infrahub.node.updated"},
9496
match={"infrahub.node.kind": "BuiltinTag", "infrahub.branch.name": "main"},
95-
match_related={
96-
"prefect.resource.role": "infrahub.node.attribute_update",
97-
"infrahub.field.name": "description",
98-
"infrahub.attribute.action": ["added", "updated", "removed"],
99-
"infrahub.attribute.value_previous": "something_old",
100-
},
97+
match_related=[
98+
{
99+
"prefect.resource.role": "infrahub.node.attribute_update",
100+
"infrahub.field.name": "description",
101+
"infrahub.attribute.action": ["added", "updated", "removed"],
102+
"infrahub.attribute.value_previous": "something_old",
103+
}
104+
],
101105
)
102106

103107
attribute_match.value_match.value = "value_full"
@@ -110,13 +114,15 @@ async def test_gather_trigger_gather_trigger_action_rules_node_attribute(
110114
assert automation.trigger == EventTrigger(
111115
events={"infrahub.node.updated"},
112116
match={"infrahub.node.kind": "BuiltinTag", "infrahub.branch.name": "main"},
113-
match_related={
114-
"prefect.resource.role": "infrahub.node.attribute_update",
115-
"infrahub.field.name": "description",
116-
"infrahub.attribute.action": ["added", "updated", "removed"],
117-
"infrahub.attribute.value": "something_new",
118-
"infrahub.attribute.value_previous": "something_old",
119-
},
117+
match_related=[
118+
{
119+
"prefect.resource.role": "infrahub.node.attribute_update",
120+
"infrahub.field.name": "description",
121+
"infrahub.attribute.action": ["added", "updated", "removed"],
122+
"infrahub.attribute.value": "something_new",
123+
"infrahub.attribute.value_previous": "something_old",
124+
}
125+
],
120126
)
121127

122128
main_node_trigger_rule.branch_scope.value = "other_branches"
@@ -129,13 +135,51 @@ async def test_gather_trigger_gather_trigger_action_rules_node_attribute(
129135
assert automation.trigger == EventTrigger(
130136
events={"infrahub.node.updated"},
131137
match={"infrahub.node.kind": "BuiltinTag", "infrahub.branch.name": "!main"},
132-
match_related={
133-
"prefect.resource.role": "infrahub.node.attribute_update",
134-
"infrahub.field.name": "description",
135-
"infrahub.attribute.action": ["added", "updated", "removed"],
136-
"infrahub.attribute.value": "something_new",
137-
"infrahub.attribute.value_previous": "something_old",
138-
},
138+
match_related=[
139+
{
140+
"prefect.resource.role": "infrahub.node.attribute_update",
141+
"infrahub.field.name": "description",
142+
"infrahub.attribute.action": ["added", "updated", "removed"],
143+
"infrahub.attribute.value": "something_new",
144+
"infrahub.attribute.value_previous": "something_old",
145+
}
146+
],
147+
)
148+
149+
second_attribute_match = await Node.init(db=db, schema=CoreNodeTriggerAttributeMatch)
150+
await second_attribute_match.new(
151+
db=db,
152+
attribute_name="another_attribute",
153+
value="the-new-value",
154+
value_previous="the-old-value",
155+
value_match="value_full",
156+
trigger=main_node_trigger_rule,
157+
)
158+
await second_attribute_match.save(db=db)
159+
160+
triggers = await gather_trigger_action_rules(db=db)
161+
assert len(triggers) == 1
162+
automation = triggers[0]
163+
164+
assert automation.trigger == EventTrigger(
165+
events={"infrahub.node.updated"},
166+
match={"infrahub.node.kind": "BuiltinTag", "infrahub.branch.name": "!main"},
167+
match_related=[
168+
{
169+
"prefect.resource.role": "infrahub.node.attribute_update",
170+
"infrahub.field.name": "description",
171+
"infrahub.attribute.action": ["added", "updated", "removed"],
172+
"infrahub.attribute.value": "something_new",
173+
"infrahub.attribute.value_previous": "something_old",
174+
},
175+
{
176+
"prefect.resource.role": "infrahub.node.attribute_update",
177+
"infrahub.field.name": "another_attribute",
178+
"infrahub.attribute.action": ["added", "updated", "removed"],
179+
"infrahub.attribute.value": "the-new-value",
180+
"infrahub.attribute.value_previous": "the-old-value",
181+
},
182+
],
139183
)
140184

141185
main_node_trigger_rule.active.value = False
@@ -196,12 +240,14 @@ async def test_gather_trigger_gather_trigger_action_rules_node_relationship(
196240
assert automation.trigger == EventTrigger(
197241
events={"infrahub.node.created"},
198242
match={"infrahub.node.kind": "TestCar"},
199-
match_related={
200-
"prefect.resource.role": "infrahub.node.relationship_update",
201-
"infrahub.field.name": "owner",
202-
"infrahub.relationship.peer_id": car_owner.id,
203-
"infrahub.relationship.peer_status": "added",
204-
},
243+
match_related=[
244+
{
245+
"prefect.resource.role": "infrahub.node.relationship_update",
246+
"infrahub.field.name": "owner",
247+
"infrahub.relationship.peer_id": car_owner.id,
248+
"infrahub.relationship.peer_status": "added",
249+
}
250+
],
205251
)
206252

207253
relationship_match.added.value = False
@@ -213,12 +259,14 @@ async def test_gather_trigger_gather_trigger_action_rules_node_relationship(
213259
assert automation.trigger == EventTrigger(
214260
events={"infrahub.node.created"},
215261
match={"infrahub.node.kind": "TestCar"},
216-
match_related={
217-
"prefect.resource.role": "infrahub.node.relationship_update",
218-
"infrahub.field.name": "owner",
219-
"infrahub.relationship.peer_id": car_owner.id,
220-
"infrahub.relationship.peer_status": "removed",
221-
},
262+
match_related=[
263+
{
264+
"prefect.resource.role": "infrahub.node.relationship_update",
265+
"infrahub.field.name": "owner",
266+
"infrahub.relationship.peer_id": car_owner.id,
267+
"infrahub.relationship.peer_status": "removed",
268+
}
269+
],
222270
)
223271

224272
main_node_trigger_rule.branch_scope.value = "other_branches"
@@ -232,12 +280,14 @@ async def test_gather_trigger_gather_trigger_action_rules_node_relationship(
232280
assert automation.trigger == EventTrigger(
233281
events={"infrahub.node.deleted"},
234282
match={"infrahub.node.kind": "TestCar", "infrahub.branch.name": "!main"},
235-
match_related={
236-
"prefect.resource.role": "infrahub.node.relationship_update",
237-
"infrahub.field.name": "owner",
238-
"infrahub.relationship.peer_id": car_owner.id,
239-
"infrahub.relationship.peer_status": "removed",
240-
},
283+
match_related=[
284+
{
285+
"prefect.resource.role": "infrahub.node.relationship_update",
286+
"infrahub.field.name": "owner",
287+
"infrahub.relationship.peer_id": car_owner.id,
288+
"infrahub.relationship.peer_status": "removed",
289+
}
290+
],
241291
)
242292

243293
main_node_trigger_rule.active.value = False

0 commit comments

Comments
 (0)