diff --git a/federation/cmd/federation-apiserver/app/core.go b/federation/cmd/federation-apiserver/app/core.go index 3b0084faa62..e3c807183c2 100644 --- a/federation/cmd/federation-apiserver/app/core.go +++ b/federation/cmd/federation-apiserver/app/core.go @@ -42,16 +42,17 @@ import ( func installCoreAPIs(s *options.ServerRunOptions, g *genericapiserver.GenericAPIServer, f genericapiserver.StorageFactory) { serviceStore, serviceStatusStore := serviceetcd.NewREST(createRESTOptionsOrDie(s, g, f, api.Resource("service"))) - namespaceStore, namespaceStatusStore, _ := namespaceetcd.NewREST(createRESTOptionsOrDie(s, g, f, api.Resource("namespaces"))) + namespaceStore, namespaceStatusStore, namespaceFinalizeStore := namespaceetcd.NewREST(createRESTOptionsOrDie(s, g, f, api.Resource("namespaces"))) secretStore := secretetcd.NewREST(createRESTOptionsOrDie(s, g, f, api.Resource("secrets"))) eventStore := eventetcd.NewREST(createRESTOptionsOrDie(s, g, f, api.Resource("events")), uint64(s.EventTTL.Seconds())) coreResources := map[string]rest.Storage{ - "secrets": secretStore, - "services": serviceStore, - "services/status": serviceStatusStore, - "namespaces": namespaceStore, - "namespaces/status": namespaceStatusStore, - "events": eventStore, + "secrets": secretStore, + "services": serviceStore, + "services/status": serviceStatusStore, + "namespaces": namespaceStore, + "namespaces/status": namespaceStatusStore, + "namespaces/finalize": namespaceFinalizeStore, + "events": eventStore, } coreGroupMeta := registered.GroupOrDie(core.GroupName) apiGroupInfo := genericapiserver.APIGroupInfo{ diff --git a/federation/pkg/federation-controller/namespace/namespace_controller.go b/federation/pkg/federation-controller/namespace/namespace_controller.go index c3f2908bdc3..f05ab848eb6 100644 --- a/federation/pkg/federation-controller/namespace/namespace_controller.go +++ b/federation/pkg/federation-controller/namespace/namespace_controller.go @@ -26,6 +26,7 @@ import ( "k8s.io/kubernetes/federation/pkg/federation-controller/util" "k8s.io/kubernetes/federation/pkg/federation-controller/util/eventsink" "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/errors" api_v1 "k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/client/cache" kube_release_1_4 "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_4" @@ -363,7 +364,12 @@ func (nc *NamespaceController) delete(namespace *api_v1.Namespace) { // TODO: What about namespaces in subclusters ??? err := nc.federatedApiClient.Core().Namespaces().Delete(updatedNamespace.Name, &api.DeleteOptions{}) if err != nil { - glog.Errorf("Failed to delete namespace %s: %v", namespace.Name, err) - nc.deliverNamespace(namespace.Name, 0, true) + // Its all good if the error is not found error. That means it is deleted already and we do not have to do anything. + // This is expected when we are processing an update as a result of namespace finalizer deletion. + // The process that deleted the last finalizer is also going to delete the namespace and we do not have to do anything. + if !errors.IsNotFound(err) { + glog.Errorf("Failed to delete namespace %s: %v", namespace.Name, err) + nc.deliverNamespace(namespace.Name, 0, true) + } } } diff --git a/test/integration/federation/server_test.go b/test/integration/federation/server_test.go index e934d27c61f..8a6c5f4c200 100644 --- a/test/integration/federation/server_test.go +++ b/test/integration/federation/server_test.go @@ -283,8 +283,8 @@ func testCoreResourceList(t *testing.T) { } assert.Equal(t, "", apiResourceList.APIVersion) assert.Equal(t, v1.SchemeGroupVersion.String(), apiResourceList.GroupVersion) - // Assert that there are exactly 6 resources. - assert.Equal(t, 6, len(apiResourceList.APIResources)) + // Assert that there are exactly 7 resources. + assert.Equal(t, 7, len(apiResourceList.APIResources)) // Verify services. found := findResource(apiResourceList.APIResources, "services") @@ -301,6 +301,9 @@ func testCoreResourceList(t *testing.T) { found = findResource(apiResourceList.APIResources, "namespaces/status") assert.NotNil(t, found) assert.False(t, found.Namespaced) + found = findResource(apiResourceList.APIResources, "namespaces/finalize") + assert.NotNil(t, found) + assert.False(t, found.Namespaced) // Verify events. found = findResource(apiResourceList.APIResources, "events")