Skip to content

Commit edd78e9

Browse files
committed
Allow all headless services, not just those backed by Statefulsets with subdomains (openservicemesh#5250)
* Allow all headless services, not just those backed by Statefulsets with subdomains Signed-off-by: Keith Mattix II <[email protected]>
1 parent 6815b67 commit edd78e9

7 files changed

+305
-9
lines changed

.github/workflows/main.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ jobs:
160160
matrix:
161161
k8s_version: [""]
162162
focus: [""]
163-
bucket: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
163+
bucket: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
164164
include:
165165
- k8s_version: v1.22.9
166166
focus: "Test traffic flowing from client to server with a Kubernetes Service for the Source: HTTP"

pkg/cli/verifier/envoy_config.go

+10
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818

1919
configv1alpha2 "github.com/openservicemesh/osm/pkg/apis/config/v1alpha2"
2020
"github.com/openservicemesh/osm/pkg/envoy"
21+
"github.com/openservicemesh/osm/pkg/k8s"
2122
"github.com/openservicemesh/osm/pkg/trafficpolicy"
2223

2324
"github.com/openservicemesh/osm/pkg/constants"
@@ -480,11 +481,15 @@ func (v *EnvoyConfigVerifier) getDstMeshServicesForSvcPod(svc corev1.Service, po
480481
// us to retrieve the TargetPort for the MeshService.
481482
meshSvc.TargetPort = k8s.GetTargetPortFromEndpoints(portSpec.Name, *endpoints)
482483

484+
// Even if the service is headless, add it so it can be targeted
483485
if !k8s.IsHeadlessService(svc) {
484486
meshServices = append(meshServices, meshSvc)
485487
continue
486488
}
487489

490+
// If there's not at least 1 subdomain-ed MeshService added,
491+
// add the entire headless service
492+
var added bool
488493
for _, subset := range endpoints.Subsets {
489494
for _, address := range subset.Addresses {
490495
if address.Hostname == "" {
@@ -498,8 +503,13 @@ func (v *EnvoyConfigVerifier) getDstMeshServicesForSvcPod(svc corev1.Service, po
498503
Protocol: meshSvc.Protocol,
499504
}
500505
meshServices = append(meshServices, mSvc)
506+
added = true
501507
}
502508
}
509+
510+
if !added {
511+
meshServices = append(meshServices, meshSvc)
512+
}
503513
}
504514

505515
return meshServices, nil

pkg/k8s/client.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,9 @@ func ServiceToMeshServices(c Controller, svc corev1.Service) []service.MeshServi
322322
meshServices = append(meshServices, meshSvc)
323323
continue
324324
}
325-
325+
// If there's not at least 1 subdomain-ed MeshService added,
326+
// add the entire headless service
327+
var added bool
326328
for _, subset := range endpoints.Subsets {
327329
for _, address := range subset.Addresses {
328330
if address.Hostname == "" {
@@ -335,10 +337,14 @@ func ServiceToMeshServices(c Controller, svc corev1.Service) []service.MeshServi
335337
TargetPort: meshSvc.TargetPort,
336338
Protocol: meshSvc.Protocol,
337339
})
340+
added = true
338341
}
339342
}
340-
}
341343

344+
if !added {
345+
meshServices = append(meshServices, meshSvc)
346+
}
347+
}
342348
return meshServices
343349
}
344350

pkg/k8s/client_test.go

+55
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,61 @@ func TestK8sServicesToMeshServices(t *testing.T) {
880880
},
881881
},
882882
},
883+
{
884+
name: "k8s headless service with single port and endpoint (no hostname), no appProtocol set",
885+
// Single port on the service maps to a single MeshService.
886+
// Since no appProtocol is specified, MeshService.Protocol should default
887+
// to http because Port.Protocol=TCP
888+
svc: corev1.Service{
889+
ObjectMeta: metav1.ObjectMeta{
890+
Namespace: "ns1",
891+
Name: "s1",
892+
},
893+
Spec: corev1.ServiceSpec{
894+
Ports: []corev1.ServicePort{
895+
{
896+
Name: "p1",
897+
Port: 80,
898+
Protocol: corev1.ProtocolTCP,
899+
},
900+
},
901+
ClusterIP: corev1.ClusterIPNone,
902+
},
903+
},
904+
svcEndpoints: []runtime.Object{
905+
&corev1.Endpoints{
906+
ObjectMeta: metav1.ObjectMeta{
907+
// Should match svc.Name and svc.Namespace
908+
Namespace: "ns1",
909+
Name: "s1",
910+
},
911+
Subsets: []corev1.EndpointSubset{
912+
{
913+
Addresses: []corev1.EndpointAddress{
914+
{
915+
IP: "10.1.0.1",
916+
},
917+
},
918+
Ports: []corev1.EndpointPort{
919+
{
920+
// Must match the port of 'svc.Spec.Ports[0]'
921+
Port: 8080, // TargetPort
922+
},
923+
},
924+
},
925+
},
926+
},
927+
},
928+
expected: []service.MeshService{
929+
{
930+
Namespace: "ns1",
931+
Name: "s1",
932+
Port: 80,
933+
TargetPort: 8080,
934+
Protocol: "http",
935+
},
936+
},
937+
},
883938
{
884939
name: "multiple ports on k8s service with appProtocol specified",
885940
svc: corev1.Service{

tests/e2e/e2e_client_server_connectivity_test.go

+14-5
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1313

1414
"github.com/openservicemesh/osm/pkg/apis/config/v1alpha2"
15+
"github.com/openservicemesh/osm/pkg/tests"
1516

1617
"github.com/openservicemesh/osm/pkg/constants"
1718
. "github.com/openservicemesh/osm/tests/framework"
@@ -26,26 +27,34 @@ var _ = OSMDescribe("Test HTTP traffic from 1 pod client -> 1 pod server",
2627
func() {
2728
Context("Test traffic flowing from client to server with a Kubernetes Service for the Source: HTTP", func() {
2829
withSourceKubernetesService := true
29-
testTraffic(withSourceKubernetesService, PodCommandDefault)
30+
testTraffic(withSourceKubernetesService, PodCommandDefault, false)
3031
})
3132

3233
Context("Test traffic flowing from client to server without a Kubernetes Service for the Source: HTTP", func() {
3334
// Prior iterations of OSM required that a source pod belong to a Kubernetes service
3435
// for the Envoy proxy to be configured for outbound traffic to some remote server.
3536
// This test ensures we test this scenario: client Pod is not associated w/ a service.
3637
withSourceKubernetesService := false
37-
testTraffic(withSourceKubernetesService, PodCommandDefault)
38+
testTraffic(withSourceKubernetesService, PodCommandDefault, false)
3839
})
3940

4041
Context("Test traffic flowing from client to a server with a podIP bind", func() {
4142
// Prior iterations of OSM didn't allow mesh services to bind to the podIP
4243
// This test ensures that that behavior is configurable via MeshConfig
4344
withSourceKubernetesService := true
44-
testTraffic(withSourceKubernetesService, []string{"gunicorn", "-b", "$(POD_IP):80", "httpbin:app", "-k", "gevent"}, WithLocalProxyMode(v1alpha2.LocalProxyModePodIP))
45+
testTraffic(withSourceKubernetesService, []string{"gunicorn", "-b", "$(POD_IP):80", "httpbin:app", "-k", "gevent"}, false, WithLocalProxyMode(v1alpha2.LocalProxyModePodIP))
46+
})
47+
48+
Context("Test traffic flowing from client to a headless service without a Kubernetes Service for the Source: HTTP", func() {
49+
// Prior iterations of OSM required that a source pod belong to a Kubernetes service
50+
// for the Envoy proxy to be configured for outbound traffic to some remote server.
51+
// This test ensures we test this scenario: client Pod is not associated w/ a service.
52+
withSourceKubernetesService := true
53+
testTraffic(withSourceKubernetesService, PodCommandDefault, true)
4554
})
4655
})
4756

48-
func testTraffic(withSourceKubernetesService bool, destPodCommand []string, installOpts ...InstallOsmOpt) {
57+
func testTraffic(withSourceKubernetesService bool, destPodCommand []string, destServiceHeadless bool, installOpts ...InstallOsmOpt) {
4958
const sourceName = "client"
5059
const destName = "server"
5160
var ns = []string{sourceName, destName}
@@ -68,7 +77,7 @@ func testTraffic(withSourceKubernetesService bool, destPodCommand []string, inst
6877
Expect(err).NotTo(HaveOccurred())
6978
_, err = Td.CreatePod(destName, podDef)
7079
Expect(err).NotTo(HaveOccurred())
71-
dstSvc, err := Td.CreateService(destName, svcDef)
80+
dstSvc, err := Td.CreateService(destName, *tests.HeadlessSvc(&svcDef))
7281
Expect(err).NotTo(HaveOccurred())
7382

7483
// Expect it to be up and running in it's receiver namespace

0 commit comments

Comments
 (0)