github.com/SUSE/skuba@v1.4.17/pkg/skuba/actions/node/remove/remove.go (about) 1 /* 2 * Copyright (c) 2019 SUSE LLC. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18 package remove 19 20 import ( 21 "fmt" 22 "time" 23 24 "github.com/pkg/errors" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 clientset "k8s.io/client-go/kubernetes" 27 28 "github.com/SUSE/skuba/internal/pkg/skuba/cni" 29 "github.com/SUSE/skuba/internal/pkg/skuba/etcd" 30 "github.com/SUSE/skuba/internal/pkg/skuba/kubeadm" 31 "github.com/SUSE/skuba/internal/pkg/skuba/kubernetes" 32 "github.com/SUSE/skuba/internal/pkg/skuba/replica" 33 ) 34 35 // Remove removes a node from the cluster 36 func Remove(client clientset.Interface, target string, drainTimeout time.Duration) error { 37 node, err := client.CoreV1().Nodes().Get(target, metav1.GetOptions{}) 38 if err != nil { 39 return errors.Wrapf(err, "[remove-node] could not get node %s", target) 40 } 41 42 currentClusterVersion, err := kubeadm.GetCurrentClusterVersion(client) 43 if err != nil { 44 return errors.Wrap(err, "could not retrieve the current cluster version") 45 } 46 47 targetName := node.ObjectMeta.Name 48 49 var isControlPlane bool 50 if isControlPlane = kubernetes.IsControlPlane(node); isControlPlane { 51 cp, err := kubernetes.GetControlPlaneNodes(client) 52 if err != nil { 53 return errors.Wrapf(err, "could not retrieve master node list") 54 } 55 if len(cp.Items) == 1 { 56 return errors.New("could not remove last master of the cluster") 57 } 58 59 fmt.Printf("[remove-node] removing control plane node %s (drain timeout: %s)\n", targetName, drainTimeout.String()) 60 } else { 61 fmt.Printf("[remove-node] removing worker node %s (drain timeout: %s)\n", targetName, drainTimeout.String()) 62 } 63 64 replicaHelper, err := replica.NewHelper(client) 65 if err != nil { 66 return err 67 } 68 if err := replicaHelper.UpdateBeforeNodeDrains(); err != nil { 69 return errors.Wrap(err, "[remove-node] failed to update deployment replicas") 70 } 71 72 if err := kubernetes.DrainNode(client, node, drainTimeout); err != nil { 73 return errors.Wrap(err, "[remove-node] could not drain node") 74 } 75 76 if isControlPlane { 77 fmt.Printf("[remove-node] removing etcd from node %s\n", targetName) 78 if err := etcd.RemoveMember(client, node, currentClusterVersion); err != nil { 79 fmt.Printf("[remove-node] failed removing etcd from node %s, continuing with node removal...\n", targetName) 80 } 81 } 82 83 if err := kubernetes.DisarmKubelet(client, node, currentClusterVersion); err != nil { 84 fmt.Printf("[remove-node] failed disarming kubelet: %v; node could be down, continuing with node removal...\n", err) 85 } 86 87 if isControlPlane { 88 if err := kubeadm.RemoveAPIEndpointFromConfigMap(client, node); err != nil { 89 return errors.Wrapf(err, "[remove-node] could not remove the APIEndpoint for %s from the kubeadm-config configmap", targetName) 90 } 91 92 ciliumVersion := kubernetes.AddonVersionForClusterVersion(kubernetes.Cilium, currentClusterVersion).Version 93 if err := cni.CreateOrUpdateCiliumConfigMap(client, ciliumVersion); err != nil { 94 return errors.Wrap(err, "[remove-node] could not update cilium-config configmap") 95 } 96 } 97 98 if err := client.CoreV1().Nodes().Delete(targetName, &metav1.DeleteOptions{}); err != nil { 99 return errors.Wrapf(err, "[remove-node] could not remove node %s", targetName) 100 } 101 102 fmt.Printf("[remove-node] node %s successfully removed from the cluster\n", targetName) 103 104 return nil 105 }