in pkg/controllers/updaterun/validation.go [178:253]
func validateClusterUpdatingStatus(
curStage, updatingStageIndex, lastFinishedStageIndex int,
stageStatus *placementv1beta1.StageUpdatingStatus,
updateRun *placementv1beta1.ClusterStagedUpdateRun,
) (int, int, error) {
stageSucceedCond := meta.FindStatusCondition(stageStatus.Conditions, string(placementv1beta1.StageUpdatingConditionSucceeded))
stageStartedCond := meta.FindStatusCondition(stageStatus.Conditions, string(placementv1beta1.StageUpdatingConditionProgressing))
if condition.IsConditionStatusTrue(stageSucceedCond, updateRun.Generation) {
// The stage has finished.
if updatingStageIndex != -1 && curStage > updatingStageIndex {
// The finished stage is after the updating stage.
unexpectedErr := controller.NewUnexpectedBehaviorError(fmt.Errorf("the finished stage `%d` is after the updating stage `%d`", curStage, updatingStageIndex))
klog.ErrorS(unexpectedErr, "The finished stage is after the updating stage", "clusterStagedUpdateRun", klog.KObj(updateRun))
return -1, -1, fmt.Errorf("%w: %s", errStagedUpdatedAborted, unexpectedErr.Error())
}
// Make sure that all the clusters are updated.
for curCluster := range stageStatus.Clusters {
// Check if the cluster is still updating.
if !condition.IsConditionStatusTrue(meta.FindStatusCondition(
stageStatus.Clusters[curCluster].Conditions,
string(placementv1beta1.ClusterUpdatingConditionSucceeded)),
updateRun.Generation) {
// The clusters in the finished stage should all have finished too.
unexpectedErr := controller.NewUnexpectedBehaviorError(fmt.Errorf("cluster `%s` in the finished stage `%s` has not succeeded", stageStatus.Clusters[curCluster].ClusterName, stageStatus.StageName))
klog.ErrorS(unexpectedErr, "The cluster in a finished stage is still updating", "clusterStagedUpdateRun", klog.KObj(updateRun))
return -1, -1, fmt.Errorf("%w: %s", errStagedUpdatedAborted, unexpectedErr.Error())
}
}
if curStage != lastFinishedStageIndex+1 {
// The current finished stage is not right after the last finished stage.
unexpectedErr := controller.NewUnexpectedBehaviorError(fmt.Errorf("the finished stage `%s` is not right after the last finished stage with index `%d`", stageStatus.StageName, lastFinishedStageIndex))
klog.ErrorS(unexpectedErr, "There's not yet started stage before the finished stage", "clusterStagedUpdateRun", klog.KObj(updateRun))
return -1, -1, fmt.Errorf("%w: %s", errStagedUpdatedAborted, unexpectedErr.Error())
}
// Record the last finished stage so we can continue from the next stage if no stage is updating.
lastFinishedStageIndex = curStage
} else if condition.IsConditionStatusFalse(stageSucceedCond, updateRun.Generation) {
// The stage has failed.
failedErr := fmt.Errorf("the stage `%s` has failed, err: %s", stageStatus.StageName, stageSucceedCond.Message)
klog.ErrorS(failedErr, "The stage has failed", "stageCond", stageSucceedCond, "clusterStagedUpdateRun", klog.KObj(updateRun))
return -1, -1, fmt.Errorf("%w: %s", errStagedUpdatedAborted, failedErr.Error())
} else if stageStartedCond != nil {
// The stage is still updating.
if updatingStageIndex != -1 {
// There should be only one stage updating at a time.
unexpectedErr := controller.NewUnexpectedBehaviorError(fmt.Errorf("the stage `%s` is updating, but there is already a stage with index `%d` updating", stageStatus.StageName, updatingStageIndex))
klog.ErrorS(unexpectedErr, "Detected more than one updating stages", "clusterStagedUpdateRun", klog.KObj(updateRun))
return -1, -1, fmt.Errorf("%w: %s", errStagedUpdatedAborted, unexpectedErr.Error())
}
if curStage != lastFinishedStageIndex+1 {
// The current updating stage is not right after the last finished stage.
unexpectedErr := controller.NewUnexpectedBehaviorError(fmt.Errorf("the updating stage `%s` is not right after the last finished stage with index `%d`", stageStatus.StageName, lastFinishedStageIndex))
klog.ErrorS(unexpectedErr, "There's not yet started stage before the updating stage", "clusterStagedUpdateRun", klog.KObj(updateRun))
return -1, -1, fmt.Errorf("%w: %s", errStagedUpdatedAborted, unexpectedErr.Error())
}
updatingStageIndex = curStage
// Collect the updating clusters.
var updatingClusters []string
for j := range stageStatus.Clusters {
clusterStartedCond := meta.FindStatusCondition(stageStatus.Clusters[j].Conditions, string(placementv1beta1.ClusterUpdatingConditionStarted))
clusterFinishedCond := meta.FindStatusCondition(stageStatus.Clusters[j].Conditions, string(placementv1beta1.ClusterUpdatingConditionSucceeded))
if condition.IsConditionStatusTrue(clusterStartedCond, updateRun.Generation) &&
!(condition.IsConditionStatusTrue(clusterFinishedCond, updateRun.Generation) || condition.IsConditionStatusFalse(clusterFinishedCond, updateRun.Generation)) {
updatingClusters = append(updatingClusters, stageStatus.Clusters[j].ClusterName)
}
}
// We don't allow more than one clusters to be updating at the same time.
// TODO(wantjian): support multiple clusters updating at the same time.
if len(updatingClusters) > 1 {
unexpectedErr := controller.NewUnexpectedBehaviorError(fmt.Errorf("more than one cluster is updating in the stage `%s`, clusters: %v", stageStatus.StageName, updatingClusters))
klog.ErrorS(unexpectedErr, "Detected more than one updating clusters in the stage", "clusterStagedUpdateRun", klog.KObj(updateRun))
return -1, -1, fmt.Errorf("%w: %s", errStagedUpdatedAborted, unexpectedErr.Error())
}
}
return updatingStageIndex, lastFinishedStageIndex, nil
}