Skip to content

Commit d0309f4

Browse files
[release-1.27] Fix named port mapping with ServiceEntries in ambient (#57784)
* fix issue with named target ports + SE * add release notes * tweak language * release note type --------- Co-authored-by: Aaron Birkland <[email protected]>
1 parent 9ba9020 commit d0309f4

File tree

3 files changed

+82
-7
lines changed

3 files changed

+82
-7
lines changed

pilot/pkg/serviceregistry/kube/controller/ambient/workloads.go

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1401,14 +1401,25 @@ func constructServices(p *v1.Pod, services []model.ServiceInfo) map[string]*work
14011401
targetPort := port.TargetPort
14021402
// The svc.Ports represents the workloadapi.Service, which drops the port name info and just has numeric target Port.
14031403
// TargetPort can be 0 which indicates its a named port. Check if its a named port and replace with the real targetPort if so.
1404-
if named, f := svc.PortNames[int32(port.ServicePort)]; f && named.TargetPortName != "" {
1405-
// Pods only match on TargetPort names
1406-
tp, ok := FindPortName(p, named.TargetPortName)
1407-
if !ok {
1408-
// Port not present for this workload. Exclude the port entirely
1409-
continue
1404+
if named, f := svc.PortNames[int32(port.ServicePort)]; f {
1405+
if named.TargetPortName != "" {
1406+
// Kubernetes Service semantics: explicit named targetPort on the Service
1407+
// Pods only match on TargetPort names
1408+
tp, ok := FindPortName(p, named.TargetPortName)
1409+
if !ok {
1410+
// Port not present for this workload. Exclude the port entirely
1411+
continue
1412+
}
1413+
targetPort = uint32(tp)
1414+
} else if svc.Source.Kind == kind.ServiceEntry && named.PortName != "" {
1415+
// ServiceEntry semantics: no explicit named targetPort field; match by ServiceEntry port name to Pod container port name
1416+
if tp, ok := FindPortName(p, named.PortName); ok {
1417+
targetPort = uint32(tp)
1418+
} else if targetPort == 0 {
1419+
// Fallback to service port if we couldn't resolve a name and targetPort wasn't set
1420+
targetPort = port.ServicePort
1421+
}
14101422
}
1411-
targetPort = uint32(tp)
14121423
}
14131424

14141425
pl.Ports = append(pl.Ports, &workloadapi.Port{

pilot/pkg/serviceregistry/kube/controller/ambient/workloads_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,60 @@ func TestPodWorkloads(t *testing.T) {
311311
},
312312
},
313313
},
314+
{
315+
name: "pod selected by ServiceEntry honors port name mapping",
316+
inputs: []any{
317+
model.ServiceInfo{
318+
Service: &workloadapi.Service{
319+
Name: "httpbin",
320+
Namespace: "httpbin2",
321+
Hostname: "httpbin.httpbin2.mesh.internal",
322+
Ports: []*workloadapi.Port{{
323+
ServicePort: 8002,
324+
TargetPort: 0,
325+
}},
326+
},
327+
PortNames: map[int32]model.ServicePortName{
328+
8002: {PortName: "http"},
329+
},
330+
LabelSelector: model.NewSelector(map[string]string{"app": "httpbin"}),
331+
Source: model.TypedObject{Kind: kind.ServiceEntry},
332+
},
333+
},
334+
pod: &v1.Pod{
335+
ObjectMeta: metav1.ObjectMeta{
336+
Name: "httpbin-123",
337+
Namespace: "httpbin2",
338+
Labels: map[string]string{"app": "httpbin"},
339+
},
340+
Spec: v1.PodSpec{
341+
Containers: []v1.Container{{Ports: []v1.ContainerPort{{
342+
Name: "http",
343+
ContainerPort: 8000,
344+
Protocol: v1.ProtocolTCP,
345+
}}}},
346+
},
347+
Status: v1.PodStatus{Phase: v1.PodRunning, Conditions: podReady, PodIP: "10.1.1.1"},
348+
},
349+
result: &workloadapi.Workload{
350+
Uid: "cluster0//Pod/httpbin2/httpbin-123",
351+
Name: "httpbin-123",
352+
Namespace: "httpbin2",
353+
Addresses: [][]byte{netip.MustParseAddr("10.1.1.1").AsSlice()},
354+
Network: testNW,
355+
CanonicalName: "httpbin",
356+
CanonicalRevision: "latest",
357+
WorkloadType: workloadapi.WorkloadType_POD,
358+
WorkloadName: "httpbin-123",
359+
Status: workloadapi.WorkloadStatus_HEALTHY,
360+
ClusterId: testC,
361+
Services: map[string]*workloadapi.PortList{
362+
"httpbin2/httpbin.httpbin2.mesh.internal": {
363+
Ports: []*workloadapi.Port{{ServicePort: 8002, TargetPort: 8000}},
364+
},
365+
},
366+
},
367+
},
314368
{
315369
name: "simple pod with locality",
316370
inputs: []any{

releasenotes/notes/57713.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
apiVersion: release-notes/v2
2+
kind: bug-fix
3+
area: traffic-management
4+
5+
issue:
6+
- https://github.com/istio/istio/issues/57713
7+
8+
releaseNotes:
9+
- |
10+
**Fixed** ServiceEntry resolution in ztunnel now matches ServiceEntry port names to pod container ports, aligning behavior with sidecars where there isn't an explicit targetPort

0 commit comments

Comments
 (0)