From 1b93a6a10ee3daf53a3692bd9818a0a77e615d83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20K=C3=A4ldstr=C3=B6m?= Date: Wed, 7 Jun 2017 17:39:26 +0300 Subject: [PATCH] kubeadm: Make the creation of the RBAC rules phase idempotent --- cmd/kubeadm/app/phases/addons/BUILD | 1 + cmd/kubeadm/app/phases/addons/addons.go | 42 +++++++++++++++---- cmd/kubeadm/app/phases/addons/manifests.go | 3 ++ .../app/phases/apiconfig/clusterroles.go | 36 +++++++++++++--- 4 files changed, 68 insertions(+), 14 deletions(-) diff --git a/cmd/kubeadm/app/phases/addons/BUILD b/cmd/kubeadm/app/phases/addons/BUILD index b7b4e8ab689..d5df5c4b933 100644 --- a/cmd/kubeadm/app/phases/addons/BUILD +++ b/cmd/kubeadm/app/phases/addons/BUILD @@ -21,6 +21,7 @@ go_library( "//cmd/kubeadm/app/images:go_default_library", "//cmd/kubeadm/app/util:go_default_library", "//pkg/api: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/runtime:go_default_library", "//vendor/k8s.io/client-go/kubernetes:go_default_library", diff --git a/cmd/kubeadm/app/phases/addons/addons.go b/cmd/kubeadm/app/phases/addons/addons.go index 51a9ee577eb..3c3ab5f113c 100644 --- a/cmd/kubeadm/app/phases/addons/addons.go +++ b/cmd/kubeadm/app/phases/addons/addons.go @@ -19,9 +19,9 @@ package addons import ( "fmt" "net" - "runtime" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" kuberuntime "k8s.io/apimachinery/pkg/runtime" clientset "k8s.io/client-go/kubernetes" @@ -80,13 +80,13 @@ func CreateEssentialAddons(cfg *kubeadmapi.MasterConfiguration, client *clientse if err != nil { return err } - fmt.Println("[addons] Created essential addon: kube-proxy") + fmt.Println("[addons] Applied essential addon: kube-proxy") err = CreateKubeDNSAddon(dnsDeploymentBytes, dnsServiceBytes, client) if err != nil { return err } - fmt.Println("[addons] Created essential addon: kube-dns") + fmt.Println("[addons] Applied essential addon: kube-dns") return nil } @@ -97,7 +97,13 @@ func CreateKubeProxyAddon(configMapBytes, daemonSetbytes []byte, client *clients } if _, err := client.CoreV1().ConfigMaps(metav1.NamespaceSystem).Create(kubeproxyConfigMap); err != nil { - return fmt.Errorf("unable to create a new kube-proxy configmap: %v", err) + if !apierrors.IsAlreadyExists(err) { + return fmt.Errorf("unable to create a new kube-proxy configmap: %v", err) + } + + if _, err := client.CoreV1().ConfigMaps(metav1.NamespaceSystem).Update(kubeproxyConfigMap); err != nil { + return fmt.Errorf("unable to update the kube-proxy configmap: %v", err) + } } kubeproxyDaemonSet := &extensions.DaemonSet{} @@ -107,7 +113,13 @@ func CreateKubeProxyAddon(configMapBytes, daemonSetbytes []byte, client *clients kubeproxyDaemonSet.Spec.Template.Spec.Tolerations = []v1.Toleration{kubeadmconstants.MasterToleration} if _, err := client.ExtensionsV1beta1().DaemonSets(metav1.NamespaceSystem).Create(kubeproxyDaemonSet); err != nil { - return fmt.Errorf("unable to create a new kube-proxy daemonset: %v", err) + if !apierrors.IsAlreadyExists(err) { + return fmt.Errorf("unable to create a new kube-proxy daemonset: %v", err) + } + + if _, err := client.ExtensionsV1beta1().DaemonSets(metav1.NamespaceSystem).Update(kubeproxyDaemonSet); err != nil { + return fmt.Errorf("unable to update the kube-proxy daemonset: %v", err) + } } return nil } @@ -125,9 +137,14 @@ func CreateKubeDNSAddon(deploymentBytes, serviceBytes []byte, client *clientset. }, } - // TODO: All these .Create(foo) calls should instead be more like "kubectl apply -f" commands; they should not fail if there are existing objects with the same name if _, err := client.ExtensionsV1beta1().Deployments(metav1.NamespaceSystem).Create(kubednsDeployment); err != nil { - return fmt.Errorf("unable to create a new kube-dns deployment: %v", err) + if !apierrors.IsAlreadyExists(err) { + return fmt.Errorf("unable to create a new kube-dns deployment: %v", err) + } + + if _, err := client.ExtensionsV1beta1().Deployments(metav1.NamespaceSystem).Update(kubednsDeployment); err != nil { + return fmt.Errorf("unable to update the kube-dns deployment: %v", err) + } } kubednsService := &v1.Service{} @@ -136,7 +153,16 @@ func CreateKubeDNSAddon(deploymentBytes, serviceBytes []byte, client *clientset. } if _, err := client.CoreV1().Services(metav1.NamespaceSystem).Create(kubednsService); err != nil { - return fmt.Errorf("unable to create a new kube-dns service: %v", err) + // Ignore if the Service is invalid with this error message: + // Service "kube-dns" is invalid: spec.clusterIP: Invalid value: "10.96.0.10": provided IP is already allocated + + if !apierrors.IsAlreadyExists(err) && !apierrors.IsInvalid(err) { + return fmt.Errorf("unable to create a new kube-dns service: %v", err) + } + + if _, err := client.CoreV1().Services(metav1.NamespaceSystem).Update(kubednsService); err != nil { + return fmt.Errorf("unable to create/update the kube-dns service: %v", err) + } } return nil } diff --git a/cmd/kubeadm/app/phases/addons/manifests.go b/cmd/kubeadm/app/phases/addons/manifests.go index d2502525553..db441015bf3 100644 --- a/cmd/kubeadm/app/phases/addons/manifests.go +++ b/cmd/kubeadm/app/phases/addons/manifests.go @@ -271,6 +271,9 @@ metadata: kubernetes.io/name: "KubeDNS" name: kube-dns namespace: kube-system + # Without this resourceVersion value, an update of the Service between versions will yield: + # Service "kube-dns" is invalid: metadata.resourceVersion: Invalid value: "": must be specified for an update + resourceVersion: "0" spec: clusterIP: {{ .DNSIP }} ports: diff --git a/cmd/kubeadm/app/phases/apiconfig/clusterroles.go b/cmd/kubeadm/app/phases/apiconfig/clusterroles.go index f29faa2ee0e..625f7ae89e3 100644 --- a/cmd/kubeadm/app/phases/apiconfig/clusterroles.go +++ b/cmd/kubeadm/app/phases/apiconfig/clusterroles.go @@ -105,8 +105,14 @@ func createRoles(clientset *clientset.Clientset) error { }, } for _, role := range roles { - if _, err := clientset.RbacV1beta1().Roles(metav1.NamespacePublic).Create(&role); err != nil { - return err + if _, err := clientset.RbacV1beta1().Roles(role.ObjectMeta.Namespace).Create(&role); err != nil { + if !apierrors.IsAlreadyExists(err) { + return fmt.Errorf("unable to create RBAC role: %v", err) + } + + if _, err := clientset.RbacV1beta1().Roles(role.ObjectMeta.Namespace).Update(&role); err != nil { + return fmt.Errorf("unable to update RBAC role: %v", err) + } } } return nil @@ -134,8 +140,14 @@ func createRoleBindings(clientset *clientset.Clientset) error { } for _, roleBinding := range roleBindings { - if _, err := clientset.RbacV1beta1().RoleBindings(metav1.NamespacePublic).Create(&roleBinding); err != nil { - return err + if _, err := clientset.RbacV1beta1().RoleBindings(roleBinding.ObjectMeta.Namespace).Create(&roleBinding); err != nil { + if !apierrors.IsAlreadyExists(err) { + return fmt.Errorf("unable to create RBAC rolebinding: %v", err) + } + + if _, err := clientset.RbacV1beta1().RoleBindings(roleBinding.ObjectMeta.Namespace).Update(&roleBinding); err != nil { + return fmt.Errorf("unable to update RBAC rolebinding: %v", err) + } } } return nil @@ -155,7 +167,13 @@ func createClusterRoles(clientset *clientset.Clientset) error { for _, roleBinding := range clusterRoles { if _, err := clientset.RbacV1beta1().ClusterRoles().Create(&roleBinding); err != nil { - return err + if !apierrors.IsAlreadyExists(err) { + return fmt.Errorf("unable to create RBAC clusterrole: %v", err) + } + + if _, err := clientset.RbacV1beta1().ClusterRoles().Update(&roleBinding); err != nil { + return fmt.Errorf("unable to update RBAC clusterrole: %v", err) + } } } return nil @@ -216,7 +234,13 @@ func createClusterRoleBindings(clientset *clientset.Clientset) error { for _, clusterRoleBinding := range clusterRoleBindings { if _, err := clientset.RbacV1beta1().ClusterRoleBindings().Create(&clusterRoleBinding); err != nil { - return err + if !apierrors.IsAlreadyExists(err) { + return fmt.Errorf("unable to create RBAC clusterrolebinding: %v", err) + } + + if _, err := clientset.RbacV1beta1().ClusterRoleBindings().Update(&clusterRoleBinding); err != nil { + return fmt.Errorf("unable to update RBAC clusterrolebinding: %v", err) + } } } return nil