github.com/gocrane/crane@v0.11.0/pkg/utils/node.go (about)

     1  package utils
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"strconv"
     7  
     8  	"golang.org/x/net/context"
     9  	v1 "k8s.io/api/core/v1"
    10  	"k8s.io/apimachinery/pkg/api/errors"
    11  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    12  	clientset "k8s.io/client-go/kubernetes"
    13  	kubeclient "k8s.io/client-go/kubernetes"
    14  	corelisters "k8s.io/client-go/listers/core/v1"
    15  	"k8s.io/klog/v2"
    16  	kubeletconfigv1beta1 "k8s.io/kubelet/config/v1beta1"
    17  	kubeletconfiginternal "k8s.io/kubernetes/pkg/kubelet/apis/config"
    18  	kubeletscheme "k8s.io/kubernetes/pkg/kubelet/apis/config/scheme"
    19  
    20  	topologyapi "github.com/gocrane/api/topology/v1alpha1"
    21  )
    22  
    23  const defaultRetryTimes = 3
    24  
    25  // UpdateNodeConditionsStatues be used to update node condition with check whether it needs to update
    26  func UpdateNodeConditionsStatues(client clientset.Interface, nodeLister corelisters.NodeLister, nodeName string, condition v1.NodeCondition, retry *uint64) (*v1.Node, error) {
    27  
    28  	for i := uint64(0); i < GetUint64withDefault(retry, defaultRetryTimes); i++ {
    29  		node, err := nodeLister.Get(nodeName)
    30  		if err != nil {
    31  			return nil, err
    32  		}
    33  
    34  		updateNode, needUpdate := updateNodeConditions(node, condition)
    35  		if needUpdate {
    36  			klog.Warningf("Updating node condition %v", condition)
    37  			if updateNode, err = client.CoreV1().Nodes().UpdateStatus(context.Background(), updateNode, metav1.UpdateOptions{}); err != nil {
    38  				if errors.IsConflict(err) {
    39  					continue
    40  				} else {
    41  					return nil, err
    42  				}
    43  			}
    44  		}
    45  
    46  		return updateNode, nil
    47  	}
    48  
    49  	return nil, fmt.Errorf("update node failed, conflict too more times")
    50  }
    51  
    52  func updateNodeConditions(node *v1.Node, condition v1.NodeCondition) (*v1.Node, bool) {
    53  	updatedNode := node.DeepCopy()
    54  
    55  	// loop and found the condition type
    56  	for i, cond := range updatedNode.Status.Conditions {
    57  		if cond.Type == condition.Type {
    58  			if cond.Status == condition.Status {
    59  				return updatedNode, false
    60  			} else {
    61  				updatedNode.Status.Conditions[i] = condition
    62  				return updatedNode, true
    63  			}
    64  		}
    65  	}
    66  
    67  	// not found the condition, to add the condition to the end
    68  	updatedNode.Status.Conditions = append(updatedNode.Status.Conditions, condition)
    69  
    70  	return updatedNode, true
    71  }
    72  
    73  // UpdateNodeTaints be used to update node taints with check whether it needs to update
    74  func UpdateNodeTaints(client clientset.Interface, nodeLister corelisters.NodeLister, nodeName string, taint v1.Taint, retry *uint64) (*v1.Node, error) {
    75  
    76  	for i := uint64(0); i < GetUint64withDefault(retry, defaultRetryTimes); i++ {
    77  		node, err := nodeLister.Get(nodeName)
    78  		if err != nil {
    79  			return nil, err
    80  		}
    81  
    82  		updateNode, needUpdate := updateNodeTaints(node, taint)
    83  		if needUpdate {
    84  			if updateNode, err = client.CoreV1().Nodes().Update(context.Background(), updateNode, metav1.UpdateOptions{}); err != nil {
    85  				if errors.IsConflict(err) {
    86  					continue
    87  				} else {
    88  					return nil, err
    89  				}
    90  			}
    91  		}
    92  
    93  		return updateNode, nil
    94  	}
    95  
    96  	return nil, fmt.Errorf("failed to update node taints after %d retries", GetUint64withDefault(retry, defaultRetryTimes))
    97  }
    98  
    99  func updateNodeTaints(node *v1.Node, taint v1.Taint) (*v1.Node, bool) {
   100  	updatedNode := node.DeepCopy()
   101  
   102  	for i, t := range updatedNode.Spec.Taints {
   103  		if t.Key == taint.Key {
   104  			if (t.Value == taint.Value) && (t.Effect == taint.Effect) {
   105  				return updatedNode, false
   106  			} else {
   107  				updatedNode.Spec.Taints[i] = taint
   108  				return updatedNode, true
   109  			}
   110  		}
   111  	}
   112  
   113  	// not found the taint, to add the taint
   114  	updatedNode.Spec.Taints = append(updatedNode.Spec.Taints, taint)
   115  	return updatedNode, true
   116  }
   117  
   118  func RemoveNodeTaints(client clientset.Interface, nodeLister corelisters.NodeLister, nodeName string, taint v1.Taint, retry *uint64) (*v1.Node, error) {
   119  	for i := uint64(0); i < GetUint64withDefault(retry, defaultRetryTimes); i++ {
   120  		node, err := nodeLister.Get(nodeName)
   121  		if err != nil {
   122  			return nil, err
   123  		}
   124  
   125  		updateNode, needUpdate := removeNodeTaints(node, taint)
   126  		if needUpdate {
   127  			klog.V(4).Infof("Removing node taint %v", taint)
   128  			if updateNode, err = client.CoreV1().Nodes().Update(context.Background(), updateNode, metav1.UpdateOptions{}); err != nil {
   129  				if errors.IsConflict(err) {
   130  					continue
   131  				} else {
   132  					return nil, err
   133  				}
   134  			}
   135  		}
   136  
   137  		return updateNode, nil
   138  	}
   139  
   140  	return nil, fmt.Errorf("update node failed, conflict too more times")
   141  }
   142  
   143  func removeNodeTaints(node *v1.Node, taint v1.Taint) (*v1.Node, bool) {
   144  
   145  	updatedNode := node.DeepCopy()
   146  
   147  	var foundTaint = false
   148  	var taints []v1.Taint
   149  
   150  	for _, t := range updatedNode.Spec.Taints {
   151  		if t.Key == taint.Key && t.Effect == taint.Effect {
   152  			foundTaint = true
   153  		} else {
   154  			taints = append(taints, t)
   155  		}
   156  	}
   157  
   158  	// found the taint, remove it
   159  	if foundTaint {
   160  		updatedNode.Spec.Taints = taints
   161  		return updatedNode, true
   162  	}
   163  
   164  	return updatedNode, false
   165  }
   166  
   167  // IsNodeAwareOfTopology returns default topology awareness policy.
   168  func IsNodeAwareOfTopology(attr map[string]string) *bool {
   169  	if val, exist := attr[topologyapi.LabelNodeTopologyAwarenessKey]; exist {
   170  		if awareness, err := strconv.ParseBool(val); err == nil {
   171  			return &awareness
   172  		}
   173  	}
   174  	return nil
   175  }
   176  
   177  // BuildZoneName returns the canonical name of a NUMA zone from its ID.
   178  func BuildZoneName(nodeID int) string {
   179  	return fmt.Sprintf("node%d", nodeID)
   180  }
   181  
   182  func GetKubeletConfig(ctx context.Context, c kubeclient.Interface, hostname string) (*kubeletconfiginternal.KubeletConfiguration, error) {
   183  	result, err := c.CoreV1().RESTClient().Get().
   184  		Resource("nodes").
   185  		SubResource("proxy").
   186  		Name(hostname).
   187  		Suffix("configz").
   188  		Do(ctx).
   189  		Raw()
   190  	if err != nil {
   191  		return nil, err
   192  	}
   193  
   194  	// This hack because /configz reports the following structure:
   195  	// {"kubeletconfig": {the JSON representation of kubeletconfigv1beta1.KubeletConfiguration}}
   196  	type configzWrapper struct {
   197  		ComponentConfig kubeletconfigv1beta1.KubeletConfiguration `json:"kubeletconfig"`
   198  	}
   199  	configz := configzWrapper{}
   200  
   201  	if err = json.Unmarshal(result, &configz); err != nil {
   202  		return nil, fmt.Errorf("failed to unmarshal json for kubelet config: %v", err)
   203  	}
   204  
   205  	scheme, _, err := kubeletscheme.NewSchemeAndCodecs()
   206  	if err != nil {
   207  		return nil, err
   208  	}
   209  	cfg := kubeletconfiginternal.KubeletConfiguration{}
   210  	if err = scheme.Convert(&configz.ComponentConfig, &cfg, nil); err != nil {
   211  		return nil, err
   212  	}
   213  
   214  	return &cfg, nil
   215  }