diff --git a/pkg/controller/endpoint/BUILD b/pkg/controller/endpoint/BUILD index b38b5bb113b..3202f12e557 100644 --- a/pkg/controller/endpoint/BUILD +++ b/pkg/controller/endpoint/BUILD @@ -20,6 +20,7 @@ go_library( "//pkg/util/metrics:go_default_library", "//vendor/github.com/golang/glog:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/labels:go_default_library", diff --git a/pkg/controller/endpoint/endpoints_controller.go b/pkg/controller/endpoint/endpoints_controller.go index 78bdf615d3f..f0b0a4e9129 100644 --- a/pkg/controller/endpoint/endpoints_controller.go +++ b/pkg/controller/endpoint/endpoints_controller.go @@ -23,6 +23,7 @@ import ( "time" "k8s.io/api/core/v1" + apiequality "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" @@ -434,8 +435,11 @@ func (e *EndpointController) syncService(key string) error { } } - if reflect.DeepEqual(currentEndpoints.Subsets, subsets) && - reflect.DeepEqual(currentEndpoints.Labels, service.Labels) { + createEndpoints := len(currentEndpoints.ResourceVersion) == 0 + + if !createEndpoints && + apiequality.Semantic.DeepEqual(currentEndpoints.Subsets, subsets) && + apiequality.Semantic.DeepEqual(currentEndpoints.Labels, service.Labels) { glog.V(5).Infof("endpoints are equal for %s/%s, skipping update", service.Namespace, service.Name) return nil } @@ -451,7 +455,6 @@ func (e *EndpointController) syncService(key string) error { } glog.V(4).Infof("Update endpoints for %v/%v, ready: %d not ready: %d", service.Namespace, service.Name, totalReadyEps, totalNotReadyEps) - createEndpoints := len(currentEndpoints.ResourceVersion) == 0 if createEndpoints { // No previous endpoints, create them _, err = e.client.Core().Endpoints(service.Namespace).Create(newEndpoints) diff --git a/pkg/controller/endpoint/endpoints_controller_test.go b/pkg/controller/endpoint/endpoints_controller_test.go index c4ef729edff..ad4007ca3c7 100644 --- a/pkg/controller/endpoint/endpoints_controller_test.go +++ b/pkg/controller/endpoint/endpoints_controller_test.go @@ -175,6 +175,70 @@ func TestSyncEndpointsItemsPreserveNoSelector(t *testing.T) { endpointsHandler.ValidateRequestCount(t, 0) } +func TestSyncEndpointsExistingNilSubsets(t *testing.T) { + ns := metav1.NamespaceDefault + testServer, endpointsHandler := makeTestServer(t, ns) + defer testServer.Close() + endpoints := newController(testServer.URL) + endpoints.endpointsStore.Add(&v1.Endpoints{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: ns, + ResourceVersion: "1", + }, + Subsets: nil, + }) + endpoints.serviceStore.Add(&v1.Service{ + ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: ns}, + Spec: v1.ServiceSpec{ + Selector: map[string]string{"foo": "bar"}, + Ports: []v1.ServicePort{{Port: 80}}, + }, + }) + endpoints.syncService(ns + "/foo") + endpointsHandler.ValidateRequestCount(t, 0) +} + +func TestSyncEndpointsExistingEmptySubsets(t *testing.T) { + ns := metav1.NamespaceDefault + testServer, endpointsHandler := makeTestServer(t, ns) + defer testServer.Close() + endpoints := newController(testServer.URL) + endpoints.endpointsStore.Add(&v1.Endpoints{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: ns, + ResourceVersion: "1", + }, + Subsets: []v1.EndpointSubset{}, + }) + endpoints.serviceStore.Add(&v1.Service{ + ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: ns}, + Spec: v1.ServiceSpec{ + Selector: map[string]string{"foo": "bar"}, + Ports: []v1.ServicePort{{Port: 80}}, + }, + }) + endpoints.syncService(ns + "/foo") + endpointsHandler.ValidateRequestCount(t, 0) +} + +func TestSyncEndpointsNewNoSubsets(t *testing.T) { + ns := metav1.NamespaceDefault + testServer, endpointsHandler := makeTestServer(t, ns) + defer testServer.Close() + endpoints := newController(testServer.URL) + endpoints.serviceStore.Add(&v1.Service{ + ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: ns}, + Spec: v1.ServiceSpec{ + Selector: map[string]string{"foo": "bar"}, + Ports: []v1.ServicePort{{Port: 80}}, + }, + }) + endpoints.syncService(ns + "/foo") + endpointsHandler.ValidateRequestCount(t, 1) +} + func TestCheckLeftoverEndpoints(t *testing.T) { ns := metav1.NamespaceDefault testServer, _ := makeTestServer(t, ns)