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  }