From 83d535aa6c568892a5be819c2c96b0e533c534a8 Mon Sep 17 00:00:00 2001 From: Chao Xu Date: Tue, 30 Jan 2018 14:56:43 -0800 Subject: [PATCH] Client ca post start hook now checks if the system namespace already exists before creating it. This avoids apiserver crashloops if a webhook rejects namespace creation when the apiserver is rebooted. --- pkg/master/BUILD | 1 + pkg/master/client_ca_hook.go | 2 +- pkg/master/client_util.go | 42 ++++++++++++++++++++++++++++++++++++ pkg/master/controller.go | 23 ++------------------ 4 files changed, 46 insertions(+), 22 deletions(-) create mode 100644 pkg/master/client_util.go diff --git a/pkg/master/BUILD b/pkg/master/BUILD index fadfc10b42b..19e398b39c0 100644 --- a/pkg/master/BUILD +++ b/pkg/master/BUILD @@ -10,6 +10,7 @@ go_library( name = "go_default_library", srcs = [ "client_ca_hook.go", + "client_util.go", "controller.go", "doc.go", "import_known_versions.go", diff --git a/pkg/master/client_ca_hook.go b/pkg/master/client_ca_hook.go index fedfdca35ef..75f76a9bce9 100644 --- a/pkg/master/client_ca_hook.go +++ b/pkg/master/client_ca_hook.go @@ -74,7 +74,7 @@ func (h ClientCARegistrationHook) PostStartHook(hookContext genericapiserver.Pos // tryToWriteClientCAs is here for unit testing with a fake client. This is a wait.ConditionFunc so the bool // indicates if the condition was met. True when its finished, false when it should retry. func (h ClientCARegistrationHook) tryToWriteClientCAs(client coreclient.CoreInterface) (bool, error) { - if _, err := client.Namespaces().Create(&api.Namespace{ObjectMeta: metav1.ObjectMeta{Name: metav1.NamespaceSystem}}); err != nil && !apierrors.IsAlreadyExists(err) { + if err := createNamespaceIfNeeded(client, metav1.NamespaceSystem); err != nil { utilruntime.HandleError(err) return false, nil } diff --git a/pkg/master/client_util.go b/pkg/master/client_util.go new file mode 100644 index 00000000000..3868fbae5c5 --- /dev/null +++ b/pkg/master/client_util.go @@ -0,0 +1,42 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package master + +import ( + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + api "k8s.io/kubernetes/pkg/apis/core" + coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion" +) + +func createNamespaceIfNeeded(c coreclient.NamespacesGetter, ns string) error { + if _, err := c.Namespaces().Get(ns, metav1.GetOptions{}); err == nil { + // the namespace already exists + return nil + } + newNs := &api.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: ns, + Namespace: "", + }, + } + _, err := c.Namespaces().Create(newNs) + if err != nil && errors.IsAlreadyExists(err) { + err = nil + } + return err +} diff --git a/pkg/master/controller.go b/pkg/master/controller.go index 291078b2710..78154d176ef 100644 --- a/pkg/master/controller.go +++ b/pkg/master/controller.go @@ -160,7 +160,7 @@ func (c *Controller) RunKubernetesNamespaces(ch chan struct{}) { wait.Until(func() { // Loop the system namespace list, and create them if they do not exist for _, ns := range c.SystemNamespaces { - if err := c.CreateNamespaceIfNeeded(ns); err != nil { + if err := createNamespaceIfNeeded(c.NamespaceClient, ns); err != nil { runtime.HandleError(fmt.Errorf("unable to create required kubernetes system namespace %s: %v", ns, err)) } } @@ -185,7 +185,7 @@ func (c *Controller) UpdateKubernetesService(reconcile bool) error { // TODO: when it becomes possible to change this stuff, // stop polling and start watching. // TODO: add endpoints of all replicas, not just the elected master. - if err := c.CreateNamespaceIfNeeded(metav1.NamespaceDefault); err != nil { + if err := createNamespaceIfNeeded(c.NamespaceClient, metav1.NamespaceDefault); err != nil { return err } @@ -200,25 +200,6 @@ func (c *Controller) UpdateKubernetesService(reconcile bool) error { return nil } -// CreateNamespaceIfNeeded will create a namespace if it doesn't already exist -func (c *Controller) CreateNamespaceIfNeeded(ns string) error { - if _, err := c.NamespaceClient.Namespaces().Get(ns, metav1.GetOptions{}); err == nil { - // the namespace already exists - return nil - } - newNs := &api.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: ns, - Namespace: "", - }, - } - _, err := c.NamespaceClient.Namespaces().Create(newNs) - if err != nil && errors.IsAlreadyExists(err) { - err = nil - } - return err -} - // createPortAndServiceSpec creates an array of service ports. // If the NodePort value is 0, just the servicePort is used, otherwise, a node port is exposed. func createPortAndServiceSpec(servicePort int, targetServicePort int, nodePort int, servicePortName string, extraServicePorts []api.ServicePort) ([]api.ServicePort, api.ServiceType) {