sigs.k8s.io/cluster-api@v1.7.1/controlplane/kubeadm/internal/controllers/status.go (about)

     1  /*
     2  Copyright 2020 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 controllers
    18  
    19  import (
    20  	"context"
    21  
    22  	"github.com/pkg/errors"
    23  
    24  	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
    25  	controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1beta1"
    26  	"sigs.k8s.io/cluster-api/controlplane/kubeadm/internal"
    27  	"sigs.k8s.io/cluster-api/util/collections"
    28  	"sigs.k8s.io/cluster-api/util/conditions"
    29  )
    30  
    31  // updateStatus is called after every reconcilitation loop in a defer statement to always make sure we have the
    32  // resource status subresourcs up-to-date.
    33  func (r *KubeadmControlPlaneReconciler) updateStatus(ctx context.Context, controlPlane *internal.ControlPlane) error {
    34  	selector := collections.ControlPlaneSelectorForCluster(controlPlane.Cluster.Name)
    35  	// Copy label selector to its status counterpart in string format.
    36  	// This is necessary for CRDs including scale subresources.
    37  	controlPlane.KCP.Status.Selector = selector.String()
    38  
    39  	controlPlane.KCP.Status.UpdatedReplicas = int32(len(controlPlane.UpToDateMachines()))
    40  
    41  	replicas := int32(len(controlPlane.Machines))
    42  	desiredReplicas := *controlPlane.KCP.Spec.Replicas
    43  
    44  	// set basic data that does not require interacting with the workload cluster
    45  	controlPlane.KCP.Status.Replicas = replicas
    46  	controlPlane.KCP.Status.ReadyReplicas = 0
    47  	controlPlane.KCP.Status.UnavailableReplicas = replicas
    48  
    49  	// Return early if the deletion timestamp is set, because we don't want to try to connect to the workload cluster
    50  	// and we don't want to report resize condition (because it is set to deleting into reconcile delete).
    51  	if !controlPlane.KCP.DeletionTimestamp.IsZero() {
    52  		return nil
    53  	}
    54  
    55  	machinesWithHealthyAPIServer := controlPlane.Machines.Filter(collections.HealthyAPIServer())
    56  	lowestVersion := machinesWithHealthyAPIServer.LowestVersion()
    57  	if lowestVersion != nil {
    58  		controlPlane.KCP.Status.Version = lowestVersion
    59  	}
    60  
    61  	switch {
    62  	// We are scaling up
    63  	case replicas < desiredReplicas:
    64  		conditions.MarkFalse(controlPlane.KCP, controlplanev1.ResizedCondition, controlplanev1.ScalingUpReason, clusterv1.ConditionSeverityWarning, "Scaling up control plane to %d replicas (actual %d)", desiredReplicas, replicas)
    65  	// We are scaling down
    66  	case replicas > desiredReplicas:
    67  		conditions.MarkFalse(controlPlane.KCP, controlplanev1.ResizedCondition, controlplanev1.ScalingDownReason, clusterv1.ConditionSeverityWarning, "Scaling down control plane to %d replicas (actual %d)", desiredReplicas, replicas)
    68  
    69  		// This means that there was no error in generating the desired number of machine objects
    70  		conditions.MarkTrue(controlPlane.KCP, controlplanev1.MachinesCreatedCondition)
    71  	default:
    72  		// make sure last resize operation is marked as completed.
    73  		// NOTE: we are checking the number of machines ready so we report resize completed only when the machines
    74  		// are actually provisioned (vs reporting completed immediately after the last machine object is created).
    75  		readyMachines := controlPlane.Machines.Filter(collections.IsReady())
    76  		if int32(len(readyMachines)) == replicas {
    77  			conditions.MarkTrue(controlPlane.KCP, controlplanev1.ResizedCondition)
    78  		}
    79  
    80  		// This means that there was no error in generating the desired number of machine objects
    81  		conditions.MarkTrue(controlPlane.KCP, controlplanev1.MachinesCreatedCondition)
    82  	}
    83  
    84  	workloadCluster, err := controlPlane.GetWorkloadCluster(ctx)
    85  	if err != nil {
    86  		return errors.Wrap(err, "failed to create remote cluster client")
    87  	}
    88  	status, err := workloadCluster.ClusterStatus(ctx)
    89  	if err != nil {
    90  		return err
    91  	}
    92  	controlPlane.KCP.Status.ReadyReplicas = status.ReadyNodes
    93  	controlPlane.KCP.Status.UnavailableReplicas = replicas - status.ReadyNodes
    94  
    95  	// This only gets initialized once and does not change if the kubeadm config map goes away.
    96  	if status.HasKubeadmConfig {
    97  		controlPlane.KCP.Status.Initialized = true
    98  		conditions.MarkTrue(controlPlane.KCP, controlplanev1.AvailableCondition)
    99  	}
   100  
   101  	if controlPlane.KCP.Status.ReadyReplicas > 0 {
   102  		controlPlane.KCP.Status.Ready = true
   103  	}
   104  
   105  	// Surface lastRemediation data in status.
   106  	// LastRemediation is the remediation currently in progress, in any, or the
   107  	// most recent of the remediation we are keeping track on machines.
   108  	var lastRemediation *RemediationData
   109  
   110  	if v, ok := controlPlane.KCP.Annotations[controlplanev1.RemediationInProgressAnnotation]; ok {
   111  		remediationData, err := RemediationDataFromAnnotation(v)
   112  		if err != nil {
   113  			return err
   114  		}
   115  		lastRemediation = remediationData
   116  	} else {
   117  		for _, m := range controlPlane.Machines.UnsortedList() {
   118  			if v, ok := m.Annotations[controlplanev1.RemediationForAnnotation]; ok {
   119  				remediationData, err := RemediationDataFromAnnotation(v)
   120  				if err != nil {
   121  					return err
   122  				}
   123  				if lastRemediation == nil || lastRemediation.Timestamp.Time.Before(remediationData.Timestamp.Time) {
   124  					lastRemediation = remediationData
   125  				}
   126  			}
   127  		}
   128  	}
   129  
   130  	if lastRemediation != nil {
   131  		controlPlane.KCP.Status.LastRemediation = lastRemediation.ToStatus()
   132  	}
   133  	return nil
   134  }