...

Source file src/k8s.io/kubectl/pkg/drain/cordon.go

Documentation: k8s.io/kubectl/pkg/drain

     1  /*
     2  Copyright 2019 The Kubernetes Authors.
     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  package drain
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  
    23  	corev1 "k8s.io/api/core/v1"
    24  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    25  	"k8s.io/apimachinery/pkg/runtime"
    26  	"k8s.io/apimachinery/pkg/runtime/schema"
    27  
    28  	"k8s.io/apimachinery/pkg/types"
    29  	"k8s.io/apimachinery/pkg/util/json"
    30  	"k8s.io/apimachinery/pkg/util/strategicpatch"
    31  	"k8s.io/client-go/kubernetes"
    32  )
    33  
    34  // CordonHelper wraps functionality to cordon/uncordon nodes
    35  type CordonHelper struct {
    36  	node    *corev1.Node
    37  	desired bool
    38  }
    39  
    40  // NewCordonHelper returns a new CordonHelper
    41  func NewCordonHelper(node *corev1.Node) *CordonHelper {
    42  	return &CordonHelper{
    43  		node: node,
    44  	}
    45  }
    46  
    47  // NewCordonHelperFromRuntimeObject returns a new CordonHelper, or an error if given object is not a
    48  // node or cannot be encoded as JSON
    49  func NewCordonHelperFromRuntimeObject(nodeObject runtime.Object, scheme *runtime.Scheme, gvk schema.GroupVersionKind) (*CordonHelper, error) {
    50  	nodeObject, err := scheme.ConvertToVersion(nodeObject, gvk.GroupVersion())
    51  	if err != nil {
    52  		return nil, err
    53  	}
    54  
    55  	node, ok := nodeObject.(*corev1.Node)
    56  	if !ok {
    57  		return nil, fmt.Errorf("unexpected type %T", nodeObject)
    58  	}
    59  
    60  	return NewCordonHelper(node), nil
    61  }
    62  
    63  // UpdateIfRequired returns true if c.node.Spec.Unschedulable isn't already set,
    64  // or false when no change is needed
    65  func (c *CordonHelper) UpdateIfRequired(desired bool) bool {
    66  	c.desired = desired
    67  
    68  	return c.node.Spec.Unschedulable != c.desired
    69  }
    70  
    71  // PatchOrReplace uses given clientset to update the node status, either by patching or
    72  // updating the given node object; it may return error if the object cannot be encoded as
    73  // JSON, or if either patch or update calls fail; it will also return a second error
    74  // whenever creating a patch has failed
    75  func (c *CordonHelper) PatchOrReplace(clientset kubernetes.Interface, serverDryRun bool) (error, error) {
    76  	return c.PatchOrReplaceWithContext(context.TODO(), clientset, serverDryRun)
    77  }
    78  
    79  // PatchOrReplaceWithContext provides the option to pass a custom context while updating
    80  // the node status
    81  func (c *CordonHelper) PatchOrReplaceWithContext(clientCtx context.Context, clientset kubernetes.Interface, serverDryRun bool) (error, error) {
    82  	client := clientset.CoreV1().Nodes()
    83  
    84  	oldData, err := json.Marshal(c.node)
    85  	if err != nil {
    86  		return err, nil
    87  	}
    88  
    89  	c.node.Spec.Unschedulable = c.desired
    90  
    91  	newData, err := json.Marshal(c.node)
    92  	if err != nil {
    93  		return err, nil
    94  	}
    95  
    96  	patchBytes, patchErr := strategicpatch.CreateTwoWayMergePatch(oldData, newData, c.node)
    97  	if patchErr == nil {
    98  		patchOptions := metav1.PatchOptions{}
    99  		if serverDryRun {
   100  			patchOptions.DryRun = []string{metav1.DryRunAll}
   101  		}
   102  		_, err = client.Patch(clientCtx, c.node.Name, types.StrategicMergePatchType, patchBytes, patchOptions)
   103  	} else {
   104  		updateOptions := metav1.UpdateOptions{}
   105  		if serverDryRun {
   106  			updateOptions.DryRun = []string{metav1.DryRunAll}
   107  		}
   108  		_, err = client.Update(clientCtx, c.node, updateOptions)
   109  	}
   110  	return err, patchErr
   111  }
   112  

View as plain text