Skip to content

Commit 25c8e53

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 25c8e53

File tree

7 files changed

+305
-10
lines changed

7 files changed

+305
-10
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ 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"
2425
"github.com/openservicemesh/osm/pkg/envoy/lds"
2526
"github.com/openservicemesh/osm/pkg/envoy/rds/route"
2627
envoySecrets "github.com/openservicemesh/osm/pkg/envoy/secrets"
2728
"github.com/openservicemesh/osm/pkg/identity"
28-
"github.com/openservicemesh/osm/pkg/k8s"
2929
"github.com/openservicemesh/osm/pkg/service"
3030
)
3131

@@ -480,11 +480,15 @@ func (v *EnvoyConfigVerifier) getDstMeshServicesForSvcPod(svc corev1.Service, po
480480
// us to retrieve the TargetPort for the MeshService.
481481
meshSvc.TargetPort = k8s.GetTargetPortFromEndpoints(portSpec.Name, *endpoints)
482482

483+
// Even if the service is headless, add it so it can be targeted
483484
if !k8s.IsHeadlessService(svc) {
484485
meshServices = append(meshServices, meshSvc)
485486
continue
486487
}
487488

489+
// If there's not at least 1 subdomain-ed MeshService added,
490+
// add the entire headless service
491+
var added bool
488492
for _, subset := range endpoints.Subsets {
489493
for _, address := range subset.Addresses {
490494
if address.Hostname == "" {
@@ -498,8 +502,13 @@ func (v *EnvoyConfigVerifier) getDstMeshServicesForSvcPod(svc corev1.Service, po
498502
Protocol: meshSvc.Protocol,
499503
}
500504
meshServices = append(meshServices, mSvc)
505+
added = true
501506
}
502507
}
508+
509+
if !added {
510+
meshServices = append(meshServices, meshSvc)
511+
}
503512
}
504513

505514
return meshServices, nil

pkg/k8s/client.go

Lines changed: 8 additions & 2 deletions
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

Lines changed: 55 additions & 0 deletions
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

Lines changed: 14 additions & 5 deletions
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)