k8s.io/kubernetes@v1.29.3/pkg/util/node/node.go (about) 1 /* 2 Copyright 2015 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 node 18 19 import ( 20 "context" 21 "fmt" 22 "net" 23 "time" 24 25 "k8s.io/klog/v2" 26 27 v1 "k8s.io/api/core/v1" 28 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 29 "k8s.io/apimachinery/pkg/util/wait" 30 clientset "k8s.io/client-go/kubernetes" 31 netutils "k8s.io/utils/net" 32 ) 33 34 const ( 35 // NodeUnreachablePodReason is the reason on a pod when its state cannot be confirmed as kubelet is unresponsive 36 // on the node it is (was) running. 37 NodeUnreachablePodReason = "NodeLost" 38 // NodeUnreachablePodMessage is the message on a pod when its state cannot be confirmed as kubelet is unresponsive 39 // on the node it is (was) running. 40 NodeUnreachablePodMessage = "Node %v which was running pod %v is unresponsive" 41 ) 42 43 // NoMatchError is a typed implementation of the error interface. It indicates a failure to get a matching Node. 44 type NoMatchError struct { 45 addresses []v1.NodeAddress 46 } 47 48 // Error is the implementation of the conventional interface for 49 // representing an error condition, with the nil value representing no error. 50 func (e *NoMatchError) Error() string { 51 return fmt.Sprintf("no preferred addresses found; known addresses: %v", e.addresses) 52 } 53 54 // GetPreferredNodeAddress returns the address of the provided node, using the provided preference order. 55 // If none of the preferred address types are found, an error is returned. 56 func GetPreferredNodeAddress(node *v1.Node, preferredAddressTypes []v1.NodeAddressType) (string, error) { 57 for _, addressType := range preferredAddressTypes { 58 for _, address := range node.Status.Addresses { 59 if address.Type == addressType { 60 return address.Address, nil 61 } 62 } 63 } 64 return "", &NoMatchError{addresses: node.Status.Addresses} 65 } 66 67 // GetNodeHostIPs returns the provided node's IP(s); either a single "primary IP" for the 68 // node in a single-stack cluster, or a dual-stack pair of IPs in a dual-stack cluster 69 // (for nodes that actually have dual-stack IPs). Among other things, the IPs returned 70 // from this function are used as the `.status.PodIPs` values for host-network pods on the 71 // node, and the first IP is used as the `.status.HostIP` for all pods on the node. 72 func GetNodeHostIPs(node *v1.Node) ([]net.IP, error) { 73 // Re-sort the addresses with InternalIPs first and then ExternalIPs 74 allIPs := make([]net.IP, 0, len(node.Status.Addresses)) 75 for _, addr := range node.Status.Addresses { 76 if addr.Type == v1.NodeInternalIP { 77 ip := netutils.ParseIPSloppy(addr.Address) 78 if ip != nil { 79 allIPs = append(allIPs, ip) 80 } 81 } 82 } 83 for _, addr := range node.Status.Addresses { 84 if addr.Type == v1.NodeExternalIP { 85 ip := netutils.ParseIPSloppy(addr.Address) 86 if ip != nil { 87 allIPs = append(allIPs, ip) 88 } 89 } 90 } 91 if len(allIPs) == 0 { 92 return nil, fmt.Errorf("host IP unknown; known addresses: %v", node.Status.Addresses) 93 } 94 95 nodeIPs := []net.IP{allIPs[0]} 96 for _, ip := range allIPs { 97 if netutils.IsIPv6(ip) != netutils.IsIPv6(nodeIPs[0]) { 98 nodeIPs = append(nodeIPs, ip) 99 break 100 } 101 } 102 103 return nodeIPs, nil 104 } 105 106 // GetNodeHostIP returns the provided node's "primary" IP; see GetNodeHostIPs for more details 107 func GetNodeHostIP(node *v1.Node) (net.IP, error) { 108 ips, err := GetNodeHostIPs(node) 109 if err != nil { 110 return nil, err 111 } 112 // GetNodeHostIPs always returns at least one IP if it didn't return an error 113 return ips[0], nil 114 } 115 116 // GetNodeIP returns an IP (as with GetNodeHostIP) for the node with the provided name. 117 // If required, it will wait for the node to be created. 118 func GetNodeIP(client clientset.Interface, name string) net.IP { 119 var nodeIP net.IP 120 backoff := wait.Backoff{ 121 Steps: 6, 122 Duration: 1 * time.Second, 123 Factor: 2.0, 124 Jitter: 0.2, 125 } 126 127 err := wait.ExponentialBackoff(backoff, func() (bool, error) { 128 node, err := client.CoreV1().Nodes().Get(context.TODO(), name, metav1.GetOptions{}) 129 if err != nil { 130 klog.Errorf("Failed to retrieve node info: %v", err) 131 return false, nil 132 } 133 nodeIP, err = GetNodeHostIP(node) 134 if err != nil { 135 klog.Errorf("Failed to retrieve node IP: %v", err) 136 return false, err 137 } 138 return true, nil 139 }) 140 if err == nil { 141 klog.Infof("Successfully retrieved node IP: %v", nodeIP) 142 } 143 return nodeIP 144 } 145 146 // IsNodeReady returns true if a node is ready; false otherwise. 147 func IsNodeReady(node *v1.Node) bool { 148 for _, c := range node.Status.Conditions { 149 if c.Type == v1.NodeReady { 150 return c.Status == v1.ConditionTrue 151 } 152 } 153 return false 154 }