Skip to content

Commit 72ca590

Browse files
committed
fix(backend): fetch only required attributes for group members
Signed-off-by: Fatih Acar <[email protected]>
1 parent 87c7fe2 commit 72ca590

File tree

4 files changed

+117
-106
lines changed

4 files changed

+117
-106
lines changed

backend/infrahub/generators/tasks.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
)
2222
from infrahub.git.base import extract_repo_file_information
2323
from infrahub.git.repository import get_initialized_repo
24+
from infrahub.git.utils import fetch_definition_targets
2425
from infrahub.workers.dependencies import get_client, get_workflow
2526
from infrahub.workflows.catalogue import REQUEST_GENERATOR_DEFINITION_RUN, REQUEST_GENERATOR_RUN
2627
from infrahub.workflows.utils import add_tags
@@ -177,14 +178,7 @@ async def request_generator_definition_run(
177178
branch=model.branch,
178179
)
179180

180-
group = await client.get(
181-
kind=InfrahubKind.GENERICGROUP,
182-
prefetch_relationships=True,
183-
populate_store=True,
184-
id=model.generator_definition.group_id,
185-
branch=model.branch,
186-
)
187-
await group.members.fetch()
181+
group = await fetch_definition_targets(client=client, branch=model.branch, definition=model.generator_definition)
188182

189183
instance_by_member = {}
190184
for instance in existing_instances:

backend/infrahub/git/tasks.py

Lines changed: 3 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
from collections import defaultdict
2-
from typing import Any
3-
41
from infrahub_sdk import InfrahubClient
52
from infrahub_sdk.protocols import (
63
CoreArtifact,
@@ -10,7 +7,6 @@
107
CoreRepositoryValidator,
118
CoreUserValidator,
129
)
13-
from infrahub_sdk.types import Order
1410
from infrahub_sdk.uuidt import UUIDT
1511
from prefect import flow, task
1612
from prefect.cache_policies import NONE
@@ -57,72 +53,7 @@
5753
UserCheckDefinitionData,
5854
)
5955
from .repository import InfrahubReadOnlyRepository, InfrahubRepository, get_initialized_repo
60-
61-
62-
def _collect_parameter_first_segments(params: Any) -> set[str]:
63-
segments: set[str] = set()
64-
65-
def _walk(value: Any) -> None:
66-
if isinstance(value, str):
67-
segment = value.split("__", 1)[0]
68-
if segment:
69-
segments.add(segment)
70-
elif isinstance(value, dict):
71-
for nested in value.values():
72-
_walk(nested)
73-
elif isinstance(value, (list, tuple, set)):
74-
for nested in value:
75-
_walk(nested)
76-
77-
_walk(params)
78-
return segments
79-
80-
81-
async def _prefetch_group_member_nodes(
82-
*,
83-
client: InfrahubClient,
84-
members: Any,
85-
branch: str,
86-
required_fields: set[str],
87-
) -> None:
88-
ids_per_kind: dict[str, list[str]] = defaultdict(list)
89-
for related in getattr(members, "peers", []):
90-
related_id = getattr(related, "id", None)
91-
related_type = getattr(related, "typename", None)
92-
if related_id and related_type:
93-
ids_per_kind[related_type].append(related_id)
94-
95-
if not ids_per_kind:
96-
return
97-
98-
batch = await client.create_batch()
99-
100-
for kind, ids in ids_per_kind.items():
101-
schema = await client.schema.get(kind=kind, branch=branch)
102-
103-
keep_attributes = {field for field in required_fields if field in schema.attribute_names}
104-
keep_relationships = {field for field in required_fields if field in schema.relationship_names}
105-
106-
exclude_attributes = [attr for attr in schema.attribute_names if attr not in keep_attributes]
107-
exclude_relationships = [rel for rel in schema.relationship_names if rel not in keep_relationships]
108-
109-
unique_ids = list(dict.fromkeys(ids))
110-
kwargs: dict[str, Any] = {
111-
"kind": kind,
112-
"ids": unique_ids,
113-
"branch": branch,
114-
"exclude": exclude_attributes + exclude_relationships,
115-
"populate_store": True,
116-
"order": Order(disable=True),
117-
}
118-
119-
if keep_relationships:
120-
kwargs["include"] = list(keep_relationships)
121-
122-
batch.add(task=client.filters, **kwargs)
123-
124-
async for _ in batch.execute():
125-
pass
56+
from .utils import fetch_definition_targets
12657

12758

12859
@flow(
@@ -393,20 +324,7 @@ async def generate_request_artifact_definition(
393324
kind=CoreArtifactDefinition, id=model.artifact_definition_id, branch=model.branch
394325
)
395326

396-
group = await client.get(
397-
kind=artifact_definition.targets.typename,
398-
id=artifact_definition.targets.id,
399-
branch=model.branch,
400-
include=["members"],
401-
)
402-
403-
parameter_fields = _collect_parameter_first_segments(artifact_definition.parameters.value)
404-
await _prefetch_group_member_nodes(
405-
client=client,
406-
members=group.members,
407-
branch=model.branch,
408-
required_fields=parameter_fields,
409-
)
327+
group = await fetch_definition_targets(client=client, branch=model.branch, definition=artifact_definition)
410328

411329
current_members = [member.id for member in group.members.peers]
412330

@@ -659,9 +577,7 @@ async def trigger_repository_user_checks_definitions(model: UserCheckDefinitionD
659577

660578
if definition.targets.id:
661579
# Check against a group of targets
662-
await definition.targets.fetch()
663-
group = definition.targets.peer
664-
await group.members.fetch()
580+
group = await fetch_definition_targets(client=client, branch=model.branch_name, definition=definition)
665581
check_models = []
666582
for relationship in group.members.peers:
667583
member = relationship.peer

backend/infrahub/git/utils.py

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
1-
from typing import TYPE_CHECKING
1+
from collections import defaultdict
2+
from typing import TYPE_CHECKING, Any
3+
4+
from infrahub_sdk import InfrahubClient
5+
from infrahub_sdk.node import InfrahubNode
6+
from infrahub_sdk.protocols import CoreArtifactDefinition, CoreCheckDefinition, CoreGroup
7+
from infrahub_sdk.types import Order
28

39
from infrahub.core import registry
410
from infrahub.core.constants import InfrahubKind
511
from infrahub.core.manager import NodeManager
612
from infrahub.database import InfrahubDatabase
13+
from infrahub.generators.models import ProposedChangeGeneratorDefinition
714

815
from .models import RepositoryBranchInfo, RepositoryData
916

@@ -46,3 +53,103 @@ async def get_repositories_commit_per_branch(
4653
)
4754

4855
return repositories
56+
57+
58+
def _collect_parameter_first_segments(params: Any) -> set[str]:
59+
segments: set[str] = set()
60+
61+
def _walk(value: Any) -> None:
62+
if isinstance(value, str):
63+
segment = value.split("__", 1)[0]
64+
if segment:
65+
segments.add(segment)
66+
elif isinstance(value, dict):
67+
for nested in value.values():
68+
_walk(nested)
69+
elif isinstance(value, (list, tuple, set)):
70+
for nested in value:
71+
_walk(nested)
72+
73+
_walk(params)
74+
return segments
75+
76+
77+
async def _prefetch_group_member_nodes(
78+
*,
79+
client: InfrahubClient,
80+
members: Any,
81+
branch: str,
82+
required_fields: set[str],
83+
) -> None:
84+
ids_per_kind: dict[str, list[str]] = defaultdict(list)
85+
for related in getattr(members, "peers", []):
86+
related_id = getattr(related, "id", None)
87+
related_type = getattr(related, "typename", None)
88+
if related_id and related_type:
89+
ids_per_kind[related_type].append(related_id)
90+
91+
if not ids_per_kind:
92+
return
93+
94+
batch = await client.create_batch()
95+
96+
for kind, ids in ids_per_kind.items():
97+
schema = await client.schema.get(kind=kind, branch=branch)
98+
99+
keep_attributes = {field for field in required_fields if field in schema.attribute_names}
100+
keep_relationships = {field for field in required_fields if field in schema.relationship_names}
101+
102+
exclude_attributes = [attr for attr in schema.attribute_names if attr not in keep_attributes]
103+
exclude_relationships = [rel for rel in schema.relationship_names if rel not in keep_relationships]
104+
105+
unique_ids = list(dict.fromkeys(ids))
106+
kwargs: dict[str, Any] = {
107+
"kind": kind,
108+
"ids": unique_ids,
109+
"branch": branch,
110+
"exclude": exclude_attributes + exclude_relationships,
111+
"populate_store": True,
112+
"order": Order(disable=True),
113+
}
114+
115+
if keep_relationships:
116+
kwargs["include"] = list(keep_relationships)
117+
118+
batch.add(task=client.filters, **kwargs)
119+
120+
async for _ in batch.execute():
121+
pass
122+
123+
124+
async def fetch_definition_targets(
125+
client: InfrahubClient,
126+
branch: str,
127+
definition: CoreArtifactDefinition | CoreCheckDefinition | ProposedChangeGeneratorDefinition,
128+
) -> CoreGroup:
129+
group_id: str
130+
parameters: Any
131+
132+
if isinstance(definition, InfrahubNode):
133+
if definition.typename in [InfrahubKind.ARTIFACTDEFINITION, InfrahubKind.CHECKDEFINITION]:
134+
group_id = definition.targets.id
135+
parameters = definition.parameters.value
136+
elif isinstance(definition, ProposedChangeGeneratorDefinition):
137+
group_id = definition.group_id
138+
parameters = definition.parameters
139+
140+
group = await client.get(
141+
kind=CoreGroup,
142+
id=group_id,
143+
branch=branch,
144+
include=["members"],
145+
)
146+
147+
parameter_fields = _collect_parameter_first_segments(parameters)
148+
await _prefetch_group_member_nodes(
149+
client=client,
150+
members=group.members,
151+
branch=branch,
152+
required_fields=parameter_fields,
153+
)
154+
155+
return group

backend/infrahub/proposed_change/tasks.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
from infrahub.git.base import extract_repo_file_information
5959
from infrahub.git.models import TriggerRepositoryInternalChecks, TriggerRepositoryUserChecks
6060
from infrahub.git.repository import InfrahubRepository, get_initialized_repo
61+
from infrahub.git.utils import fetch_definition_targets
6162
from infrahub.log import get_logger
6263
from infrahub.message_bus.types import (
6364
ProposedChangeArtifactDefinition,
@@ -652,9 +653,7 @@ async def validate_artifacts_generation(model: RequestArtifactDefinitionCheck, c
652653
branch=model.source_branch,
653654
)
654655

655-
await artifact_definition.targets.fetch()
656-
group = artifact_definition.targets.peer
657-
await group.members.fetch()
656+
group = await fetch_definition_targets(client=client, branch=model.source_branch, definition=artifact_definition)
658657

659658
artifacts_by_member = {}
660659
for artifact in existing_artifacts:
@@ -918,14 +917,9 @@ async def request_generator_definition_check(model: RequestGeneratorDefinitionCh
918917
branch=model.source_branch,
919918
)
920919

921-
group = await client.get(
922-
kind=InfrahubKind.GENERICGROUP,
923-
prefetch_relationships=True,
924-
populate_store=True,
925-
id=model.generator_definition.group_id,
926-
branch=model.source_branch,
920+
group = await fetch_definition_targets(
921+
client=client, branch=model.source_branch, definition=model.generator_definition
927922
)
928-
await group.members.fetch()
929923

930924
instance_by_member = {}
931925
for instance in existing_instances:

0 commit comments

Comments
 (0)