Skip to content

Commit 715807b

Browse files
committed
fix:Collapse cross-account artifacts in query lineage response
1 parent 72d1246 commit 715807b

File tree

2 files changed

+178
-1
lines changed

2 files changed

+178
-1
lines changed

src/sagemaker/lineage/query.py

+41-1
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,44 @@ def _convert_api_response(self, response) -> LineageQueryResult:
208208

209209
return converted
210210

211+
def _collapse_cross_cross_account_artifacts(self, query_response):
212+
"""Collapse the duplicate vertices and edges for cross-account."""
213+
for edge in query_response.edges:
214+
if (
215+
"artifact" in edge.source_arn
216+
and "artifact" in edge.destination_arn
217+
and edge.source_arn.split("/")[1] == edge.destination_arn.split("/")[1]
218+
and edge.source_arn != edge.destination_arn
219+
):
220+
edge_source_arn = edge.source_arn
221+
edge_destination_arn = edge.destination_arn
222+
self._update_cross_account_edge(
223+
edges=query_response.edges,
224+
arn=edge_source_arn,
225+
duplicate_arn=edge_destination_arn,
226+
)
227+
self._update_cross_account_vertex(
228+
query_response=query_response, duplicate_arn=edge_destination_arn
229+
)
230+
231+
# remove the duplicate edges from cross account
232+
new_edge = [e for e in query_response.edges if not e.source_arn == e.destination_arn]
233+
query_response.edges = new_edge
234+
235+
return query_response
236+
237+
def _update_cross_account_edge(self, edges, arn, duplicate_arn):
238+
"""Replace the duplicate arn with arn in edges list."""
239+
for idx, e in enumerate(edges):
240+
if e.destination_arn == duplicate_arn:
241+
edges[idx].destination_arn = arn
242+
elif e.source_arn == duplicate_arn:
243+
edges[idx].source_arn = arn
244+
245+
def _update_cross_account_vertex(self, query_response, duplicate_arn):
246+
"""Remove the vertex with duplicate arn in the vertices list."""
247+
query_response.vertices = [v for v in query_response.vertices if not v.arn == duplicate_arn]
248+
211249
def query(
212250
self,
213251
start_arns: List[str],
@@ -235,5 +273,7 @@ def query(
235273
Filters=query_filter._to_request_dict() if query_filter else {},
236274
MaxDepth=max_depth,
237275
)
276+
query_response = self._convert_api_response(query_response)
277+
query_response = self._collapse_cross_cross_account_artifacts(query_response)
238278

239-
return self._convert_api_response(query_response)
279+
return query_response

tests/unit/sagemaker/lineage/test_query.py

+137
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,143 @@ def test_lineage_query(sagemaker_session):
4444
assert response.vertices[1].lineage_entity == "Context"
4545

4646

47+
def test_lineage_query_cross_account_same_artifact(sagemaker_session):
48+
lineage_query = LineageQuery(sagemaker_session)
49+
sagemaker_session.sagemaker_client.query_lineage.return_value = {
50+
"Vertices": [
51+
{
52+
"Arn": "arn:aws:sagemaker:us-east-2:012345678901:artifact/e1f29799189751939405b0f2b5b9d2a0",
53+
"Type": "Endpoint",
54+
"LineageType": "Artifact",
55+
},
56+
{
57+
"Arn": "arn:aws:sagemaker:us-east-2:012345678902:artifact/e1f29799189751939405b0f2b5b9d2a0",
58+
"Type": "Endpoint",
59+
"LineageType": "Artifact",
60+
},
61+
],
62+
"Edges": [
63+
{
64+
"SourceArn": "arn:aws:sagemaker:us-east-2:012345678901:artifact/e1f29799189751939405b0f2b5b9d2a0",
65+
"DestinationArn": "arn:aws:sagemaker:us-east-2:012345678902:artifact/e1f29799189751939405b0f2b5b9d2a0",
66+
"AssociationType": "SAME_AS",
67+
},
68+
{
69+
"SourceArn": "arn:aws:sagemaker:us-east-2:012345678902:artifact/e1f29799189751939405b0f2b5b9d2a0",
70+
"DestinationArn": "arn:aws:sagemaker:us-east-2:012345678901:artifact/e1f29799189751939405b0f2b5b9d2a0",
71+
"AssociationType": "SAME_AS",
72+
},
73+
],
74+
}
75+
76+
response = lineage_query.query(
77+
start_arns=["arn:aws:sagemaker:us-west-2:0123456789012:context/mycontext"]
78+
)
79+
assert len(response.edges) == 0
80+
assert len(response.vertices) == 1
81+
assert (
82+
response.vertices[0].arn
83+
== "arn:aws:sagemaker:us-east-2:012345678901:artifact/e1f29799189751939405b0f2b5b9d2a0"
84+
)
85+
assert response.vertices[0].lineage_source == "Endpoint"
86+
assert response.vertices[0].lineage_entity == "Artifact"
87+
88+
89+
def test_lineage_query_cross_account(sagemaker_session):
90+
lineage_query = LineageQuery(sagemaker_session)
91+
sagemaker_session.sagemaker_client.query_lineage.return_value = {
92+
"Vertices": [
93+
{
94+
"Arn": "arn:aws:sagemaker:us-east-2:012345678901:artifact/e1f29799189751939405b0f2b5b9d2a0",
95+
"Type": "Endpoint",
96+
"LineageType": "Artifact",
97+
},
98+
{
99+
"Arn": "arn:aws:sagemaker:us-east-2:012345678902:artifact/e1f29799189751939405b0f2b5b9d2a0",
100+
"Type": "Endpoint",
101+
"LineageType": "Artifact",
102+
},
103+
{
104+
"Arn": "arn:aws:sagemaker:us-east-2:012345678903:artifact/e1f29799189751939405b0f2b5b9abcd",
105+
"Type": "Endpoint",
106+
"LineageType": "Artifact",
107+
},
108+
{
109+
"Arn": "arn:aws:sagemaker:us-east-2:012345678903:artifact/e1f29799189751939405b0f2b5b9efgh",
110+
"Type": "Endpoint",
111+
"LineageType": "Artifact",
112+
},
113+
],
114+
"Edges": [
115+
{
116+
"SourceArn": "arn:aws:sagemaker:us-east-2:012345678901:artifact/e1f29799189751939405b0f2b5b9d2a0",
117+
"DestinationArn": "arn:aws:sagemaker:us-east-2:012345678902:artifact/e1f29799189751939405b0f2b5b9d2a0",
118+
"AssociationType": "SAME_AS",
119+
},
120+
{
121+
"SourceArn": "arn:aws:sagemaker:us-east-2:012345678902:artifact/e1f29799189751939405b0f2b5b9d2a0",
122+
"DestinationArn": "arn:aws:sagemaker:us-east-2:012345678901:artifact/e1f29799189751939405b0f2b5b9d2a0",
123+
"AssociationType": "SAME_AS",
124+
},
125+
{
126+
"SourceArn": "arn:aws:sagemaker:us-east-2:012345678902:artifact/e1f29799189751939405b0f2b5b9d2a0",
127+
"DestinationArn": "arn:aws:sagemaker:us-east-2:012345678903:artifact/e1f29799189751939405b0f2b5b9abcd",
128+
"AssociationType": "ABC",
129+
},
130+
{
131+
"SourceArn": "arn:aws:sagemaker:us-east-2:012345678903:artifact/e1f29799189751939405b0f2b5b9abcd",
132+
"DestinationArn": "arn:aws:sagemaker:us-east-2:012345678903:artifact/e1f29799189751939405b0f2b5b9efgh",
133+
"AssociationType": "DEF",
134+
},
135+
],
136+
}
137+
138+
response = lineage_query.query(
139+
start_arns=["arn:aws:sagemaker:us-west-2:0123456789012:context/mycontext"]
140+
)
141+
142+
assert len(response.edges) == 2
143+
assert (
144+
response.edges[0].source_arn
145+
== "arn:aws:sagemaker:us-east-2:012345678901:artifact/e1f29799189751939405b0f2b5b9d2a0"
146+
)
147+
assert (
148+
response.edges[0].destination_arn
149+
== "arn:aws:sagemaker:us-east-2:012345678903:artifact/e1f29799189751939405b0f2b5b9abcd"
150+
)
151+
assert response.edges[0].association_type == "ABC"
152+
153+
assert (
154+
response.edges[1].source_arn
155+
== "arn:aws:sagemaker:us-east-2:012345678903:artifact/e1f29799189751939405b0f2b5b9abcd"
156+
)
157+
assert (
158+
response.edges[1].destination_arn
159+
== "arn:aws:sagemaker:us-east-2:012345678903:artifact/e1f29799189751939405b0f2b5b9efgh"
160+
)
161+
assert response.edges[1].association_type == "DEF"
162+
163+
assert len(response.vertices) == 3
164+
assert (
165+
response.vertices[0].arn
166+
== "arn:aws:sagemaker:us-east-2:012345678901:artifact/e1f29799189751939405b0f2b5b9d2a0"
167+
)
168+
assert response.vertices[0].lineage_source == "Endpoint"
169+
assert response.vertices[0].lineage_entity == "Artifact"
170+
assert (
171+
response.vertices[1].arn
172+
== "arn:aws:sagemaker:us-east-2:012345678903:artifact/e1f29799189751939405b0f2b5b9abcd"
173+
)
174+
assert response.vertices[1].lineage_source == "Endpoint"
175+
assert response.vertices[1].lineage_entity == "Artifact"
176+
assert (
177+
response.vertices[2].arn
178+
== "arn:aws:sagemaker:us-east-2:012345678903:artifact/e1f29799189751939405b0f2b5b9efgh"
179+
)
180+
assert response.vertices[2].lineage_source == "Endpoint"
181+
assert response.vertices[2].lineage_entity == "Artifact"
182+
183+
47184
def test_vertex_to_object_endpoint_context(sagemaker_session):
48185
vertex = Vertex(
49186
arn="arn:aws:sagemaker:us-west-2:0123456789012:context/mycontext",

0 commit comments

Comments
 (0)