Do not create endpoints if service of type ExternalName (#114814)

This commit is contained in:
Viacheslav Panasovets
2023-01-18 12:12:34 +01:00
committed by GitHub
parent 46f3821bf4
commit 6adf60fdf4
5 changed files with 268 additions and 1 deletions

View File

@@ -378,6 +378,12 @@ func (e *Controller) syncService(ctx context.Context, key string) error {
return nil
}
if service.Spec.Type == v1.ServiceTypeExternalName {
// services with Type ExternalName receive no endpoints from this controller;
// Ref: https://issues.k8s.io/105986
return nil
}
if service.Spec.Selector == nil {
// services without a selector receive no endpoints from this controller;
// these services will receive the endpoints that are created out-of-band via the REST API.

View File

@@ -479,6 +479,75 @@ func TestSyncEndpointsHeadlessServiceLabel(t *testing.T) {
endpointsHandler.ValidateRequestCount(t, 0)
}
func TestSyncServiceExternalNameType(t *testing.T) {
serviceName := "testing-1"
namespace := metav1.NamespaceDefault
testCases := []struct {
desc string
service *v1.Service
}{
{
desc: "External name with selector and ports should not receive endpoints",
service: &v1.Service{
ObjectMeta: metav1.ObjectMeta{Name: serviceName, Namespace: namespace},
Spec: v1.ServiceSpec{
Selector: map[string]string{"foo": "bar"},
Ports: []v1.ServicePort{{Port: 80}},
Type: v1.ServiceTypeExternalName,
},
},
},
{
desc: "External name with ports should not receive endpoints",
service: &v1.Service{
ObjectMeta: metav1.ObjectMeta{Name: serviceName, Namespace: namespace},
Spec: v1.ServiceSpec{
Ports: []v1.ServicePort{{Port: 80}},
Type: v1.ServiceTypeExternalName,
},
},
},
{
desc: "External name with selector should not receive endpoints",
service: &v1.Service{
ObjectMeta: metav1.ObjectMeta{Name: serviceName, Namespace: namespace},
Spec: v1.ServiceSpec{
Selector: map[string]string{"foo": "bar"},
Type: v1.ServiceTypeExternalName,
},
},
},
{
desc: "External name without selector and ports should not receive endpoints",
service: &v1.Service{
ObjectMeta: metav1.ObjectMeta{Name: serviceName, Namespace: namespace},
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeExternalName,
},
},
},
}
for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
testServer, endpointsHandler := makeTestServer(t, namespace)
defer testServer.Close()
endpoints := newController(testServer.URL, 0*time.Second)
err := endpoints.serviceStore.Add(tc.service)
if err != nil {
t.Fatalf("Error adding service to service store: %v", err)
}
err = endpoints.syncService(context.TODO(), namespace+"/"+serviceName)
if err != nil {
t.Fatalf("Error syncing service: %v", err)
}
endpointsHandler.ValidateRequestCount(t, 0)
})
}
}
func TestSyncEndpointsProtocolUDP(t *testing.T) {
ns := "other"
testServer, endpointsHandler := makeTestServer(t, ns)

View File

@@ -328,6 +328,12 @@ func (c *Controller) syncService(key string) error {
return nil
}
if service.Spec.Type == v1.ServiceTypeExternalName {
// services with Type ExternalName receive no endpoints from this controller;
// Ref: https://issues.k8s.io/105986
return nil
}
if service.Spec.Selector == nil {
// services without a selector receive no endpoint slices from this controller;
// these services will receive endpoint slices that are created out-of-band via the REST API.

View File

@@ -134,6 +134,78 @@ func TestSyncServiceNoSelector(t *testing.T) {
assert.Len(t, client.Actions(), 0)
}
func TestServiceExternalNameTypeSync(t *testing.T) {
serviceName := "testing-1"
namespace := metav1.NamespaceDefault
testCases := []struct {
desc string
service *v1.Service
}{
{
desc: "External name with selector and ports should not receive endpoint slices",
service: &v1.Service{
ObjectMeta: metav1.ObjectMeta{Name: serviceName, Namespace: namespace},
Spec: v1.ServiceSpec{
Selector: map[string]string{"foo": "bar"},
Ports: []v1.ServicePort{{Port: 80}},
Type: v1.ServiceTypeExternalName,
},
},
},
{
desc: "External name with ports should not receive endpoint slices",
service: &v1.Service{
ObjectMeta: metav1.ObjectMeta{Name: serviceName, Namespace: namespace},
Spec: v1.ServiceSpec{
Ports: []v1.ServicePort{{Port: 80}},
Type: v1.ServiceTypeExternalName,
},
},
},
{
desc: "External name with selector should not receive endpoint slices",
service: &v1.Service{
ObjectMeta: metav1.ObjectMeta{Name: serviceName, Namespace: namespace},
Spec: v1.ServiceSpec{
Selector: map[string]string{"foo": "bar"},
Type: v1.ServiceTypeExternalName,
},
},
},
{
desc: "External name without selector and ports should not receive endpoint slices",
service: &v1.Service{
ObjectMeta: metav1.ObjectMeta{Name: serviceName, Namespace: namespace},
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeExternalName,
},
},
},
}
for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
client, esController := newController([]string{"node-1"}, time.Duration(0))
pod := newPod(1, namespace, true, 0, false)
err := esController.podStore.Add(pod)
assert.NoError(t, err)
err = esController.serviceStore.Add(tc.service)
assert.NoError(t, err)
err = esController.syncService(fmt.Sprintf("%s/%s", namespace, serviceName))
assert.NoError(t, err)
assert.Len(t, client.Actions(), 0)
sliceList, err := client.DiscoveryV1().EndpointSlices(namespace).List(context.TODO(), metav1.ListOptions{})
assert.NoError(t, err)
assert.Len(t, sliceList.Items, 0, "Expected 0 endpoint slices")
})
}
}
// Ensure SyncService for service with pending deletion results in no action
func TestSyncServicePendingDeletion(t *testing.T) {
ns := metav1.NamespaceDefault