func validateDeleteStageStatus()

in pkg/controllers/updaterun/validation.go [257:320]


func validateDeleteStageStatus(
	updatingStageIndex, lastFinishedStageIndex, totalStages int,
	toBeDeletedBindings []*placementv1beta1.ClusterResourceBinding,
	updateRun *placementv1beta1.ClusterStagedUpdateRun,
) (int, error) {
	updateRunRef := klog.KObj(updateRun)
	existingDeleteStageStatus := updateRun.Status.DeletionStageStatus
	if existingDeleteStageStatus == nil {
		unexpectedErr := controller.NewUnexpectedBehaviorError(fmt.Errorf("the clusterStagedUpdateRun has nil deletionStageStatus"))
		klog.ErrorS(unexpectedErr, "Failed to find the deletionStageStatus in the clusterStagedUpdateRun", "clusterStagedUpdateRun", updateRunRef)
		return -1, fmt.Errorf("%w: %s", errStagedUpdatedAborted, unexpectedErr.Error())
	}

	// Validate whether toBeDeletedBindings are a subnet of the clusters in the delete stage status.
	// We only validate if it's a subnet because we will delete the bindings during the deleteStage execution so they can disappear.
	// We only need to check the existence, not the order, because clusters are always sorted by name in the delete stage.
	deletingClusterMap := make(map[string]struct{}, len(existingDeleteStageStatus.Clusters))
	for _, cluster := range existingDeleteStageStatus.Clusters {
		deletingClusterMap[cluster.ClusterName] = struct{}{}
	}
	for _, binding := range toBeDeletedBindings {
		if _, ok := deletingClusterMap[binding.Spec.TargetCluster]; !ok {
			unexpectedErr := controller.NewUnexpectedBehaviorError(fmt.Errorf("the cluster `%s` to be deleted is not in the delete stage", binding.Spec.TargetCluster))
			klog.ErrorS(unexpectedErr, "Detect new cluster to be unscheduled", "clusterResourceBinding", klog.KObj(binding), "clusterStagedUpdateRun", updateRunRef)
			return -1, fmt.Errorf("%w: %s", errStagedUpdatedAborted, unexpectedErr.Error())
		}
	}

	deleteStageFinishedCond := meta.FindStatusCondition(existingDeleteStageStatus.Conditions, string(placementv1beta1.StagedUpdateRunConditionSucceeded))
	deleteStageProgressingCond := meta.FindStatusCondition(existingDeleteStageStatus.Conditions, string(placementv1beta1.StagedUpdateRunConditionProgressing))
	// Check if there is any active updating stage
	if updatingStageIndex != -1 || lastFinishedStageIndex < totalStages-1 {
		// There are still stages updating before the delete stage, make sure the delete stage is not active/finished.
		if condition.IsConditionStatusTrue(deleteStageFinishedCond, updateRun.Generation) ||
			condition.IsConditionStatusFalse(deleteStageFinishedCond, updateRun.Generation) ||
			condition.IsConditionStatusTrue(deleteStageProgressingCond, updateRun.Generation) {
			unexpectedErr := controller.NewUnexpectedBehaviorError(fmt.Errorf("the delete stage is active, but there are still stages updating, updatingStageIndex: %d, lastFinishedStageIndex: %d", updatingStageIndex, lastFinishedStageIndex))
			klog.ErrorS(unexpectedErr, "the delete stage is active, but there are still stages updating", "clusterStagedUpdateRun", updateRunRef)
			return -1, fmt.Errorf("%w: %s", errStagedUpdatedAborted, unexpectedErr.Error())
		}

		// If no stage is updating, continue from the last finished stage.
		// We initialized lastFinishedStageIndex to -1, so that from the very beginning, we start from 0, the first stage.
		if updatingStageIndex == -1 {
			updatingStageIndex = lastFinishedStageIndex + 1
		}
		return updatingStageIndex, nil
	}

	klog.InfoS("All stages are finished, continue from the delete stage", "clusterStagedUpdateRun", updateRunRef)
	// Check if the delete stage has finished successfully.
	if condition.IsConditionStatusTrue(deleteStageFinishedCond, updateRun.Generation) {
		klog.InfoS("The delete stage has finished successfully, no more stages to update", "clusterStagedUpdateRun", updateRunRef)
		return -1, nil
	}
	// Check if the delete stage has failed.
	if condition.IsConditionStatusFalse(deleteStageFinishedCond, updateRun.Generation) {
		failedErr := fmt.Errorf("the delete stage has failed, err: %s", deleteStageFinishedCond.Message)
		klog.ErrorS(failedErr, "The delete stage has failed", "stageCond", deleteStageFinishedCond, "clusterStagedUpdateRun", updateRunRef)
		return -1, fmt.Errorf("%w: %s", errStagedUpdatedAborted, failedErr.Error())
	}
	// The delete stage is still updating or just to start.
	return totalStages, nil
}