sigs.k8s.io/cluster-api@v1.7.1/internal/topology/check/upgrade.go (about)

     1  /*
     2  Copyright 2024 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 check
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  
    23  	"github.com/pkg/errors"
    24  	corev1 "k8s.io/api/core/v1"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"sigs.k8s.io/controller-runtime/pkg/client"
    27  
    28  	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
    29  	expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1"
    30  )
    31  
    32  // IsMachineDeploymentUpgrading determines if the MachineDeployment is upgrading.
    33  // A machine deployment is considered upgrading if at least one of the Machines of this
    34  // MachineDeployment has a different version.
    35  func IsMachineDeploymentUpgrading(ctx context.Context, c client.Reader, md *clusterv1.MachineDeployment) (bool, error) {
    36  	// If the MachineDeployment has no version there is no definitive way to check if it is upgrading. Therefore, return false.
    37  	// Note: This case should not happen.
    38  	if md.Spec.Template.Spec.Version == nil {
    39  		return false, nil
    40  	}
    41  	selectorMap, err := metav1.LabelSelectorAsMap(&md.Spec.Selector)
    42  	if err != nil {
    43  		return false, errors.Wrapf(err, "failed to check if MachineDeployment %s is upgrading: failed to convert label selector to map", md.Name)
    44  	}
    45  	machines := &clusterv1.MachineList{}
    46  	if err := c.List(ctx, machines, client.InNamespace(md.Namespace), client.MatchingLabels(selectorMap)); err != nil {
    47  		return false, errors.Wrapf(err, "failed to check if MachineDeployment %s is upgrading: failed to list Machines", md.Name)
    48  	}
    49  	mdVersion := *md.Spec.Template.Spec.Version
    50  	// Check if the versions of the all the Machines match the MachineDeployment version.
    51  	for i := range machines.Items {
    52  		machine := machines.Items[i]
    53  		if machine.Spec.Version == nil {
    54  			return false, fmt.Errorf("failed to check if MachineDeployment %s is upgrading: Machine %s has no version", md.Name, machine.Name)
    55  		}
    56  		if *machine.Spec.Version != mdVersion {
    57  			return true, nil
    58  		}
    59  	}
    60  	return false, nil
    61  }
    62  
    63  // IsMachinePoolUpgrading determines if the MachinePool is upgrading.
    64  // A machine pool is considered upgrading if at least one of the Machines of this
    65  // MachinePool has a different version.
    66  func IsMachinePoolUpgrading(ctx context.Context, c client.Reader, mp *expv1.MachinePool) (bool, error) {
    67  	// If the MachinePool has no version there is no definitive way to check if it is upgrading. Therefore, return false.
    68  	// Note: This case should not happen.
    69  	if mp.Spec.Template.Spec.Version == nil {
    70  		return false, nil
    71  	}
    72  	mpVersion := *mp.Spec.Template.Spec.Version
    73  	// Check if the kubelet versions of the MachinePool noderefs match the MachinePool version.
    74  	for _, nodeRef := range mp.Status.NodeRefs {
    75  		node := &corev1.Node{}
    76  		if err := c.Get(ctx, client.ObjectKey{Name: nodeRef.Name}, node); err != nil {
    77  			return false, fmt.Errorf("failed to check if MachinePool %s is upgrading: failed to get Node %s", mp.Name, nodeRef.Name)
    78  		}
    79  		if mpVersion != node.Status.NodeInfo.KubeletVersion {
    80  			return true, nil
    81  		}
    82  	}
    83  	return false, nil
    84  }