287 lines
6.6 KiB
Go
287 lines
6.6 KiB
Go
package node
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/rancher/norman/types/convert"
|
|
v1 "github.com/rancher/rancher/pkg/generated/norman/core/v1"
|
|
v3 "github.com/rancher/rancher/pkg/generated/norman/management.cattle.io/v3"
|
|
"github.com/rancher/rancher/pkg/settings"
|
|
rkeservices "github.com/rancher/rke/services"
|
|
rketypes "github.com/rancher/rke/types"
|
|
corev1 "k8s.io/api/core/v1"
|
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
|
"k8s.io/apimachinery/pkg/labels"
|
|
)
|
|
|
|
const (
|
|
externalAddressAnnotation = "rke.cattle.io/external-ip"
|
|
LabelNodeName = "management.cattle.io/nodename"
|
|
nodeStatusLabel = "cattle.rancher.io/node-status"
|
|
)
|
|
|
|
func GetNodeName(machine *v3.Node) string {
|
|
if machine.Status.NodeName != "" {
|
|
return machine.Status.NodeName
|
|
}
|
|
// to handle the case when machine was provisioned first
|
|
if machine.Status.NodeConfig != nil {
|
|
if machine.Status.NodeConfig.HostnameOverride != "" {
|
|
return machine.Status.NodeConfig.HostnameOverride
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func IgnoreNode(name string, labels map[string]string) bool {
|
|
ignoreName := settings.IgnoreNodeName.Get()
|
|
if name == ignoreName {
|
|
return true
|
|
}
|
|
|
|
if labels == nil {
|
|
return false
|
|
}
|
|
value, ok := labels[nodeStatusLabel]
|
|
return ok && value == "ignore"
|
|
}
|
|
|
|
// IsNodeForNode returns true if node names or addresses are equal
|
|
func IsNodeForNode(node *corev1.Node, machine *v3.Node) bool {
|
|
nodeName := GetNodeName(machine)
|
|
if nodeName == node.Name {
|
|
return true
|
|
}
|
|
|
|
machineAddress := ""
|
|
if machine.Status.NodeConfig != nil {
|
|
if machine.Status.NodeConfig.InternalAddress == "" {
|
|
// rke defaults internal address to address
|
|
machineAddress = machine.Status.NodeConfig.Address
|
|
} else {
|
|
machineAddress = machine.Status.NodeConfig.InternalAddress
|
|
}
|
|
}
|
|
|
|
if machineAddress == "" {
|
|
return false
|
|
}
|
|
|
|
if machineAddress == GetNodeInternalAddress(node) {
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func GetNodeInternalAddress(node *corev1.Node) string {
|
|
for _, address := range node.Status.Addresses {
|
|
if address.Type == corev1.NodeInternalIP {
|
|
return address.Address
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func GetEndpointV1NodeIP(node *v1.Node) string {
|
|
externalIP := ""
|
|
internalIP := ""
|
|
for _, ip := range node.Status.Addresses {
|
|
if ip.Type == "ExternalIP" && ip.Address != "" {
|
|
externalIP = ip.Address
|
|
break
|
|
} else if ip.Type == "InternalIP" && ip.Address != "" {
|
|
internalIP = ip.Address
|
|
}
|
|
}
|
|
if externalIP != "" {
|
|
return externalIP
|
|
}
|
|
if node.Annotations != nil {
|
|
externalIP = node.Annotations[externalAddressAnnotation]
|
|
if externalIP != "" {
|
|
return externalIP
|
|
}
|
|
}
|
|
return internalIP
|
|
}
|
|
|
|
func GetEndpointNodeIP(node *v3.Node) string {
|
|
externalIP := ""
|
|
internalIP := ""
|
|
for _, ip := range node.Status.InternalNodeStatus.Addresses {
|
|
if ip.Type == "ExternalIP" && ip.Address != "" {
|
|
externalIP = ip.Address
|
|
break
|
|
} else if ip.Type == "InternalIP" && ip.Address != "" {
|
|
internalIP = ip.Address
|
|
}
|
|
}
|
|
if externalIP != "" {
|
|
return externalIP
|
|
}
|
|
if node.Annotations != nil {
|
|
externalIP = node.Status.NodeAnnotations[externalAddressAnnotation]
|
|
if externalIP != "" {
|
|
return externalIP
|
|
}
|
|
}
|
|
return internalIP
|
|
}
|
|
|
|
func GetNodeByNodeName(nodes []*v3.Node, nodeName string) *v3.Node {
|
|
for _, m := range nodes {
|
|
if GetNodeName(m) == nodeName {
|
|
return m
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func GetNodeForMachine(machine *v3.Node, nodeLister v1.NodeLister) (*corev1.Node, error) {
|
|
nodeName := ""
|
|
if machine.Labels != nil {
|
|
nodeName = machine.Labels[LabelNodeName]
|
|
}
|
|
var nodes []*corev1.Node
|
|
var err error
|
|
if nodeName != "" {
|
|
var node *corev1.Node
|
|
node, err = nodeLister.Get("", nodeName)
|
|
if err != nil && !apierrors.IsNotFound(err) {
|
|
return nil, err
|
|
|
|
}
|
|
if node != nil {
|
|
nodes = append(nodes, node)
|
|
}
|
|
}
|
|
|
|
if len(nodes) == 0 {
|
|
nodes, err = nodeLister.List("", labels.NewSelector())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
for _, n := range nodes {
|
|
if IsNodeForNode(n, machine) {
|
|
return n, nil
|
|
}
|
|
}
|
|
|
|
return nil, nil
|
|
}
|
|
|
|
func GetMachineForNode(node *corev1.Node, clusterNamespace string, machineLister v3.NodeLister) (*v3.Node, error) {
|
|
labelsSearchSet := labels.Set{LabelNodeName: node.Name}
|
|
machines, err := machineLister.List(clusterNamespace, labels.SelectorFromSet(labelsSearchSet))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(machines) == 0 {
|
|
machines, err = machineLister.List(clusterNamespace, labels.NewSelector())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
for _, machine := range machines {
|
|
if IsNodeForNode(node, machine) {
|
|
return machine, nil
|
|
}
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func IsNodeReady(node *v1.Node) bool {
|
|
for _, cond := range node.Status.Conditions {
|
|
if cond.Type == corev1.NodeReady {
|
|
return cond.Status == corev1.ConditionTrue
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func IsMachineReady(machine *v3.Node) bool {
|
|
for _, cond := range machine.Status.InternalNodeStatus.Conditions {
|
|
if cond.Type == corev1.NodeReady {
|
|
return cond.Status == corev1.ConditionTrue
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func DrainBeforeDelete(node *v3.Node, cluster *v3.Cluster, nodePool *v3.NodePool) bool {
|
|
if node.Status.NodeConfig == nil {
|
|
return false
|
|
}
|
|
// never drain an etcd node, you will regret it
|
|
if IsEtcd(node.Status.NodeConfig) {
|
|
return false
|
|
}
|
|
|
|
// vsphere nodes with cloud providers need to be drained to unmount vmdk files as vsphere deletes them automatically
|
|
if nil != cluster.Spec.RancherKubernetesEngineConfig.CloudProvider.VsphereCloudProvider {
|
|
return true
|
|
}
|
|
|
|
if nodePool != nil && nodePool.Spec.DrainBeforeDelete {
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func IsEtcd(node *rketypes.RKEConfigNode) bool {
|
|
roles := node.Role
|
|
for _, role := range roles {
|
|
if role == rkeservices.ETCDRole {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func IsControlPlane(node *rketypes.RKEConfigNode) bool {
|
|
for _, role := range node.Role {
|
|
if role == rkeservices.ControlRole {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func IsWorker(node *rketypes.RKEConfigNode) bool {
|
|
roles := node.Role
|
|
for _, role := range roles {
|
|
if role == rkeservices.WorkerRole {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func IsNonWorker(node *rketypes.RKEConfigNode) bool {
|
|
return IsControlPlane(node) || IsEtcd(node)
|
|
}
|
|
|
|
func GetDrainFlags(node *v3.Node) []string {
|
|
input := node.Spec.NodeDrainInput
|
|
if input == nil {
|
|
return []string{}
|
|
}
|
|
|
|
var ignoreDaemonSets bool
|
|
if input.IgnoreDaemonSets == nil {
|
|
ignoreDaemonSets = true
|
|
} else {
|
|
ignoreDaemonSets = *input.IgnoreDaemonSets
|
|
}
|
|
return []string{
|
|
fmt.Sprintf("--delete-local-data=%v", input.DeleteLocalData),
|
|
fmt.Sprintf("--force=%v", input.Force),
|
|
fmt.Sprintf("--grace-period=%v", input.GracePeriod),
|
|
fmt.Sprintf("--ignore-daemonsets=%v", ignoreDaemonSets),
|
|
fmt.Sprintf("--timeout=%s", convert.ToString(input.Timeout)+"s")}
|
|
}
|