Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 150 additions & 0 deletions pkg/commatrix-creator/commatrix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,109 @@ var (
},
},
}

// Test resources for localhost filtering test.
testPodWithLocalhostPorts = &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "localhost-test-pod",
Namespace: "localhost-ns",
Labels: map[string]string{
"app": "localhost-app",
},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "main-container",
Image: "test-image:latest",
Ports: []corev1.ContainerPort{
{
ContainerPort: 8080,
HostIP: "127.0.0.1", // Should be filtered out
},
{
ContainerPort: 9090,
HostIP: "0.0.0.0", // Should NOT be filtered out
},
{
ContainerPort: 3000,
HostIP: "::1", // Should be filtered out
},
},
},
},
},
}

testServiceLocalhost = &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "localhost-service",
Namespace: "localhost-ns",
},
Spec: corev1.ServiceSpec{
Selector: map[string]string{
"app": "localhost-app",
},
Ports: []corev1.ServicePort{
{
Name: "port-8080",
Port: 8080,
Protocol: corev1.ProtocolTCP,
},
{
Name: "port-9090",
Port: 9090,
Protocol: corev1.ProtocolTCP,
},
{
Name: "port-3000",
Port: 3000,
Protocol: corev1.ProtocolTCP,
},
},
Type: corev1.ServiceTypeNodePort,
},
}

testEndpointSliceLocalhost = &discoveryv1.EndpointSlice{
ObjectMeta: metav1.ObjectMeta{
Name: "localhost-service-endpoints",
Namespace: "localhost-ns",
Labels: map[string]string{
"kubernetes.io/service-name": "localhost-service",
},
OwnerReferences: []metav1.OwnerReference{
{
Kind: "Service",
Name: "localhost-service",
},
},
},
AddressType: discoveryv1.AddressTypeIPv4,
Endpoints: []discoveryv1.Endpoint{
{
NodeName: &testNode.Name,
Addresses: []string{"192.168.1.10"},
},
},
Ports: []discoveryv1.EndpointPort{
{
Name: func(s string) *string { return &s }("port-8080"),
Port: func(i int32) *int32 { return &i }(8080),
Protocol: func(p corev1.Protocol) *corev1.Protocol { return &p }(corev1.ProtocolTCP),
},
{
Name: func(s string) *string { return &s }("port-9090"),
Port: func(i int32) *int32 { return &i }(9090),
Protocol: func(p corev1.Protocol) *corev1.Protocol { return &p }(corev1.ProtocolTCP),
},
{
Name: func(s string) *string { return &s }("port-3000"),
Port: func(i int32) *int32 { return &i }(3000),
Protocol: func(p corev1.Protocol) *corev1.Protocol { return &p }(corev1.ProtocolTCP),
},
},
}
)

var _ = g.Describe("Commatrix creator pkg tests", func() {
Expand Down Expand Up @@ -332,5 +435,52 @@ var _ = g.Describe("Commatrix creator pkg tests", func() {
o.Expect(diff.GetUniquePrimary().Matrix).To(o.BeEmpty())
o.Expect(diff.GetUniqueSecondary().Matrix).To(o.BeEmpty())
})

g.It("Should filter out localhost-bound ports from endpoint matrix", func() {
g.By("Setting up fake client with localhost test resources")
sch := runtime.NewScheme()
err := corev1.AddToScheme(sch)
o.Expect(err).NotTo(o.HaveOccurred())
err = discoveryv1.AddToScheme(sch)
o.Expect(err).NotTo(o.HaveOccurred())
o.Expect(err).NotTo(o.HaveOccurred())

fakeClient := fake.NewClientBuilder().WithScheme(sch).WithObjects(
testNode,
testPodWithLocalhostPorts, testServiceLocalhost, testEndpointSliceLocalhost).Build()
fakeClientset := fakek.NewSimpleClientset()

clientset := &client.ClientSet{
Client: fakeClient,
CoreV1Interface: fakeClientset.CoreV1(),
}

localhostEndpointSlices, err := endpointslices.New(clientset)
o.Expect(err).ToNot(o.HaveOccurred())

g.By("Creating endpoint matrix")
commatrixCreator, err := New(localhostEndpointSlices, "", "", configv1.AWSPlatformType, types.SNO, false)
o.Expect(err).ToNot(o.HaveOccurred())
commatrix, err := commatrixCreator.CreateEndpointMatrix()
o.Expect(err).ToNot(o.HaveOccurred())

g.By("Verifying that localhost-bound ports (8080 on 127.0.0.1, 3000 on ::1) are filtered out")
for _, entry := range commatrix.Matrix {
if entry.Service == "localhost-service" {
o.Expect(entry.Port).ToNot(o.Equal(8080), "Port 8080 bound to 127.0.0.1 should be filtered out")
o.Expect(entry.Port).ToNot(o.Equal(3000), "Port 3000 bound to ::1 should be filtered out")
}
}

g.By("Verifying that non-localhost port (9090 on 0.0.0.0) is present")
foundPort9090 := false
for _, entry := range commatrix.Matrix {
if entry.Service == "localhost-service" && entry.Port == 9090 {
foundPort9090 = true
break
}
}
o.Expect(foundPort9090).To(o.BeTrue(), "Port 9090 bound to 0.0.0.0 should be present in the matrix")
})
})
})
8 changes: 7 additions & 1 deletion pkg/endpointslices/endpointslices.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,13 @@ func (ep *EndpointSlicesExporter) LoadExposedEndpointSlicesInfo() error {
if len(ports) == 0 {
continue
}
epl.Items[0].Ports = ports
// Exclude ports explicitly bound to localhost (127.0.0.1 or ::1)
epsPortsInfo := getEndpointSlicePortsFromPod(pods.Items[0], ports)
portsNoLocalhost := filterOutLocalhostPorts(epsPortsInfo)
if len(portsNoLocalhost) == 0 {
continue
}
epl.Items[0].Ports = portsNoLocalhost
}
epsliceInfo := createEPSliceInfo(service, epl.Items[0], pods.Items)
log.Debug("epsliceInfo created", epsliceInfo)
Expand Down
13 changes: 13 additions & 0 deletions pkg/endpointslices/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,19 @@ func filterEndpointPortsByPodHostPort(portsInfo []EndpointPortInfo) []discoveryv
return filteredPorts
}

// filterOutLocalhostPorts returns endpoint ports from the given pod
// but excludes any port entries explicitly bound to localhost (127.0.0.1 or ::1).
func filterOutLocalhostPorts(portsInfo []EndpointPortInfo) []discoveryv1.EndpointPort {
filtered := make([]discoveryv1.EndpointPort, 0, len(portsInfo))
for _, pi := range portsInfo {
if pi.ContainerPort.HostIP == "127.0.0.1" || pi.ContainerPort.HostIP == "::1" {
continue
}
filtered = append(filtered, pi.EndpointPort)
}
return filtered
}

// filterHostNetwork checks if the pods behind the endpointSlice are host network.
func isHostNetworked(pod corev1.Pod) bool {
// Assuming all pods in an EndpointSlice are uniformly on host network or not, we only check the first one.
Expand Down