From 965437ed84ba7ec9f86ff5ef3a600bae8e1ef537 Mon Sep 17 00:00:00 2001 From: Zhiying Lin <54013513+zhiying-lin@users.noreply.github.com> Date: Tue, 23 Apr 2024 11:57:26 +0800 Subject: [PATCH] feat: enabling the new condition (#768) * feat: enabling the new condition --------- Co-authored-by: Zhiying Lin Co-authored-by: Ryan Zhang --- apis/placement/v1beta1/binding_types.go | 8 - cmd/hubagent/workload/setup.go | 36 +- .../clusterresourceplacement/controller.go | 245 +- .../controller_integration_test.go | 175 +- .../controller_test.go | 113 +- .../placement_controllerv1alpha1.go | 3 - .../placement_status.go | 309 +- .../placement_status_test.go | 2962 +++-------------- .../clusterresourceplacement/suite_test.go | 17 +- .../overrider/clusterresource_controller.go | 3 - pkg/controllers/rollout/controller.go | 66 +- pkg/controllers/workgenerator/controller.go | 43 +- .../controller_integration_test.go | 36 +- .../workgenerator/controller_test.go | 15 +- pkg/utils/condition/condition.go | 58 +- test/e2e/actuals_test.go | 197 +- test/e2e/enveloped_object_placement_test.go | 16 +- test/e2e/placement_pickall_test.go | 26 +- test/e2e/placement_pickfixed_test.go | 6 +- test/e2e/placement_pickn_test.go | 14 +- .../e2e/placement_selecting_resources_test.go | 86 +- test/e2e/rollout_test.go | 6 +- test/e2e/scheduler_watchers_test.go | 129 +- test/e2e/setup.sh | 1 - test/e2e/taint_toleration_test.go | 16 +- test/e2e/utils_test.go | 48 +- 26 files changed, 1100 insertions(+), 3534 deletions(-) diff --git a/apis/placement/v1beta1/binding_types.go b/apis/placement/v1beta1/binding_types.go index a24c35ee2..8f7ce0607 100644 --- a/apis/placement/v1beta1/binding_types.go +++ b/apis/placement/v1beta1/binding_types.go @@ -124,14 +124,6 @@ const ( // - "Unknown" means it is unknown. ResourceBindingOverridden ResourceBindingConditionType = "Overridden" - // ResourceBindingBound indicates the bound condition of the given resources. - // Its condition status can be one of the following: - // - "True" means the corresponding work CR is created in the target cluster's namespace. - // - "False" means the corresponding work CR is not created yet. - // - "Unknown" means it is unknown. - // TODO, will be replaced by "WorkSynchronized" - ResourceBindingBound ResourceBindingConditionType = "Bound" - // ResourceBindingWorkSynchronized indicates the work synchronized condition of the given resources. // Its condition status can be one of the following: // - "True" means all corresponding works are created or updated in the target cluster's namespace. diff --git a/cmd/hubagent/workload/setup.go b/cmd/hubagent/workload/setup.go index edd8a78b3..94f246c98 100644 --- a/cmd/hubagent/workload/setup.go +++ b/cmd/hubagent/workload/setup.go @@ -23,10 +23,12 @@ import ( placementv1beta1 "go.goms.io/fleet/apis/placement/v1beta1" fleetv1alpha1 "go.goms.io/fleet/apis/v1alpha1" "go.goms.io/fleet/cmd/hubagent/options" + "go.goms.io/fleet/pkg/controllers/clusterresourcebindingwatcher" "go.goms.io/fleet/pkg/controllers/clusterresourceplacement" "go.goms.io/fleet/pkg/controllers/clusterresourceplacementwatcher" "go.goms.io/fleet/pkg/controllers/clusterschedulingpolicysnapshot" "go.goms.io/fleet/pkg/controllers/memberclusterplacement" + "go.goms.io/fleet/pkg/controllers/overrider" "go.goms.io/fleet/pkg/controllers/resourcechange" "go.goms.io/fleet/pkg/controllers/rollout" "go.goms.io/fleet/pkg/controllers/workgenerator" @@ -194,12 +196,21 @@ func SetupControllers(ctx context.Context, wg *sync.WaitGroup, mgr ctrl.Manager, return err } - klog.Info("Setting up clusterSchedulingPolicySnapshot controller") + klog.Info("Setting up clusterResourceBinding watcher") + if err := (&clusterresourcebindingwatcher.Reconciler{ + PlacementController: clusterResourcePlacementControllerV1Beta1, + Client: mgr.GetClient(), + }).SetupWithManager(mgr); err != nil { + klog.ErrorS(err, "Unable to set up the clusterResourceBinding watcher") + return err + } + + klog.Info("Setting up clusterSchedulingPolicySnapshot watcher") if err := (&clusterschedulingpolicysnapshot.Reconciler{ Client: mgr.GetClient(), PlacementController: clusterResourcePlacementControllerV1Beta1, }).SetupWithManager(mgr); err != nil { - klog.ErrorS(err, "Unable to set up the clusterResourcePlacement watcher") + klog.ErrorS(err, "Unable to set up the clusterSchedulingPolicySnapshot watcher") return err } @@ -276,6 +287,27 @@ func SetupControllers(ctx context.Context, wg *sync.WaitGroup, mgr ctrl.Manager, klog.ErrorS(err, "Unable to set up memberCluster watcher for scheduler") return err } + + // setup override related controllers + klog.Info("Setting up the clusterResourceOverride controller") + if err := (&overrider.ClusterResourceReconciler{ + Reconciler: overrider.Reconciler{ + Client: mgr.GetClient(), + }, + }).SetupWithManager(mgr); err != nil { + klog.ErrorS(err, "Unable to set up clusterResourceOverride controller") + return err + } + + klog.Info("Setting up the resourceOverride controller") + if err := (&overrider.ResourceReconciler{ + Reconciler: overrider.Reconciler{ + Client: mgr.GetClient(), + }, + }).SetupWithManager(mgr); err != nil { + klog.ErrorS(err, "Unable to set up resourceOverride controller") + return err + } } // Set up a runner that starts all the custom controllers we created above diff --git a/pkg/controllers/clusterresourceplacement/controller.go b/pkg/controllers/clusterresourceplacement/controller.go index 53accb9e0..0d95487fe 100644 --- a/pkg/controllers/clusterresourceplacement/controller.go +++ b/pkg/controllers/clusterresourceplacement/controller.go @@ -16,7 +16,6 @@ import ( corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" utilerrors "k8s.io/apimachinery/pkg/util/errors" @@ -203,54 +202,26 @@ func (r *Reconciler) handleUpdate(ctx context.Context, crp *fleetv1beta1.Cluster } klog.V(2).InfoS("Updated the clusterResourcePlacement status", "clusterResourcePlacement", crpKObj) - if !isCRPScheduled(oldCRP) && isCRPScheduled(crp) { - klog.V(2).InfoS("Placement has been scheduled", "clusterResourcePlacement", crpKObj, "generation", crp.Generation) - r.Recorder.Event(crp, corev1.EventTypeNormal, "PlacementScheduleSuccess", "Successfully scheduled the placement") - } - - if r.UseNewConditions { - // We skip checking the last resource condition (available) because it will be covered by checking isRolloutCompleted func. - for i := condition.RolloutStartedCondition; i < condition.TotalCondition-1; i++ { - oldCond := oldCRP.GetCondition(string(i.ClusterResourcePlacementConditionType())) - newCond := crp.GetCondition(string(i.ClusterResourcePlacementConditionType())) - if !condition.IsConditionStatusTrue(oldCond, oldCRP.Generation) && - condition.IsConditionStatusTrue(newCond, crp.Generation) { - klog.V(2).InfoS("Placement resource condition status has been changed to true", "clusterResourcePlacement", crpKObj, "generation", crp.Generation, "condition", i.ClusterResourcePlacementConditionType()) - r.Recorder.Event(crp, corev1.EventTypeNormal, i.EventReasonForTrue(), i.EventMessageForTrue()) - } + // We skip checking the last resource condition (available) because it will be covered by checking isRolloutCompleted func. + for i := condition.RolloutStartedCondition; i < condition.TotalCondition-1; i++ { + oldCond := oldCRP.GetCondition(string(i.ClusterResourcePlacementConditionType())) + newCond := crp.GetCondition(string(i.ClusterResourcePlacementConditionType())) + if !condition.IsConditionStatusTrue(oldCond, oldCRP.Generation) && + condition.IsConditionStatusTrue(newCond, crp.Generation) { + klog.V(2).InfoS("Placement resource condition status has been changed to true", "clusterResourcePlacement", crpKObj, "generation", crp.Generation, "condition", i.ClusterResourcePlacementConditionType()) + r.Recorder.Event(crp, corev1.EventTypeNormal, i.EventReasonForTrue(), i.EventMessageForTrue()) } - - // There is no need to check if the CRP is available or not. - // If the available condition is true, it means the rollout is completed. - if isRolloutCompleted(r.UseNewConditions, crp) { - if !isRolloutCompleted(r.UseNewConditions, oldCRP) { - klog.V(2).InfoS("Placement rollout has finished and resources are available", "clusterResourcePlacement", crpKObj, "generation", crp.Generation) - r.Recorder.Event(crp, corev1.EventTypeNormal, "PlacementRolloutCompleted", "Resources are available in the selected clusters") - } - // We don't need to requeue any request now by watching the binding changes - return ctrl.Result{}, nil - } - klog.V(2).InfoS("Placement rollout has not finished yet or resources are not available yet", "clusterResourcePlacement", crpKObj, "status", crp.Status, "generation", crp.Generation) - // We don't need to requeue any request now by watching the binding changes. - // Once the scheduler makes the decision, the binding will be changed by the scheduler at the same time. - return ctrl.Result{}, nil } - if !isCRPSynchronized(oldCRP) && isCRPSynchronized(crp) { - klog.V(2).InfoS("Placement has been synchronized", "clusterResourcePlacement", crpKObj, "generation", crp.Generation) - r.Recorder.Event(crp, corev1.EventTypeNormal, "PlacementSyncSuccess", "Successfully synchronized the placement") - } - - // There is no need to check if the CRP is applied or not. - // If the applied condition is true, it means the scheduling is done & works have been synchronized which means the rollout is completed. - if isRolloutCompleted(r.UseNewConditions, crp) { - if !isRolloutCompleted(r.UseNewConditions, oldCRP) { - klog.V(2).InfoS("Placement rollout has finished", "clusterResourcePlacement", crpKObj, "generation", crp.Generation) - r.Recorder.Event(crp, corev1.EventTypeNormal, "PlacementRolloutCompleted", "Resources have been applied to the selected clusters") + // There is no need to check if the CRP is available or not. + // If the available condition is true, it means the rollout is completed. + if isRolloutCompleted(crp) { + if !isRolloutCompleted(oldCRP) { + klog.V(2).InfoS("Placement rollout has finished and resources are available", "clusterResourcePlacement", crpKObj, "generation", crp.Generation) + r.Recorder.Event(crp, corev1.EventTypeNormal, "PlacementRolloutCompleted", "Resources are available in the selected clusters") } - // We keep a slow reconcile loop here to periodically update the work status in case the applied works change the status. - klog.V(2).InfoS("Placement rollout has finished and requeue the request in case of works change", "clusterResourcePlacement", crpKObj) - return ctrl.Result{RequeueAfter: 5 * time.Minute}, nil + // We don't need to requeue any request now by watching the binding changes + return ctrl.Result{}, nil } if !isClusterScheduled { @@ -270,9 +241,10 @@ func (r *Reconciler) handleUpdate(ctx context.Context, crp *fleetv1beta1.Cluster } klog.V(2).InfoS("Placement rollout has not finished yet and requeue the request", "clusterResourcePlacement", crpKObj, "status", crp.Status, "generation", crp.Generation) - // we need to requeue the request to update the status of the resources. - // TODO: adjust the requeue time based on the rollout status. - return ctrl.Result{RequeueAfter: 5 * time.Second}, nil + // we need to requeue the request to update the status of the resources eg, failedManifests. + // The binding status won't be changed. + // TODO: once we move to populate the failedManifests from the binding, no need to requeue. + return ctrl.Result{RequeueAfter: 1 * time.Minute}, nil } func (r *Reconciler) getOrCreateClusterSchedulingPolicySnapshot(ctx context.Context, crp *fleetv1beta1.ClusterResourcePlacement, revisionHistoryLimit int) (*fleetv1beta1.ClusterSchedulingPolicySnapshot, error) { @@ -935,25 +907,6 @@ func (r *Reconciler) setPlacementStatus(ctx context.Context, crp *fleetv1beta1.C if scheduledCondition.Status == metav1.ConditionUnknown { // For the new conditions, we no longer populate the remaining otherwise it's too complicated and the default condition // will be unknown. - if !r.UseNewConditions { - conditions := []metav1.Condition{ - { - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ClusterResourcePlacementSynchronizedConditionType), - Reason: SynchronizePendingReason, - Message: "Scheduling has not completed", - ObservedGeneration: crp.Generation, - }, - { - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ClusterResourcePlacementAppliedConditionType), - Reason: ApplyPendingReason, - Message: "Scheduling has not completed", - ObservedGeneration: crp.Generation, - }, - } - crp.SetConditions(conditions...) - } // skip populating detailed resourcePlacementStatus & work related conditions // reset other status fields // TODO: need to track whether we have deleted the resources for the last decisions. @@ -963,11 +916,7 @@ func (r *Reconciler) setPlacementStatus(ctx context.Context, crp *fleetv1beta1.C return false, nil } - if r.UseNewConditions { - return r.setResourceConditions(ctx, crp, latestSchedulingPolicySnapshot, latestResourceSnapshot) - } - - return r.setResourcePlacementStatusAndResourceConditions(ctx, crp, latestSchedulingPolicySnapshot, latestResourceSnapshot) + return r.setResourceConditions(ctx, crp, latestSchedulingPolicySnapshot, latestResourceSnapshot) } func buildScheduledCondition(crp *fleetv1beta1.ClusterResourcePlacement, latestSchedulingPolicySnapshot *fleetv1beta1.ClusterSchedulingPolicySnapshot) metav1.Condition { @@ -1023,161 +972,19 @@ func buildResourcePlacementStatusMap(crp *fleetv1beta1.ClusterResourcePlacement) return m } -func (r *Reconciler) buildClusterResourceBindingMap(ctx context.Context, crp *fleetv1beta1.ClusterResourcePlacement, latestSchedulingPolicySnapshot *fleetv1beta1.ClusterSchedulingPolicySnapshot, latestResourceSnapshot *fleetv1beta1.ClusterResourceSnapshot) (map[string]*fleetv1beta1.ClusterResourceBinding, error) { - // List all bindings derived from the CRP. - bindingList := &fleetv1beta1.ClusterResourceBindingList{} - listOptions := client.MatchingLabels{ - fleetv1beta1.CRPTrackingLabel: crp.Name, - } - crpKObj := klog.KObj(crp) - if err := r.Client.List(ctx, bindingList, listOptions); err != nil { - klog.ErrorS(err, "Failed to list all bindings", "clusterResourcePlacement", crpKObj) - return nil, controller.NewAPIServerError(true, err) - } - - res := make(map[string]*fleetv1beta1.ClusterResourceBinding, len(bindingList.Items)) - bindings := bindingList.Items - // filter out the latest resource bindings - for i := range bindings { - if !bindings[i].DeletionTimestamp.IsZero() { - klog.V(2).InfoS("Filtering out the deleting clusterResourceBinding", "clusterResourceBinding", klog.KObj(&bindings[i])) - continue - } - - if len(bindings[i].Spec.TargetCluster) == 0 { - err := fmt.Errorf("targetCluster is empty on clusterResourceBinding %s", bindings[i].Name) - klog.ErrorS(controller.NewUnexpectedBehaviorError(err), "Found an invalid clusterResourceBinding and skipping it when building placement status", "clusterResourceBinding", klog.KObj(&bindings[i]), "clusterResourcePlacement", crpKObj) - continue - } - if bindings[i].Spec.ResourceSnapshotName != latestResourceSnapshot.Name || - bindings[i].Spec.SchedulingPolicySnapshotName != latestSchedulingPolicySnapshot.Name { - continue - } - res[bindings[i].Spec.TargetCluster] = &bindings[i] - } - return res, nil -} - -// setResourcePlacementStatusAndResourceConditions returns whether the scheduler selects any cluster or not. -func (r *Reconciler) setResourcePlacementStatusAndResourceConditions(ctx context.Context, crp *fleetv1beta1.ClusterResourcePlacement, - latestSchedulingPolicySnapshot *fleetv1beta1.ClusterSchedulingPolicySnapshot, latestResourceSnapshot *fleetv1beta1.ClusterResourceSnapshot) (bool, error) { - placementStatuses := make([]fleetv1beta1.ResourcePlacementStatus, 0, len(latestSchedulingPolicySnapshot.Status.ClusterDecisions)) - decisions := latestSchedulingPolicySnapshot.Status.ClusterDecisions - selected, unselected := classifyClusterDecisions(decisions) - - // In the pickN case, if the placement cannot be satisfied. For example, pickN deployment requires 5 clusters and - // scheduler schedules the resources on 3 clusters. We'll populate why the other two cannot be scheduled. - // Here it is calculating how many unscheduled resources there are. - unscheduledClusterCount := 0 - if crp.Spec.Policy != nil { - if crp.Spec.Policy.PlacementType == fleetv1beta1.PickNPlacementType && crp.Spec.Policy.NumberOfClusters != nil { - unscheduledClusterCount = int(*crp.Spec.Policy.NumberOfClusters) - len(selected) - } - if crp.Spec.Policy.PlacementType == fleetv1beta1.PickFixedPlacementType { - unscheduledClusterCount = len(crp.Spec.Policy.ClusterNames) - len(selected) - } - } - - // Used to record each selected cluster placement sync status - syncPendingCount := 0 - syncSucceededCount := 0 - - // Used to record each selected cluster placement applied status. - appliedPendingCount := 0 - appliedFailedCount := 0 - appliedSucceededCount := 0 - oldResourcePlacementStatusMap := buildResourcePlacementStatusMap(crp) - resourceBindingMap, err := r.buildClusterResourceBindingMap(ctx, crp, latestSchedulingPolicySnapshot, latestResourceSnapshot) - if err != nil { - return false, err - } - - for _, c := range selected { - var rp fleetv1beta1.ResourcePlacementStatus - scheduledCondition := metav1.Condition{ - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourceScheduledConditionType), - Reason: ResourceScheduleSucceededReason, - Message: fmt.Sprintf(resourcePlacementConditionScheduleSucceededMessageFormat, c.ClusterName, c.Reason), - ObservedGeneration: crp.Generation, - } - rp.ClusterName = c.ClusterName - if c.ClusterScore != nil { - scheduledCondition.Message = fmt.Sprintf(resourcePlacementConditionScheduleSucceededWithScoreMessageFormat, c.ClusterName, *c.ClusterScore.AffinityScore, *c.ClusterScore.TopologySpreadScore, c.Reason) - } - oldConditions, ok := oldResourcePlacementStatusMap[c.ClusterName] - if ok { - // update the lastTransitionTime considering the existing condition status instead of overwriting - rp.Conditions = oldConditions - } - meta.SetStatusCondition(&rp.Conditions, scheduledCondition) - syncCondition, appliedCondition, err := r.setWorkStatusForResourcePlacementStatus(ctx, crp, latestResourceSnapshot, resourceBindingMap[c.ClusterName], &rp) - if err != nil { - return false, err - } - if syncCondition == nil || syncCondition.Status != metav1.ConditionTrue { - syncPendingCount++ - } else { - syncSucceededCount++ - } - if appliedCondition == nil || appliedCondition.Status == metav1.ConditionUnknown { - appliedPendingCount++ - } else if appliedCondition.Status == metav1.ConditionFalse { - appliedFailedCount++ - } else { - appliedSucceededCount++ - } - placementStatuses = append(placementStatuses, rp) - } - isClusterScheduled := len(placementStatuses) > 0 - - for i := 0; i < unscheduledClusterCount && i < len(unselected); i++ { - // TODO: we could improve the message by summarizing the failure reasons from all of the unselected clusters. - // For now, it starts from adding some sample failures of unselected clusters. - var rp fleetv1beta1.ResourcePlacementStatus - scheduledCondition := metav1.Condition{ - Status: metav1.ConditionFalse, - Type: string(fleetv1beta1.ResourceScheduledConditionType), - Reason: ResourceScheduleFailedReason, - Message: fmt.Sprintf(resourcePlacementConditionScheduleFailedMessageFormat, unselected[i].ClusterName, unselected[i].Reason), - ObservedGeneration: crp.Generation, - } - if unselected[i].ClusterScore != nil { - scheduledCondition.Message = fmt.Sprintf(resourcePlacementConditionScheduleFailedWithScoreMessageFormat, unselected[i].ClusterName, unselected[i].ClusterScore, unselected[i].Reason) - } - meta.SetStatusCondition(&rp.Conditions, scheduledCondition) - placementStatuses = append(placementStatuses, rp) - } - crp.Status.PlacementStatuses = placementStatuses - crp.SetConditions(buildClusterResourcePlacementSyncCondition(crp, syncPendingCount, syncSucceededCount)) - crp.SetConditions(buildClusterResourcePlacementApplyCondition(crp, syncPendingCount == 0, appliedPendingCount, appliedSucceededCount, appliedFailedCount)) - return isClusterScheduled, nil -} - -func isRolloutCompleted(useNewConditions bool, crp *fleetv1beta1.ClusterResourcePlacement) bool { +func isRolloutCompleted(crp *fleetv1beta1.ClusterResourcePlacement) bool { if !isCRPScheduled(crp) { return false } - if useNewConditions { - for i := condition.RolloutStartedCondition; i < condition.TotalCondition; i++ { - if !condition.IsConditionStatusTrue(crp.GetCondition(string(i.ClusterResourcePlacementConditionType())), crp.Generation) { - return false - } + for i := condition.RolloutStartedCondition; i < condition.TotalCondition; i++ { + if !condition.IsConditionStatusTrue(crp.GetCondition(string(i.ClusterResourcePlacementConditionType())), crp.Generation) { + return false } - return true } - return isCRPSynchronized(crp) && isCRPApplied(crp) + return true } func isCRPScheduled(crp *fleetv1beta1.ClusterResourcePlacement) bool { return condition.IsConditionStatusTrue(crp.GetCondition(string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType)), crp.Generation) } - -func isCRPSynchronized(crp *fleetv1beta1.ClusterResourcePlacement) bool { - return condition.IsConditionStatusTrue(crp.GetCondition(string(fleetv1beta1.ClusterResourcePlacementSynchronizedConditionType)), crp.Generation) -} - -func isCRPApplied(crp *fleetv1beta1.ClusterResourcePlacement) bool { - return condition.IsConditionStatusTrue(crp.GetCondition(string(fleetv1beta1.ClusterResourcePlacementAppliedConditionType)), crp.Generation) -} diff --git a/pkg/controllers/clusterresourceplacement/controller_integration_test.go b/pkg/controllers/clusterresourceplacement/controller_integration_test.go index 904fddd05..3879a2dbd 100644 --- a/pkg/controllers/clusterresourceplacement/controller_integration_test.go +++ b/pkg/controllers/clusterresourceplacement/controller_integration_test.go @@ -23,6 +23,7 @@ import ( placementv1beta1 "go.goms.io/fleet/apis/placement/v1beta1" "go.goms.io/fleet/pkg/utils" + "go.goms.io/fleet/pkg/utils/condition" "go.goms.io/fleet/pkg/utils/resource" ) @@ -30,9 +31,8 @@ const ( member1Name = "member-1" member2Name = "member-2" - eventuallyTimeout = time.Minute * 2 - consistentlyDuration = time.Second * 10 - interval = time.Millisecond * 250 + eventuallyTimeout = time.Second * 10 + interval = time.Millisecond * 250 ) var ( @@ -154,7 +154,7 @@ func retrieveAndValidateCRPDeletion(crp *placementv1beta1.ClusterResourcePlaceme }, eventuallyTimeout, interval).Should(BeTrue(), "Get() clusterResourcePlacement, want not found") } -func createClusterResourceBinding(cluster string, policySnapshot *placementv1beta1.ClusterSchedulingPolicySnapshot, resourceSnapshot *placementv1beta1.ClusterResourceSnapshot) { +func createOverriddenClusterResourceBinding(cluster string, policySnapshot *placementv1beta1.ClusterSchedulingPolicySnapshot, resourceSnapshot *placementv1beta1.ClusterResourceSnapshot) *placementv1beta1.ClusterResourceBinding { binding := &placementv1beta1.ClusterResourceBinding{ ObjectMeta: metav1.ObjectMeta{ Name: "binding-" + cluster, @@ -170,36 +170,34 @@ func createClusterResourceBinding(cluster string, policySnapshot *placementv1bet }, } Expect(k8sClient.Create(ctx, binding)).Should(Succeed(), "Failed to create clusterResourceBinding") - condition := metav1.Condition{ + cond := metav1.Condition{ Status: metav1.ConditionTrue, - Type: string(placementv1beta1.ResourceBindingBound), - Reason: "resourceBindingTrue", + Type: string(placementv1beta1.ResourceBindingRolloutStarted), + Reason: condition.RolloutStartedReason, ObservedGeneration: binding.Generation, } - meta.SetStatusCondition(&binding.Status.Conditions, condition) + meta.SetStatusCondition(&binding.Status.Conditions, cond) + cond = metav1.Condition{ + Status: metav1.ConditionTrue, + Type: string(placementv1beta1.ResourceBindingOverridden), + Reason: condition.OverriddenSucceededReason, + ObservedGeneration: binding.Generation, + } + meta.SetStatusCondition(&binding.Status.Conditions, cond) Expect(k8sClient.Status().Update(ctx, binding)).Should(Succeed(), "Failed to update the binding status") + return binding } -func createApplySucceededWork(resourceSnapshot *placementv1beta1.ClusterResourceSnapshot, namespace string) { - work := &placementv1beta1.Work{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, - Name: "work-1", - Labels: map[string]string{ - placementv1beta1.CRPTrackingLabel: resourceSnapshot.Labels[placementv1beta1.CRPTrackingLabel], - placementv1beta1.ParentResourceSnapshotIndexLabel: resourceSnapshot.Labels[placementv1beta1.ResourceIndexLabel], - }, - }, - } - Expect(k8sClient.Create(ctx, work)).Should(Succeed(), "Failed to create work") - condition := metav1.Condition{ - Type: placementv1beta1.WorkConditionTypeApplied, +func createSynchronizedClusterResourceBinding(cluster string, policySnapshot *placementv1beta1.ClusterSchedulingPolicySnapshot, resourceSnapshot *placementv1beta1.ClusterResourceSnapshot) { + binding := createOverriddenClusterResourceBinding(cluster, policySnapshot, resourceSnapshot) + cond := metav1.Condition{ Status: metav1.ConditionTrue, - ObservedGeneration: work.Generation, - Reason: "Success", + Type: string(placementv1beta1.ResourceBindingWorkSynchronized), + Reason: condition.WorkSynchronizedReason, + ObservedGeneration: binding.Generation, } - meta.SetStatusCondition(&work.Status.Conditions, condition) - Expect(k8sClient.Status().Update(ctx, work)).Should(Succeed(), "Failed to update work status as applied") + meta.SetStatusCondition(&binding.Status.Conditions, cond) + Expect(k8sClient.Status().Update(ctx, binding)).Should(Succeed(), "Failed to update the binding status") } var _ = Describe("Test ClusterResourcePlacement Controller", func() { @@ -298,21 +296,11 @@ var _ = Describe("Test ClusterResourcePlacement Controller", func() { Status: placementv1beta1.ClusterResourcePlacementStatus{ ObservedResourceIndex: "0", Conditions: []metav1.Condition{ - { - Status: metav1.ConditionUnknown, - Type: string(placementv1beta1.ClusterResourcePlacementAppliedConditionType), - Reason: ApplyPendingReason, - }, { Status: metav1.ConditionUnknown, Type: string(placementv1beta1.ClusterResourcePlacementScheduledConditionType), Reason: SchedulingUnknownReason, }, - { - Status: metav1.ConditionUnknown, - Type: string(placementv1beta1.ClusterResourcePlacementSynchronizedConditionType), - Reason: SynchronizePendingReason, - }, }, }, } @@ -337,7 +325,7 @@ var _ = Describe("Test ClusterResourcePlacement Controller", func() { gotPolicySnapshot.Status.ObservedCRPGeneration = gotCRP.Generation Expect(k8sClient.Status().Update(ctx, gotPolicySnapshot)).Should(Succeed(), "Failed to update the policy snapshot status") - By("By validating the CRP status") + By("By validating the CRP status has only scheduling condition") wantCRP := &placementv1beta1.ClusterResourcePlacement{ ObjectMeta: metav1.ObjectMeta{ Name: testName, @@ -347,21 +335,11 @@ var _ = Describe("Test ClusterResourcePlacement Controller", func() { Status: placementv1beta1.ClusterResourcePlacementStatus{ ObservedResourceIndex: "0", Conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: string(placementv1beta1.ClusterResourcePlacementAppliedConditionType), - Reason: ApplySucceededReason, - }, { Status: metav1.ConditionTrue, Type: string(placementv1beta1.ClusterResourcePlacementScheduledConditionType), Reason: ResourceScheduleSucceededReason, }, - { - Status: metav1.ConditionTrue, - Type: string(placementv1beta1.ClusterResourcePlacementSynchronizedConditionType), - Reason: SynchronizeSucceededReason, - }, }, }, } @@ -393,10 +371,7 @@ var _ = Describe("Test ClusterResourcePlacement Controller", func() { Expect(k8sClient.Status().Update(ctx, gotPolicySnapshot)).Should(Succeed(), "Failed to update the policy snapshot status") By("By creating clusterResourceBinding on member-1") - createClusterResourceBinding(member1Name, gotPolicySnapshot, gotResourceSnapshot) - - By("By creating appliedSuccess works on member-1") - createApplySucceededWork(gotResourceSnapshot, member1Namespace) + createOverriddenClusterResourceBinding(member1Name, gotPolicySnapshot, gotResourceSnapshot) By("By validating the CRP status") wantCRP := &placementv1beta1.ClusterResourcePlacement{ @@ -408,20 +383,15 @@ var _ = Describe("Test ClusterResourcePlacement Controller", func() { Status: placementv1beta1.ClusterResourcePlacementStatus{ ObservedResourceIndex: "0", Conditions: []metav1.Condition{ - { - Status: metav1.ConditionUnknown, - Type: string(placementv1beta1.ClusterResourcePlacementAppliedConditionType), - Reason: ApplyPendingReason, - }, { Status: metav1.ConditionTrue, Type: string(placementv1beta1.ClusterResourcePlacementScheduledConditionType), Reason: ResourceScheduleSucceededReason, }, { - Status: metav1.ConditionFalse, - Type: string(placementv1beta1.ClusterResourcePlacementSynchronizedConditionType), - Reason: SynchronizePendingReason, + Status: metav1.ConditionUnknown, + Type: string(placementv1beta1.ClusterResourcePlacementRolloutStartedConditionType), + Reason: condition.RolloutStartedUnknownReason, }, }, PlacementStatuses: []placementv1beta1.ResourcePlacementStatus{ @@ -430,38 +400,38 @@ var _ = Describe("Test ClusterResourcePlacement Controller", func() { Conditions: []metav1.Condition{ { Status: metav1.ConditionTrue, - Type: string(placementv1beta1.ResourcesAppliedConditionType), - Reason: ResourceApplySucceededReason, + Type: string(placementv1beta1.ResourceScheduledConditionType), + Reason: condition.ScheduleSucceededReason, }, { Status: metav1.ConditionTrue, - Type: string(placementv1beta1.ResourceScheduledConditionType), - Reason: ResourceScheduleSucceededReason, + Type: string(placementv1beta1.ResourceRolloutStartedConditionType), + Reason: condition.RolloutStartedReason, }, { Status: metav1.ConditionTrue, + Type: string(placementv1beta1.ResourceOverriddenConditionType), + Reason: condition.OverriddenSucceededReason, + }, + { + Status: metav1.ConditionUnknown, Type: string(placementv1beta1.ResourceWorkSynchronizedConditionType), - Reason: WorkSynchronizeSucceededReason, + Reason: condition.WorkSynchronizedUnknownReason, }, }, }, { ClusterName: member2Name, Conditions: []metav1.Condition{ - { - Status: metav1.ConditionUnknown, - Type: string(placementv1beta1.ResourcesAppliedConditionType), - Reason: ResourceApplyPendingReason, - }, { Status: metav1.ConditionTrue, Type: string(placementv1beta1.ResourceScheduledConditionType), - Reason: ResourceScheduleSucceededReason, + Reason: condition.ScheduleSucceededReason, }, { - Status: metav1.ConditionFalse, - Type: string(placementv1beta1.ResourceWorkSynchronizedConditionType), - Reason: WorkSynchronizePendingReason, + Status: metav1.ConditionUnknown, + Type: string(placementv1beta1.ResourceRolloutStartedConditionType), + Reason: condition.RolloutStartedUnknownReason, }, }, }, @@ -470,11 +440,9 @@ var _ = Describe("Test ClusterResourcePlacement Controller", func() { } retrieveAndValidateClusterResourcePlacement(testName, wantCRP) - By("By creating clusterResourceBinding on member-1") - createClusterResourceBinding(member2Name, gotPolicySnapshot, gotResourceSnapshot) + By("By creating a synchronized clusterResourceBinding on member-2") + createSynchronizedClusterResourceBinding(member2Name, gotPolicySnapshot, gotResourceSnapshot) - By("By creating appliedSuccess works on member-2") - createApplySucceededWork(gotResourceSnapshot, member2Namespace) wantCRP = &placementv1beta1.ClusterResourcePlacement{ ObjectMeta: metav1.ObjectMeta{ Name: testName, @@ -486,38 +454,49 @@ var _ = Describe("Test ClusterResourcePlacement Controller", func() { Conditions: []metav1.Condition{ { Status: metav1.ConditionTrue, - Type: string(placementv1beta1.ClusterResourcePlacementAppliedConditionType), - Reason: ApplySucceededReason, + Type: string(placementv1beta1.ClusterResourcePlacementScheduledConditionType), + Reason: ResourceScheduleSucceededReason, }, { Status: metav1.ConditionTrue, - Type: string(placementv1beta1.ClusterResourcePlacementScheduledConditionType), - Reason: ResourceScheduleSucceededReason, + Type: string(placementv1beta1.ClusterResourcePlacementRolloutStartedConditionType), + Reason: condition.RolloutStartedReason, }, { Status: metav1.ConditionTrue, - Type: string(placementv1beta1.ClusterResourcePlacementSynchronizedConditionType), - Reason: SynchronizeSucceededReason, + Type: string(placementv1beta1.ClusterResourcePlacementOverriddenConditionType), + Reason: condition.OverrideNotSpecifiedReason, + }, + { + Status: metav1.ConditionUnknown, + Type: string(placementv1beta1.ClusterResourcePlacementWorkSynchronizedConditionType), + Reason: condition.WorkSynchronizedUnknownReason, }, }, PlacementStatuses: []placementv1beta1.ResourcePlacementStatus{ { + ClusterName: member1Name, Conditions: []metav1.Condition{ { Status: metav1.ConditionTrue, - Type: string(placementv1beta1.ResourcesAppliedConditionType), - Reason: ResourceApplySucceededReason, + Type: string(placementv1beta1.ResourceScheduledConditionType), + Reason: condition.ScheduleSucceededReason, }, { Status: metav1.ConditionTrue, - Type: string(placementv1beta1.ResourceScheduledConditionType), - Reason: ResourceScheduleSucceededReason, + Type: string(placementv1beta1.ResourceRolloutStartedConditionType), + Reason: condition.RolloutStartedReason, }, { Status: metav1.ConditionTrue, + Type: string(placementv1beta1.ResourceOverriddenConditionType), + Reason: condition.OverriddenSucceededReason, + }, + { + Status: metav1.ConditionUnknown, Type: string(placementv1beta1.ResourceWorkSynchronizedConditionType), - Reason: WorkSynchronizeSucceededReason, + Reason: condition.WorkSynchronizedUnknownReason, }, }, }, @@ -526,18 +505,28 @@ var _ = Describe("Test ClusterResourcePlacement Controller", func() { Conditions: []metav1.Condition{ { Status: metav1.ConditionTrue, - Type: string(placementv1beta1.ResourcesAppliedConditionType), - Reason: ResourceApplySucceededReason, + Type: string(placementv1beta1.ResourceScheduledConditionType), + Reason: condition.ScheduleSucceededReason, }, { Status: metav1.ConditionTrue, - Type: string(placementv1beta1.ResourceScheduledConditionType), - Reason: ResourceScheduleSucceededReason, + Type: string(placementv1beta1.ResourceRolloutStartedConditionType), + Reason: condition.RolloutStartedReason, + }, + { + Status: metav1.ConditionTrue, + Type: string(placementv1beta1.ResourceOverriddenConditionType), + Reason: condition.OverriddenSucceededReason, }, { Status: metav1.ConditionTrue, Type: string(placementv1beta1.ResourceWorkSynchronizedConditionType), - Reason: WorkSynchronizeSucceededReason, + Reason: condition.WorkSynchronizedReason, + }, + { + Status: metav1.ConditionUnknown, + Type: string(placementv1beta1.ResourcesAppliedConditionType), + Reason: condition.ApplyPendingReason, }, }, }, diff --git a/pkg/controllers/clusterresourceplacement/controller_test.go b/pkg/controllers/clusterresourceplacement/controller_test.go index 042e1bd5b..702cf0867 100644 --- a/pkg/controllers/clusterresourceplacement/controller_test.go +++ b/pkg/controllers/clusterresourceplacement/controller_test.go @@ -3073,117 +3073,6 @@ func TestHandleDelete(t *testing.T) { } func TestIsRolloutComplete(t *testing.T) { - crpGeneration := int64(25) - tests := []struct { - name string - conditions []metav1.Condition - want bool - }{ - { - name: "rollout is completed", - conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementAppliedConditionType), - ObservedGeneration: crpGeneration, - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType), - ObservedGeneration: crpGeneration, - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementSynchronizedConditionType), - ObservedGeneration: crpGeneration, - }, - }, - want: true, - }, - { - name: "schedule has not completed", - conditions: []metav1.Condition{ - { - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ClusterResourcePlacementAppliedConditionType), - ObservedGeneration: crpGeneration, - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType), - ObservedGeneration: crpGeneration, - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementSynchronizedConditionType), - ObservedGeneration: crpGeneration, - }, - }, - want: false, - }, - { - name: "sync has not completed", - conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementAppliedConditionType), - ObservedGeneration: crpGeneration, - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType), - ObservedGeneration: crpGeneration - 1, - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementSynchronizedConditionType), - ObservedGeneration: crpGeneration, - }, - }, - want: false, - }, - { - name: "apply has not completed", - conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementAppliedConditionType), - ObservedGeneration: crpGeneration, - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType), - ObservedGeneration: crpGeneration - 1, - }, - { - Status: metav1.ConditionFalse, - Type: string(fleetv1beta1.ClusterResourcePlacementSynchronizedConditionType), - ObservedGeneration: crpGeneration, - }, - }, - want: false, - }, - } - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - crp := &fleetv1beta1.ClusterResourcePlacement{ - ObjectMeta: metav1.ObjectMeta{ - Name: testName, - Generation: crpGeneration, - }, - Status: fleetv1beta1.ClusterResourcePlacementStatus{ - Conditions: tc.conditions, - }, - } - got := isRolloutCompleted(false, crp) - if got != tc.want { - t.Errorf("isRolloutCompleted() got %v, want %v", got, tc.want) - } - }) - } -} - -func TestIsRolloutComplete_withNewConditions(t *testing.T) { crpGeneration := int64(25) tests := []struct { name string @@ -3369,7 +3258,7 @@ func TestIsRolloutComplete_withNewConditions(t *testing.T) { Conditions: tc.conditions, }, } - got := isRolloutCompleted(true, crp) + got := isRolloutCompleted(crp) if got != tc.want { t.Errorf("isRolloutCompleted() got %v, want %v", got, tc.want) } diff --git a/pkg/controllers/clusterresourceplacement/placement_controllerv1alpha1.go b/pkg/controllers/clusterresourceplacement/placement_controllerv1alpha1.go index 62ca8c255..9cf061e9f 100644 --- a/pkg/controllers/clusterresourceplacement/placement_controllerv1alpha1.go +++ b/pkg/controllers/clusterresourceplacement/placement_controllerv1alpha1.go @@ -58,9 +58,6 @@ type Reconciler struct { Recorder record.EventRecorder Scheme *runtime.Scheme - - // Whether to use the new status func to populate the crp status. - UseNewConditions bool } // ReconcileV1Alpha1 reconciles v1aplha1 APIs. diff --git a/pkg/controllers/clusterresourceplacement/placement_status.go b/pkg/controllers/clusterresourceplacement/placement_status.go index 0e3b443da..192588288 100644 --- a/pkg/controllers/clusterresourceplacement/placement_status.go +++ b/pkg/controllers/clusterresourceplacement/placement_status.go @@ -18,7 +18,6 @@ import ( "go.goms.io/fleet/pkg/utils" "go.goms.io/fleet/pkg/utils/condition" "go.goms.io/fleet/pkg/utils/controller" - "go.goms.io/fleet/pkg/utils/labels" ) var ( @@ -77,276 +76,7 @@ const ( resourcePlacementConditionScheduleSucceededWithScoreMessageFormat = "Successfully scheduled resources for placement in %s (affinity score: %d, topology spread score: %d): %s" ) -func buildClusterResourcePlacementSyncCondition(crp *fleetv1beta1.ClusterResourcePlacement, pendingCount, succeededCount int) metav1.Condition { - klog.V(3).InfoS("Building the clusterResourcePlacement synchronized condition", "clusterResourcePlacement", klog.KObj(crp), - "numberOfSynchronizedPendingCluster", pendingCount, "numberOfSynchronizedSucceededCluster", succeededCount) - if pendingCount > 0 { - return metav1.Condition{ - Status: metav1.ConditionFalse, - Type: string(fleetv1beta1.ClusterResourcePlacementSynchronizedConditionType), - Reason: SynchronizePendingReason, - Message: fmt.Sprintf("There are still %d cluster(s) pending to be sychronized on the hub cluster", pendingCount), - ObservedGeneration: crp.Generation, - } - } - return metav1.Condition{ - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementSynchronizedConditionType), - Reason: SynchronizeSucceededReason, - Message: fmt.Sprintf("All %d cluster(s) are synchronized to the latest resources on the hub cluster", succeededCount), - ObservedGeneration: crp.Generation, - } -} - -func buildClusterResourcePlacementApplyCondition(crp *fleetv1beta1.ClusterResourcePlacement, isSync bool, pendingCount, succeededCount, failedCount int) metav1.Condition { - klog.V(3).InfoS("Building the clusterResourcePlacement applied condition", "clusterResourcePlacement", klog.KObj(crp), - "isSynced", isSync, "numberOfAppliedPendingCluster", pendingCount, "numberOfAppliedSucceededCluster", succeededCount, "numberOfAppliedFailedCluster", failedCount) - - if pendingCount+succeededCount+failedCount == 0 { - // If the cluster is selected, it should be in one of the state. - return metav1.Condition{ - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementAppliedConditionType), - Reason: ApplySucceededReason, - Message: "There are no clusters selected to place the resources", - ObservedGeneration: crp.Generation, - } - } - - if !isSync || pendingCount > 0 { - return metav1.Condition{ - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ClusterResourcePlacementAppliedConditionType), - Reason: ApplyPendingReason, - Message: fmt.Sprintf("Works need to be synchronized on the hub cluster or there are still manifests pending to be processed by the %d member clusters ", pendingCount), - ObservedGeneration: crp.Generation, - } - } - - if failedCount > 0 { - return metav1.Condition{ - Status: metav1.ConditionFalse, - Type: string(fleetv1beta1.ClusterResourcePlacementAppliedConditionType), - Reason: ApplyFailedReason, - Message: fmt.Sprintf("Failed to apply manifests to %d clusters, please check the `failedPlacements` status", failedCount), - ObservedGeneration: crp.Generation, - } - } - - return metav1.Condition{ - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementAppliedConditionType), - Reason: ApplySucceededReason, - Message: fmt.Sprintf("Successfully applied resources to %d member clusters", succeededCount), - ObservedGeneration: crp.Generation, - } -} - -// setWorkStatusForResourcePlacementStatus will list all the associated works with latest resourceSnapshots and build the work conditions. -// Returns workSynchronizedCondition & workAppliedCondition. -func (r *Reconciler) setWorkStatusForResourcePlacementStatus(ctx context.Context, - crp *fleetv1beta1.ClusterResourcePlacement, latestResourceSnapshot *fleetv1beta1.ClusterResourceSnapshot, clusterResourceBinding *fleetv1beta1.ClusterResourceBinding, - status *fleetv1beta1.ResourcePlacementStatus) (*metav1.Condition, *metav1.Condition, error) { - crpKObj := klog.KObj(crp) - namespaceMatcher := client.InNamespace(fmt.Sprintf(utils.NamespaceNameFormat, status.ClusterName)) - workLabelMatcher := client.MatchingLabels{ - fleetv1beta1.CRPTrackingLabel: crp.Name, - } - workList := &fleetv1beta1.WorkList{} - - if err := r.Client.List(ctx, workList, workLabelMatcher, namespaceMatcher); err != nil { - klog.ErrorS(err, "Failed to list all the work associated with the clusterResourcePlacement", "clusterResourcePlacement", crpKObj, "clusterName", status.ClusterName) - return nil, nil, controller.NewAPIServerError(true, err) - } - - latestResourceIndex, err := labels.ExtractResourceIndexFromClusterResourceSnapshot(latestResourceSnapshot) - if err != nil { - klog.ErrorS(err, "Failed to parse the resource snapshot index label from latest clusterResourceSnapshot", "clusterResourcePlacement", crpKObj, "clusterResourceSnapshot", klog.KObj(latestResourceSnapshot)) - return nil, nil, controller.NewUnexpectedBehaviorError(err) - } - // Used to build the work applied condition - pendingWorkCounter := 0 // The work has not been applied yet. - - failedResourcePlacements := make([]fleetv1beta1.FailedResourcePlacement, 0, maxFailedResourcePlacementLimit) // preallocate the memory - for i := range workList.Items { - work := workList.Items[i] - if work.DeletionTimestamp != nil { - continue // ignore the deleting work - } - workKObj := klog.KObj(&work) - resourceIndexFromWork, err := labels.ExtractResourceSnapshotIndexFromWork(&work) - if err != nil { - klog.ErrorS(err, "Failed to parse the resource snapshot index label from work", "clusterResourcePlacement", crpKObj, "work", workKObj) - return nil, nil, controller.NewUnexpectedBehaviorError(err) - } - if resourceIndexFromWork > latestResourceIndex { - err := fmt.Errorf("invalid work %s: resource snapshot index %d on the work is greater than resource index %d on the latest clusterResourceSnapshot", workKObj, resourceIndexFromWork, latestResourceIndex) - klog.ErrorS(err, "Invalid work", "clusterResourcePlacement", crpKObj, "clusterResourceSnapshot", klog.KObj(latestResourceSnapshot), "work", workKObj) - return nil, nil, controller.NewUnexpectedBehaviorError(err) - } else if resourceIndexFromWork == latestResourceIndex { - // We only build the work applied status on the new works. - isPending, failedManifests := buildFailedResourcePlacements(&work) - if isPending { - pendingWorkCounter++ - } - if len(failedManifests) != 0 && len(failedResourcePlacements) < maxFailedResourcePlacementLimit { - failedResourcePlacements = append(failedResourcePlacements, failedManifests...) - } - } - } - - if len(failedResourcePlacements) > maxFailedResourcePlacementLimit { - failedResourcePlacements = failedResourcePlacements[0:maxFailedResourcePlacementLimit] - } - - klog.V(2).InfoS("Building the resourcePlacementStatus", "clusterResourcePlacement", crpKObj, "clusterName", status.ClusterName, - "numberOfPendingWorks", pendingWorkCounter, "numberOfFailedResources", len(failedResourcePlacements)) - - status.FailedPlacements = failedResourcePlacements - - isSync, workSynchronizedCondition := buildWorkSynchronizedCondition(crp, clusterResourceBinding) - meta.SetStatusCondition(&status.Conditions, workSynchronizedCondition) - - workAppliedCondition := buildWorkAppliedCondition(crp, !isSync || pendingWorkCounter > 0, len(failedResourcePlacements) > 0) - meta.SetStatusCondition(&status.Conditions, workAppliedCondition) - return &workSynchronizedCondition, &workAppliedCondition, nil -} - -func buildWorkSynchronizedCondition(crp *fleetv1beta1.ClusterResourcePlacement, binding *fleetv1beta1.ClusterResourceBinding) (bool, metav1.Condition) { - if binding != nil { - boundCondition := binding.GetCondition(string(fleetv1beta1.ResourceBindingBound)) - if condition.IsConditionStatusTrue(boundCondition, binding.Generation) { - // This condition is set to true only if the work generator have created all the works according to the latest resource snapshot. - return true, metav1.Condition{ - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourceWorkSynchronizedConditionType), - Reason: WorkSynchronizeSucceededReason, - Message: "Successfully Synchronized work(s) for placement", - ObservedGeneration: crp.Generation, - } - } else if condition.IsConditionStatusFalse(boundCondition, binding.Generation) { - return false, metav1.Condition{ - Status: metav1.ConditionFalse, - Type: string(fleetv1beta1.ResourceWorkSynchronizedConditionType), - Reason: WorkSynchronizeFailedReason, - Message: boundCondition.Message, - ObservedGeneration: crp.Generation, - } - } - } - return false, metav1.Condition{ - Status: metav1.ConditionFalse, - Type: string(fleetv1beta1.ResourceWorkSynchronizedConditionType), - Reason: WorkSynchronizePendingReason, - Message: "In the process of synchronizing or operation is blocked by the rollout strategy ", - ObservedGeneration: crp.Generation, - } -} - -func buildWorkAppliedCondition(crp *fleetv1beta1.ClusterResourcePlacement, hasPendingWork, hasFailedResource bool) metav1.Condition { - // hasPendingWork could be true when - // - the works have not been created in the hub cluster. - // - the works have not been processed by the member cluster. - if hasPendingWork { - return metav1.Condition{ - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ResourcesAppliedConditionType), - Reason: ResourceApplyPendingReason, - Message: "Works need to be synchronized on the hub cluster or there are still manifests pending to be processed by the member cluster", - ObservedGeneration: crp.Generation, - } - } - - if hasFailedResource { - return metav1.Condition{ - Status: metav1.ConditionFalse, - Type: string(fleetv1beta1.ResourcesAppliedConditionType), - Reason: ResourceApplyFailedReason, - Message: "Failed to apply manifests, please check the `failedPlacements` status", - ObservedGeneration: crp.Generation, - } - } - - return metav1.Condition{ // if !hasFailedResource && !hasPendingWork - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourcesAppliedConditionType), - Reason: ResourceApplySucceededReason, - Message: "Successfully applied resources", - ObservedGeneration: crp.Generation, - } -} - -// buildFailedResourcePlacements returns if work is pending or not. -// If the work has been applied, it returns the list of failed resources. -func buildFailedResourcePlacements(work *fleetv1beta1.Work) (isPending bool, res []fleetv1beta1.FailedResourcePlacement) { - // check the overall condition - workKObj := klog.KObj(work) - appliedCond := meta.FindStatusCondition(work.Status.Conditions, fleetv1beta1.WorkConditionTypeApplied) - if appliedCond == nil { - klog.V(3).InfoS("The work is never picked up by the member cluster", "work", workKObj) - return true, nil - } - if appliedCond.ObservedGeneration < work.GetGeneration() || appliedCond.Status == metav1.ConditionUnknown { - klog.V(3).InfoS("The update of the work is not picked up by the member cluster yet", "work", workKObj, "workGeneration", work.GetGeneration(), "appliedGeneration", appliedCond.ObservedGeneration, "status", appliedCond.Status) - return true, nil - } - - if appliedCond.Status == metav1.ConditionTrue { - klog.V(3).InfoS("The work is applied successfully by the member cluster", "work", workKObj, "workGeneration", work.GetGeneration()) - return false, nil - } - - // check if the work is generated by an enveloped object - envelopeType, isEnveloped := work.GetLabels()[fleetv1beta1.EnvelopeTypeLabel] - var envelopObjName, envelopObjNamespace string - if isEnveloped { - // If the work generated by an enveloped object, it must contain those labels. - envelopObjName = work.GetLabels()[fleetv1beta1.EnvelopeNameLabel] - envelopObjNamespace = work.GetLabels()[fleetv1beta1.EnvelopeNamespaceLabel] - } - res = make([]fleetv1beta1.FailedResourcePlacement, 0, len(work.Status.ManifestConditions)) - for _, manifestCondition := range work.Status.ManifestConditions { - appliedCond = meta.FindStatusCondition(manifestCondition.Conditions, fleetv1beta1.WorkConditionTypeApplied) - // collect if there is an explicit fail - if appliedCond != nil && appliedCond.Status != metav1.ConditionTrue { - if isEnveloped { - klog.V(2).InfoS("Find a failed to apply enveloped manifest", - "manifestName", manifestCondition.Identifier.Name, - "group", manifestCondition.Identifier.Group, - "version", manifestCondition.Identifier.Version, "kind", manifestCondition.Identifier.Kind, - "envelopeType", envelopeType, "envelopObjName", envelopObjName, "envelopObjNamespace", envelopObjNamespace) - } else { - klog.V(2).InfoS("Find a failed to apply manifest", - "manifestName", manifestCondition.Identifier.Name, "group", manifestCondition.Identifier.Group, - "version", manifestCondition.Identifier.Version, "kind", manifestCondition.Identifier.Kind) - } - failedManifest := fleetv1beta1.FailedResourcePlacement{ - ResourceIdentifier: fleetv1beta1.ResourceIdentifier{ - Group: manifestCondition.Identifier.Group, - Version: manifestCondition.Identifier.Version, - Kind: manifestCondition.Identifier.Kind, - Name: manifestCondition.Identifier.Name, - Namespace: manifestCondition.Identifier.Namespace, - }, - Condition: *appliedCond, - } - if isEnveloped { - failedManifest.ResourceIdentifier.Envelope = &fleetv1beta1.EnvelopeIdentifier{ - Name: envelopObjName, - Namespace: envelopObjNamespace, - Type: fleetv1beta1.EnvelopeType(envelopeType), - } - } - res = append(res, failedManifest) - } - } - return false, res -} - -// --------------------------------- populating the new conditions------------ - -// setResourceConditions sets the resource related conditions by looking at the bindings and work, excluding the scheduled -// condition. +// setResourceConditions sets the resource related conditions by looking at the bindings and work, excluding the scheduled condition. // It returns whether there is a cluster scheduled or not. func (r *Reconciler) setResourceConditions(ctx context.Context, crp *fleetv1beta1.ClusterResourcePlacement, latestSchedulingPolicySnapshot *fleetv1beta1.ClusterSchedulingPolicySnapshot, latestResourceSnapshot *fleetv1beta1.ClusterResourceSnapshot) (bool, error) { @@ -409,6 +139,11 @@ func (r *Reconciler) setResourceConditions(ctx context.Context, crp *fleetv1beta clusterConditionStatusRes[i][condition.UnknownConditionStatus]++ } } + // The resources can be changed without updating the crp spec. + // To reflect the latest resource conditions, we reset the renaming conditions. + for i := condition.ResourceCondition(len(res)); i < condition.TotalCondition; i++ { + meta.RemoveStatusCondition(&rps.Conditions, string(i.ResourcePlacementConditionType())) + } placementStatuses = append(placementStatuses, rps) klog.V(2).InfoS("Populated the resource placement status for the scheduled cluster", "clusterResourcePlacement", klog.KObj(crp), "cluster", c.ClusterName) } @@ -435,12 +170,16 @@ func (r *Reconciler) setResourceConditions(ctx context.Context, crp *fleetv1beta crp.Status.PlacementStatuses = placementStatuses if !isClusterScheduled { - // TODO special handling when isClusterScheduled is false - // Currently it will stop updating the resource related conditions and leave the existing conditions there. + // It covers one special case: CRP selects a cluster which joins (resource are applied) and then leaves. + // In this case, CRP generation has not been changed. + // And we cannot rely on the generation to filter out the stale conditions. + // But the resource related conditions are set before. So that, we reset them. + crp.Status.Conditions = []metav1.Condition{*crp.GetCondition(string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType))} return false, nil } - for i := condition.RolloutStartedCondition; i < condition.TotalCondition; i++ { + i := condition.RolloutStartedCondition + for ; i < condition.TotalCondition; i++ { if clusterConditionStatusRes[i][condition.UnknownConditionStatus] > 0 { crp.SetConditions(i.UnknownClusterResourcePlacementCondition(crp.Generation, clusterConditionStatusRes[i][condition.UnknownConditionStatus])) break @@ -448,9 +187,29 @@ func (r *Reconciler) setResourceConditions(ctx context.Context, crp *fleetv1beta crp.SetConditions(i.FalseClusterResourcePlacementCondition(crp.Generation, clusterConditionStatusRes[i][condition.FalseConditionStatus])) break } else { - crp.SetConditions(i.TrueClusterResourcePlacementCondition(crp.Generation, clusterConditionStatusRes[i][condition.TrueConditionStatus])) + cond := i.TrueClusterResourcePlacementCondition(crp.Generation, clusterConditionStatusRes[i][condition.TrueConditionStatus]) + if i == condition.OverriddenCondition { + hasOverride := false + for _, status := range placementStatuses { + if len(status.ApplicableResourceOverrides) > 0 || len(status.ApplicableClusterResourceOverrides) > 0 { + hasOverride = true + break + } + } + if !hasOverride { + cond.Reason = condition.OverrideNotSpecifiedReason + cond.Message = "No override rules are configured for the selected resources" + } + } + crp.SetConditions(cond) } } + // reset the remaining conditions, starting from the next one + for i = i + 1; i < condition.TotalCondition; i++ { + // The resources can be changed without updating the crp spec. + // To reflect the latest resource conditions, we reset the renaming conditions. + meta.RemoveStatusCondition(&crp.Status.Conditions, string(i.ClusterResourcePlacementConditionType())) + } klog.V(2).InfoS("Populated the placement conditions", "clusterResourcePlacement", klog.KObj(crp)) return true, nil diff --git a/pkg/controllers/clusterresourceplacement/placement_status_test.go b/pkg/controllers/clusterresourceplacement/placement_status_test.go index 22665d996..f17fd3189 100644 --- a/pkg/controllers/clusterresourceplacement/placement_status_test.go +++ b/pkg/controllers/clusterresourceplacement/placement_status_test.go @@ -28,11 +28,6 @@ import ( "go.goms.io/fleet/pkg/utils/controller" ) -var ( - cluster1Name = "cluster-1" - cluster2Name = "cluster-2" -) - var statusCmpOptions = []cmp.Option{ // ignore the message as we may change the message in the future cmpopts.IgnoreFields(metav1.Condition{}, "Message"), @@ -76,6 +71,20 @@ func TestSetPlacementStatus(t *testing.T) { Name: "svc-name", Namespace: "svc-namespace", }, + { + Group: "", + Version: "v1", + Kind: "Deployment", + Name: "deployment-name", + Namespace: "deployment-namespace", + }, + { + Group: "", + Version: "v1", + Kind: "ConfigMap", + Name: "config-name", + Namespace: "config-namespace", + }, } tests := []struct { name string @@ -87,6 +96,7 @@ func TestSetPlacementStatus(t *testing.T) { works []fleetv1beta1.Work want bool wantStatus *fleetv1beta1.ClusterResourcePlacementStatus + wantErr error }{ { name: "empty policy and resource status", @@ -98,15 +108,6 @@ func TestSetPlacementStatus(t *testing.T) { fleetv1beta1.IsLatestSnapshotLabel: "true", fleetv1beta1.CRPTrackingLabel: testName, }, - OwnerReferences: []metav1.OwnerReference{ - { - Name: testName, - BlockOwnerDeletion: ptr.To(true), - Controller: ptr.To(true), - APIVersion: fleetAPIVersion, - Kind: "ClusterResourcePlacement", - }, - }, Annotations: map[string]string{ fleetv1beta1.NumberOfClustersAnnotation: strconv.Itoa(3), }, @@ -120,15 +121,6 @@ func TestSetPlacementStatus(t *testing.T) { fleetv1beta1.CRPTrackingLabel: testName, fleetv1beta1.IsLatestSnapshotLabel: "true", }, - OwnerReferences: []metav1.OwnerReference{ - { - Name: testName, - BlockOwnerDeletion: ptr.To(true), - Controller: ptr.To(true), - APIVersion: fleetAPIVersion, - Kind: "ClusterResourcePlacement", - }, - }, Annotations: map[string]string{ fleetv1beta1.ResourceGroupHashAnnotation: "hash", fleetv1beta1.NumberOfResourceSnapshotsAnnotation: "1", @@ -140,13 +132,6 @@ func TestSetPlacementStatus(t *testing.T) { SelectedResources: selectedResources, ObservedResourceIndex: "0", Conditions: []metav1.Condition{ - { - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ClusterResourcePlacementAppliedConditionType), - Reason: ApplyPendingReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, { Status: metav1.ConditionUnknown, Type: string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType), @@ -154,13 +139,6 @@ func TestSetPlacementStatus(t *testing.T) { ObservedGeneration: crpGeneration, LastTransitionTime: metav1.NewTime(currentTime), }, - { - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ClusterResourcePlacementSynchronizedConditionType), - Reason: SynchronizePendingReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, }, PlacementStatuses: []fleetv1beta1.ResourcePlacementStatus{}, }, @@ -175,15 +153,6 @@ func TestSetPlacementStatus(t *testing.T) { fleetv1beta1.IsLatestSnapshotLabel: "true", fleetv1beta1.CRPTrackingLabel: testName, }, - OwnerReferences: []metav1.OwnerReference{ - { - Name: testName, - BlockOwnerDeletion: ptr.To(true), - Controller: ptr.To(true), - APIVersion: fleetAPIVersion, - Kind: "ClusterResourcePlacement", - }, - }, Annotations: map[string]string{ fleetv1beta1.NumberOfClustersAnnotation: strconv.Itoa(3), }, @@ -211,15 +180,6 @@ func TestSetPlacementStatus(t *testing.T) { fleetv1beta1.CRPTrackingLabel: testName, fleetv1beta1.IsLatestSnapshotLabel: "true", }, - OwnerReferences: []metav1.OwnerReference{ - { - Name: testName, - BlockOwnerDeletion: ptr.To(true), - Controller: ptr.To(true), - APIVersion: fleetAPIVersion, - Kind: "ClusterResourcePlacement", - }, - }, Annotations: map[string]string{ fleetv1beta1.ResourceGroupHashAnnotation: "hash", fleetv1beta1.NumberOfResourceSnapshotsAnnotation: "1", @@ -228,24 +188,9 @@ func TestSetPlacementStatus(t *testing.T) { }, want: false, wantStatus: &fleetv1beta1.ClusterResourcePlacementStatus{ - SelectedResources: []fleetv1beta1.ResourceIdentifier{ - { - Group: "", - Version: "v1", - Kind: "Service", - Name: "svc-name", - Namespace: "svc-namespace", - }, - }, + SelectedResources: selectedResources, ObservedResourceIndex: "0", Conditions: []metav1.Condition{ - { - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ClusterResourcePlacementAppliedConditionType), - Reason: ApplyPendingReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, { Status: metav1.ConditionUnknown, Type: string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType), @@ -253,13 +198,6 @@ func TestSetPlacementStatus(t *testing.T) { ObservedGeneration: crpGeneration, LastTransitionTime: metav1.NewTime(currentTime), }, - { - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ClusterResourcePlacementSynchronizedConditionType), - Reason: SynchronizePendingReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, }, PlacementStatuses: []fleetv1beta1.ResourcePlacementStatus{}, }, @@ -274,15 +212,6 @@ func TestSetPlacementStatus(t *testing.T) { fleetv1beta1.IsLatestSnapshotLabel: "true", fleetv1beta1.CRPTrackingLabel: testName, }, - OwnerReferences: []metav1.OwnerReference{ - { - Name: testName, - BlockOwnerDeletion: ptr.To(true), - Controller: ptr.To(true), - APIVersion: fleetAPIVersion, - Kind: "ClusterResourcePlacement", - }, - }, Annotations: map[string]string{ fleetv1beta1.NumberOfClustersAnnotation: strconv.Itoa(3), }, @@ -310,15 +239,6 @@ func TestSetPlacementStatus(t *testing.T) { fleetv1beta1.CRPTrackingLabel: testName, fleetv1beta1.IsLatestSnapshotLabel: "true", }, - OwnerReferences: []metav1.OwnerReference{ - { - Name: testName, - BlockOwnerDeletion: ptr.To(true), - Controller: ptr.To(true), - APIVersion: fleetAPIVersion, - Kind: "ClusterResourcePlacement", - }, - }, Annotations: map[string]string{ fleetv1beta1.ResourceGroupHashAnnotation: "hash", fleetv1beta1.NumberOfResourceSnapshotsAnnotation: "1", @@ -330,13 +250,6 @@ func TestSetPlacementStatus(t *testing.T) { SelectedResources: selectedResources, ObservedResourceIndex: "0", Conditions: []metav1.Condition{ - { - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ClusterResourcePlacementAppliedConditionType), - Reason: ApplyPendingReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, { Status: metav1.ConditionUnknown, Type: string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType), @@ -344,13 +257,6 @@ func TestSetPlacementStatus(t *testing.T) { ObservedGeneration: crpGeneration, LastTransitionTime: metav1.NewTime(currentTime), }, - { - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ClusterResourcePlacementSynchronizedConditionType), - Reason: SynchronizePendingReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, }, PlacementStatuses: []fleetv1beta1.ResourcePlacementStatus{}, }, @@ -366,15 +272,6 @@ func TestSetPlacementStatus(t *testing.T) { fleetv1beta1.IsLatestSnapshotLabel: "true", fleetv1beta1.CRPTrackingLabel: testName, }, - OwnerReferences: []metav1.OwnerReference{ - { - Name: testName, - BlockOwnerDeletion: ptr.To(true), - Controller: ptr.To(true), - APIVersion: fleetAPIVersion, - Kind: "ClusterResourcePlacement", - }, - }, Annotations: map[string]string{ fleetv1beta1.NumberOfClustersAnnotation: strconv.Itoa(3), }, @@ -391,7 +288,6 @@ func TestSetPlacementStatus(t *testing.T) { ObservedGeneration: 1, }, }, - ClusterDecisions: nil, }, }, latestResourceSnapshot: &fleetv1beta1.ClusterResourceSnapshot{ @@ -402,15 +298,6 @@ func TestSetPlacementStatus(t *testing.T) { fleetv1beta1.CRPTrackingLabel: testName, fleetv1beta1.IsLatestSnapshotLabel: "true", }, - OwnerReferences: []metav1.OwnerReference{ - { - Name: testName, - BlockOwnerDeletion: ptr.To(true), - Controller: ptr.To(true), - APIVersion: fleetAPIVersion, - Kind: "ClusterResourcePlacement", - }, - }, Annotations: map[string]string{ fleetv1beta1.ResourceGroupHashAnnotation: "hash", fleetv1beta1.NumberOfResourceSnapshotsAnnotation: "1", @@ -422,13 +309,6 @@ func TestSetPlacementStatus(t *testing.T) { SelectedResources: selectedResources, ObservedResourceIndex: "0", Conditions: []metav1.Condition{ - { - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ClusterResourcePlacementAppliedConditionType), - Reason: ApplyPendingReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, { Status: metav1.ConditionUnknown, Type: string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType), @@ -436,13 +316,6 @@ func TestSetPlacementStatus(t *testing.T) { ObservedGeneration: crpGeneration, LastTransitionTime: metav1.NewTime(currentTime), }, - { - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ClusterResourcePlacementSynchronizedConditionType), - Reason: SynchronizePendingReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, }, PlacementStatuses: []fleetv1beta1.ResourcePlacementStatus{}, }, @@ -458,15 +331,6 @@ func TestSetPlacementStatus(t *testing.T) { fleetv1beta1.IsLatestSnapshotLabel: "true", fleetv1beta1.CRPTrackingLabel: testName, }, - OwnerReferences: []metav1.OwnerReference{ - { - Name: testName, - BlockOwnerDeletion: ptr.To(true), - Controller: ptr.To(true), - APIVersion: fleetAPIVersion, - Kind: "ClusterResourcePlacement", - }, - }, Annotations: map[string]string{ fleetv1beta1.NumberOfClustersAnnotation: strconv.Itoa(3), }, @@ -514,15 +378,6 @@ func TestSetPlacementStatus(t *testing.T) { fleetv1beta1.CRPTrackingLabel: testName, fleetv1beta1.IsLatestSnapshotLabel: "true", }, - OwnerReferences: []metav1.OwnerReference{ - { - Name: testName, - BlockOwnerDeletion: ptr.To(true), - Controller: ptr.To(true), - APIVersion: fleetAPIVersion, - Kind: "ClusterResourcePlacement", - }, - }, Annotations: map[string]string{ fleetv1beta1.ResourceGroupHashAnnotation: "hash", fleetv1beta1.NumberOfResourceSnapshotsAnnotation: "1", @@ -536,8 +391,8 @@ func TestSetPlacementStatus(t *testing.T) { Conditions: []metav1.Condition{ { Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ClusterResourcePlacementAppliedConditionType), - Reason: ApplyPendingReason, + Type: string(fleetv1beta1.ClusterResourcePlacementRolloutStartedConditionType), + Reason: condition.RolloutStartedUnknownReason, ObservedGeneration: crpGeneration, LastTransitionTime: metav1.NewTime(currentTime), }, @@ -548,91 +403,60 @@ func TestSetPlacementStatus(t *testing.T) { ObservedGeneration: crpGeneration, LastTransitionTime: metav1.NewTime(currentTime), }, - { - Status: metav1.ConditionFalse, - Type: string(fleetv1beta1.ClusterResourcePlacementSynchronizedConditionType), - Reason: SynchronizePendingReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, }, PlacementStatuses: []fleetv1beta1.ResourcePlacementStatus{ { - ClusterName: "member-1", - FailedPlacements: []fleetv1beta1.FailedResourcePlacement{}, + ClusterName: "member-1", Conditions: []metav1.Condition{ { Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ResourcesAppliedConditionType), - Reason: ResourceApplyPendingReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - { - Status: metav1.ConditionFalse, - Type: string(fleetv1beta1.ResourceWorkSynchronizedConditionType), - Reason: WorkSynchronizePendingReason, + Type: string(fleetv1beta1.ResourceRolloutStartedConditionType), + Reason: condition.RolloutStartedUnknownReason, ObservedGeneration: crpGeneration, LastTransitionTime: metav1.NewTime(currentTime), }, { Status: metav1.ConditionTrue, Type: string(fleetv1beta1.ResourceScheduledConditionType), - Reason: "ScheduleSucceeded", + Reason: condition.ScheduleSucceededReason, ObservedGeneration: crpGeneration, LastTransitionTime: metav1.NewTime(currentTime), }, }, }, { - ClusterName: "member-2", - FailedPlacements: []fleetv1beta1.FailedResourcePlacement{}, + ClusterName: "member-2", Conditions: []metav1.Condition{ { Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ResourcesAppliedConditionType), - Reason: ResourceApplyPendingReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - { - Status: metav1.ConditionFalse, - Type: string(fleetv1beta1.ResourceWorkSynchronizedConditionType), - Reason: WorkSynchronizePendingReason, + Type: string(fleetv1beta1.ResourceRolloutStartedConditionType), + Reason: condition.RolloutStartedUnknownReason, ObservedGeneration: crpGeneration, LastTransitionTime: metav1.NewTime(currentTime), }, { Status: metav1.ConditionTrue, Type: string(fleetv1beta1.ResourceScheduledConditionType), - Reason: "ScheduleSucceeded", + Reason: condition.ScheduleSucceededReason, ObservedGeneration: crpGeneration, LastTransitionTime: metav1.NewTime(currentTime), }, }, }, { - ClusterName: "member-3", - FailedPlacements: []fleetv1beta1.FailedResourcePlacement{}, + ClusterName: "member-3", Conditions: []metav1.Condition{ { Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ResourcesAppliedConditionType), - Reason: ResourceApplyPendingReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - { - Status: metav1.ConditionFalse, - Type: string(fleetv1beta1.ResourceWorkSynchronizedConditionType), - Reason: WorkSynchronizePendingReason, + Type: string(fleetv1beta1.ResourceRolloutStartedConditionType), + Reason: condition.RolloutStartedUnknownReason, ObservedGeneration: crpGeneration, LastTransitionTime: metav1.NewTime(currentTime), }, { Status: metav1.ConditionTrue, Type: string(fleetv1beta1.ResourceScheduledConditionType), - Reason: "ScheduleSucceeded", + Reason: condition.ScheduleSucceededReason, ObservedGeneration: crpGeneration, LastTransitionTime: metav1.NewTime(currentTime), }, @@ -642,6 +466,7 @@ func TestSetPlacementStatus(t *testing.T) { }, }, { + // TODO special handling no cluster is selected name: "the placement has been scheduled for pickAll; none of clusters are selected; no clusterResourceBindings and works", latestPolicySnapshot: &fleetv1beta1.ClusterSchedulingPolicySnapshot{ ObjectMeta: metav1.ObjectMeta{ @@ -651,15 +476,6 @@ func TestSetPlacementStatus(t *testing.T) { fleetv1beta1.IsLatestSnapshotLabel: "true", fleetv1beta1.CRPTrackingLabel: testName, }, - OwnerReferences: []metav1.OwnerReference{ - { - Name: testName, - BlockOwnerDeletion: ptr.To(true), - Controller: ptr.To(true), - APIVersion: fleetAPIVersion, - Kind: "ClusterResourcePlacement", - }, - }, Annotations: map[string]string{ fleetv1beta1.NumberOfClustersAnnotation: strconv.Itoa(3), }, @@ -696,15 +512,6 @@ func TestSetPlacementStatus(t *testing.T) { fleetv1beta1.CRPTrackingLabel: testName, fleetv1beta1.IsLatestSnapshotLabel: "true", }, - OwnerReferences: []metav1.OwnerReference{ - { - Name: testName, - BlockOwnerDeletion: ptr.To(true), - Controller: ptr.To(true), - APIVersion: fleetAPIVersion, - Kind: "ClusterResourcePlacement", - }, - }, Annotations: map[string]string{ fleetv1beta1.ResourceGroupHashAnnotation: "hash", fleetv1beta1.NumberOfResourceSnapshotsAnnotation: "1", @@ -716,20 +523,6 @@ func TestSetPlacementStatus(t *testing.T) { SelectedResources: selectedResources, ObservedResourceIndex: "0", Conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementAppliedConditionType), - Reason: ResourceApplySucceededReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementSynchronizedConditionType), - Reason: SynchronizeSucceededReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, { Status: metav1.ConditionTrue, Type: string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType), @@ -752,15 +545,6 @@ func TestSetPlacementStatus(t *testing.T) { fleetv1beta1.IsLatestSnapshotLabel: "true", fleetv1beta1.CRPTrackingLabel: testName, }, - OwnerReferences: []metav1.OwnerReference{ - { - Name: testName, - BlockOwnerDeletion: ptr.To(true), - Controller: ptr.To(true), - APIVersion: fleetAPIVersion, - Kind: "ClusterResourcePlacement", - }, - }, Annotations: map[string]string{ fleetv1beta1.NumberOfClustersAnnotation: strconv.Itoa(3), }, @@ -804,15 +588,6 @@ func TestSetPlacementStatus(t *testing.T) { fleetv1beta1.CRPTrackingLabel: testName, fleetv1beta1.IsLatestSnapshotLabel: "true", }, - OwnerReferences: []metav1.OwnerReference{ - { - Name: testName, - BlockOwnerDeletion: ptr.To(true), - Controller: ptr.To(true), - APIVersion: fleetAPIVersion, - Kind: "ClusterResourcePlacement", - }, - }, Annotations: map[string]string{ fleetv1beta1.ResourceGroupHashAnnotation: "hash", fleetv1beta1.NumberOfResourceSnapshotsAnnotation: "1", @@ -826,22 +601,15 @@ func TestSetPlacementStatus(t *testing.T) { Conditions: []metav1.Condition{ { Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ClusterResourcePlacementAppliedConditionType), - Reason: ApplyPendingReason, + Type: string(fleetv1beta1.ClusterResourcePlacementRolloutStartedConditionType), + Reason: condition.RolloutStartedUnknownReason, ObservedGeneration: crpGeneration, LastTransitionTime: metav1.NewTime(currentTime), }, { Status: metav1.ConditionFalse, - Type: string(fleetv1beta1.ClusterResourcePlacementSynchronizedConditionType), - Reason: SynchronizePendingReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - { - Status: metav1.ConditionFalse, - Type: string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType), - Reason: "SchedulingFailed", + Type: string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType), + Reason: "SchedulingFailed", ObservedGeneration: crpGeneration, LastTransitionTime: metav1.NewTime(currentTime), }, @@ -852,27 +620,19 @@ func TestSetPlacementStatus(t *testing.T) { Conditions: []metav1.Condition{ { Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ResourcesAppliedConditionType), - Reason: ResourceApplyPendingReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - { - Status: metav1.ConditionFalse, - Type: string(fleetv1beta1.ResourceWorkSynchronizedConditionType), - Reason: WorkSynchronizePendingReason, + Type: string(fleetv1beta1.ResourceRolloutStartedConditionType), + Reason: condition.RolloutStartedUnknownReason, ObservedGeneration: crpGeneration, LastTransitionTime: metav1.NewTime(currentTime), }, { Status: metav1.ConditionTrue, Type: string(fleetv1beta1.ResourceScheduledConditionType), - Reason: "ScheduleSucceeded", + Reason: condition.ScheduleSucceededReason, ObservedGeneration: crpGeneration, LastTransitionTime: metav1.NewTime(currentTime), }, }, - FailedPlacements: []fleetv1beta1.FailedResourcePlacement{}, }, { Conditions: []metav1.Condition{ @@ -899,26 +659,12 @@ func TestSetPlacementStatus(t *testing.T) { }, }, }, + // TODO special handling when selected cluster is 0 { name: "the placement scheduling succeeded when numberOfClusters is 0", policy: &fleetv1beta1.PlacementPolicy{ PlacementType: fleetv1beta1.PickNPlacementType, NumberOfClusters: ptr.To(int32(0)), - Affinity: &fleetv1beta1.Affinity{ - ClusterAffinity: &fleetv1beta1.ClusterAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &fleetv1beta1.ClusterSelector{ - ClusterSelectorTerms: []fleetv1beta1.ClusterSelectorTerm{ - { - LabelSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "key1": "value1", - }, - }, - }, - }, - }, - }, - }, }, latestPolicySnapshot: &fleetv1beta1.ClusterSchedulingPolicySnapshot{ ObjectMeta: metav1.ObjectMeta{ @@ -995,13 +741,6 @@ func TestSetPlacementStatus(t *testing.T) { SelectedResources: selectedResources, ObservedResourceIndex: "0", Conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementAppliedConditionType), - Reason: ResourceApplySucceededReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, { Status: metav1.ConditionTrue, Type: string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType), @@ -1009,65 +748,15 @@ func TestSetPlacementStatus(t *testing.T) { ObservedGeneration: crpGeneration, LastTransitionTime: metav1.NewTime(currentTime), }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementSynchronizedConditionType), - Reason: SynchronizeSucceededReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, }, PlacementStatuses: []fleetv1beta1.ResourcePlacementStatus{}, }, }, { - name: "the placement status has not been changed from the last update, validating the lastTransitionTime", + name: "the placement is completed with clusterResourceBindings and works", policy: &fleetv1beta1.PlacementPolicy{ PlacementType: fleetv1beta1.PickNPlacementType, - NumberOfClusters: ptr.To(int32(0)), - Affinity: &fleetv1beta1.Affinity{ - ClusterAffinity: &fleetv1beta1.ClusterAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &fleetv1beta1.ClusterSelector{ - ClusterSelectorTerms: []fleetv1beta1.ClusterSelectorTerm{ - { - LabelSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "key1": "value1", - }, - }, - }, - }, - }, - }, - }, - }, - crpStatus: fleetv1beta1.ClusterResourcePlacementStatus{ - SelectedResources: selectedResources, - ObservedResourceIndex: "0", - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementAppliedConditionType), - Reason: ResourceApplySucceededReason, - ObservedGeneration: 1, - LastTransitionTime: oldTransitionTime, - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType), - Reason: "Scheduled", - ObservedGeneration: 1, - LastTransitionTime: oldTransitionTime, - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementSynchronizedConditionType), - Reason: SynchronizeSucceededReason, - ObservedGeneration: 1, - LastTransitionTime: oldTransitionTime, - }, - }, - PlacementStatuses: []fleetv1beta1.ResourcePlacementStatus{}, + NumberOfClusters: ptr.To(int32(1)), }, latestPolicySnapshot: &fleetv1beta1.ClusterSchedulingPolicySnapshot{ ObjectMeta: metav1.ObjectMeta{ @@ -1077,17 +766,8 @@ func TestSetPlacementStatus(t *testing.T) { fleetv1beta1.IsLatestSnapshotLabel: "true", fleetv1beta1.CRPTrackingLabel: testName, }, - OwnerReferences: []metav1.OwnerReference{ - { - Name: testName, - BlockOwnerDeletion: ptr.To(true), - Controller: ptr.To(true), - APIVersion: fleetAPIVersion, - Kind: "ClusterResourcePlacement", - }, - }, Annotations: map[string]string{ - fleetv1beta1.NumberOfClustersAnnotation: strconv.Itoa(0), + fleetv1beta1.NumberOfClustersAnnotation: strconv.Itoa(1), }, Generation: 1, }, @@ -1105,13 +785,12 @@ func TestSetPlacementStatus(t *testing.T) { ClusterDecisions: []fleetv1beta1.ClusterDecision{ { ClusterName: "member-1", - Selected: false, - Reason: "filtered", + Selected: true, + Reason: "success", }, { - ClusterName: "member-2", - Selected: false, - Reason: "filtered", + ClusterName: "member-4", + Reason: "failed", }, }, }, @@ -1124,22 +803,73 @@ func TestSetPlacementStatus(t *testing.T) { fleetv1beta1.CRPTrackingLabel: testName, fleetv1beta1.IsLatestSnapshotLabel: "true", }, - OwnerReferences: []metav1.OwnerReference{ - { - Name: testName, - BlockOwnerDeletion: ptr.To(true), - Controller: ptr.To(true), - APIVersion: fleetAPIVersion, - Kind: "ClusterResourcePlacement", - }, - }, Annotations: map[string]string{ fleetv1beta1.ResourceGroupHashAnnotation: "hash", - fleetv1beta1.NumberOfResourceSnapshotsAnnotation: "0", + fleetv1beta1.NumberOfResourceSnapshotsAnnotation: "1", }, }, }, - want: false, + clusterResourceBindings: []fleetv1beta1.ClusterResourceBinding{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "binding-1", + Labels: map[string]string{ + fleetv1beta1.CRPTrackingLabel: testName, + }, + Generation: 1, + }, + Spec: fleetv1beta1.ResourceBindingSpec{ + ResourceSnapshotName: fmt.Sprintf(fleetv1beta1.ResourceSnapshotNameFmt, testName, 0), + ResourceOverrideSnapshots: []fleetv1beta1.NamespacedName{ + { + Name: "override-1", + Namespace: "override-ns", + }, + { + Name: "override-2", + }, + }, + ClusterResourceOverrideSnapshots: []string{"o-1", "o-2"}, + SchedulingPolicySnapshotName: fmt.Sprintf(fleetv1beta1.PolicySnapshotNameFmt, testName, 0), + TargetCluster: "member-1", + }, + Status: fleetv1beta1.ResourceBindingStatus{ + Conditions: []metav1.Condition{ + { + Status: metav1.ConditionTrue, + Type: string(fleetv1beta1.ResourceBindingRolloutStarted), + Reason: condition.RolloutStartedReason, + ObservedGeneration: 1, + }, + { + Status: metav1.ConditionTrue, + Type: string(fleetv1beta1.ResourceBindingOverridden), + Reason: condition.OverriddenSucceededReason, + ObservedGeneration: 1, + }, + { + Status: metav1.ConditionTrue, + Type: string(fleetv1beta1.ResourceBindingWorkSynchronized), + Reason: condition.WorkSynchronizedReason, + ObservedGeneration: 1, + }, + { + Status: metav1.ConditionTrue, + Type: string(fleetv1beta1.ResourceBindingApplied), + Reason: condition.ApplySucceededReason, + ObservedGeneration: 1, + }, + { + Status: metav1.ConditionTrue, + Type: string(fleetv1beta1.ResourceBindingAvailable), + Reason: condition.AvailableReason, + ObservedGeneration: 1, + }, + }, + }, + }, + }, + want: true, wantStatus: &fleetv1beta1.ClusterResourcePlacementStatus{ SelectedResources: selectedResources, ObservedResourceIndex: "0", @@ -1147,1973 +877,99 @@ func TestSetPlacementStatus(t *testing.T) { { Status: metav1.ConditionTrue, Type: string(fleetv1beta1.ClusterResourcePlacementAppliedConditionType), - Reason: ResourceApplySucceededReason, + Reason: condition.ApplySucceededReason, ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, + LastTransitionTime: metav1.NewTime(currentTime), }, { Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType), - Reason: "Scheduled", + Type: string(fleetv1beta1.ClusterResourcePlacementAvailableConditionType), + Reason: condition.AvailableReason, ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, + LastTransitionTime: metav1.NewTime(currentTime), }, { Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementSynchronizedConditionType), - Reason: SynchronizeSucceededReason, + Type: string(fleetv1beta1.ClusterResourcePlacementOverriddenConditionType), + Reason: condition.OverriddenSucceededReason, ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - }, - PlacementStatuses: []fleetv1beta1.ResourcePlacementStatus{}, - }, - }, - { - name: "the placement status has been changed from the last update, validating the lastTransitionTime", - policy: &fleetv1beta1.PlacementPolicy{ - PlacementType: fleetv1beta1.PickNPlacementType, - NumberOfClusters: ptr.To(int32(0)), - Affinity: &fleetv1beta1.Affinity{ - ClusterAffinity: &fleetv1beta1.ClusterAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &fleetv1beta1.ClusterSelector{ - ClusterSelectorTerms: []fleetv1beta1.ClusterSelectorTerm{ - { - LabelSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "key1": "value1", - }, - }, - }, - }, - }, + LastTransitionTime: metav1.NewTime(currentTime), }, - }, - }, - crpStatus: fleetv1beta1.ClusterResourcePlacementStatus{ - SelectedResources: selectedResources, - ObservedResourceIndex: "0", - Conditions: []metav1.Condition{ { - Status: metav1.ConditionFalse, - Type: string(fleetv1beta1.ClusterResourcePlacementAppliedConditionType), - Reason: ResourceApplySucceededReason, - ObservedGeneration: 1, - LastTransitionTime: oldTransitionTime, + Status: metav1.ConditionTrue, + Type: string(fleetv1beta1.ClusterResourcePlacementRolloutStartedConditionType), + Reason: condition.RolloutStartedReason, + ObservedGeneration: crpGeneration, + LastTransitionTime: metav1.NewTime(currentTime), }, { Status: metav1.ConditionTrue, Type: string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType), Reason: "Scheduled", - ObservedGeneration: 1, - LastTransitionTime: oldTransitionTime, + ObservedGeneration: crpGeneration, + LastTransitionTime: metav1.NewTime(currentTime), }, { - Status: metav1.ConditionFalse, - Type: string(fleetv1beta1.ClusterResourcePlacementSynchronizedConditionType), - Reason: SynchronizeSucceededReason, - ObservedGeneration: 1, - LastTransitionTime: oldTransitionTime, + Status: metav1.ConditionTrue, + Type: string(fleetv1beta1.ClusterResourcePlacementWorkSynchronizedConditionType), + Reason: condition.WorkSynchronizedReason, + ObservedGeneration: crpGeneration, + LastTransitionTime: metav1.NewTime(currentTime), }, }, - PlacementStatuses: []fleetv1beta1.ResourcePlacementStatus{}, - }, - latestPolicySnapshot: &fleetv1beta1.ClusterSchedulingPolicySnapshot{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf(fleetv1beta1.PolicySnapshotNameFmt, testName, 0), - Labels: map[string]string{ - fleetv1beta1.PolicyIndexLabel: "0", - fleetv1beta1.IsLatestSnapshotLabel: "true", - fleetv1beta1.CRPTrackingLabel: testName, - }, - OwnerReferences: []metav1.OwnerReference{ - { - Name: testName, - BlockOwnerDeletion: ptr.To(true), - Controller: ptr.To(true), - APIVersion: fleetAPIVersion, - Kind: "ClusterResourcePlacement", + PlacementStatuses: []fleetv1beta1.ResourcePlacementStatus{ + { + ClusterName: "member-1", + ApplicableClusterResourceOverrides: []string{"o-1", "o-2"}, + ApplicableResourceOverrides: []fleetv1beta1.NamespacedName{ + { + Name: "override-1", + Namespace: "override-ns", + }, + { + Name: "override-2", + }, }, - }, - Annotations: map[string]string{ - fleetv1beta1.NumberOfClustersAnnotation: strconv.Itoa(0), - }, - Generation: 1, - }, - Status: fleetv1beta1.SchedulingPolicySnapshotStatus{ - ObservedCRPGeneration: crpGeneration, - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.PolicySnapshotScheduled), - Reason: "Scheduled", - Message: "message", - ObservedGeneration: 1, - }, - }, - ClusterDecisions: []fleetv1beta1.ClusterDecision{ - { - ClusterName: "member-1", - Selected: false, - Reason: "filtered", - }, - { - ClusterName: "member-2", - Selected: false, - Reason: "filtered", - }, - }, - }, - }, - latestResourceSnapshot: &fleetv1beta1.ClusterResourceSnapshot{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf(fleetv1beta1.ResourceSnapshotNameFmt, testName, 0), - Labels: map[string]string{ - fleetv1beta1.ResourceIndexLabel: "0", - fleetv1beta1.CRPTrackingLabel: testName, - fleetv1beta1.IsLatestSnapshotLabel: "true", - }, - OwnerReferences: []metav1.OwnerReference{ - { - Name: testName, - BlockOwnerDeletion: ptr.To(true), - Controller: ptr.To(true), - APIVersion: fleetAPIVersion, - Kind: "ClusterResourcePlacement", - }, - }, - Annotations: map[string]string{ - fleetv1beta1.ResourceGroupHashAnnotation: "hash", - fleetv1beta1.NumberOfResourceSnapshotsAnnotation: "0", - }, - }, - }, - want: false, - wantStatus: &fleetv1beta1.ClusterResourcePlacementStatus{ - SelectedResources: selectedResources, - ObservedResourceIndex: "0", - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementAppliedConditionType), - Reason: ResourceApplySucceededReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType), - Reason: "Scheduled", - ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementSynchronizedConditionType), - Reason: SynchronizeSucceededReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - }, - PlacementStatuses: []fleetv1beta1.ResourcePlacementStatus{}, - }, - }, - { - name: "the placement has been applied", - policy: placementPolicyForTest(), - latestPolicySnapshot: &fleetv1beta1.ClusterSchedulingPolicySnapshot{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf(fleetv1beta1.PolicySnapshotNameFmt, testName, 0), - Labels: map[string]string{ - fleetv1beta1.PolicyIndexLabel: "0", - fleetv1beta1.IsLatestSnapshotLabel: "true", - fleetv1beta1.CRPTrackingLabel: testName, - }, - OwnerReferences: []metav1.OwnerReference{ - { - Name: testName, - BlockOwnerDeletion: ptr.To(true), - Controller: ptr.To(true), - APIVersion: fleetAPIVersion, - Kind: "ClusterResourcePlacement", - }, - }, - Annotations: map[string]string{ - fleetv1beta1.NumberOfClustersAnnotation: strconv.Itoa(3), - }, - Generation: 1, - }, - Status: fleetv1beta1.SchedulingPolicySnapshotStatus{ - ObservedCRPGeneration: crpGeneration, - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.PolicySnapshotScheduled), - Reason: "Scheduled", - Message: "message", - ObservedGeneration: 1, - }, - }, - ClusterDecisions: []fleetv1beta1.ClusterDecision{ - { - ClusterName: cluster1Name, - Selected: true, - Reason: "success", - }, - { - ClusterName: cluster2Name, - Selected: true, - Reason: "success", - }, - }, - }, - }, - latestResourceSnapshot: &fleetv1beta1.ClusterResourceSnapshot{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf(fleetv1beta1.ResourceSnapshotNameFmt, testName, 0), - Labels: map[string]string{ - fleetv1beta1.ResourceIndexLabel: "0", - fleetv1beta1.CRPTrackingLabel: testName, - fleetv1beta1.IsLatestSnapshotLabel: "true", - }, - OwnerReferences: []metav1.OwnerReference{ - { - Name: testName, - BlockOwnerDeletion: ptr.To(true), - Controller: ptr.To(true), - APIVersion: fleetAPIVersion, - Kind: "ClusterResourcePlacement", - }, - }, - Annotations: map[string]string{ - fleetv1beta1.ResourceGroupHashAnnotation: "hash", - fleetv1beta1.NumberOfResourceSnapshotsAnnotation: "1", - }, - }, - }, - clusterResourceBindings: []fleetv1beta1.ClusterResourceBinding{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "binding-1", - Labels: map[string]string{ - fleetv1beta1.CRPTrackingLabel: testName, - }, - Generation: 1, - }, - Spec: fleetv1beta1.ResourceBindingSpec{ - State: fleetv1beta1.BindingStateBound, - ResourceSnapshotName: fmt.Sprintf(fleetv1beta1.ResourceSnapshotNameFmt, testName, 0), - SchedulingPolicySnapshotName: fmt.Sprintf(fleetv1beta1.PolicySnapshotNameFmt, testName, 0), - TargetCluster: cluster1Name, - }, - Status: fleetv1beta1.ResourceBindingStatus{ - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourceBindingBound), - Reason: "resourceBindingTrue", - ObservedGeneration: 1, - LastTransitionTime: oldTransitionTime, - }, - }, - }, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Name: "binding-2", - Labels: map[string]string{ - fleetv1beta1.CRPTrackingLabel: testName, - }, - Generation: 1, - }, - Spec: fleetv1beta1.ResourceBindingSpec{ - State: fleetv1beta1.BindingStateBound, - ResourceSnapshotName: fmt.Sprintf(fleetv1beta1.ResourceSnapshotNameFmt, testName, 0), - SchedulingPolicySnapshotName: fmt.Sprintf(fleetv1beta1.PolicySnapshotNameFmt, testName, 0), - TargetCluster: cluster2Name, - }, - Status: fleetv1beta1.ResourceBindingStatus{ - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourceBindingBound), - Reason: "resourceBindingTrue", - ObservedGeneration: 1, - LastTransitionTime: oldTransitionTime, - }, - }, - }, - }, - }, - works: []fleetv1beta1.Work{ - { - ObjectMeta: metav1.ObjectMeta{ - Namespace: fmt.Sprintf(utils.NamespaceNameFormat, cluster1Name), - Name: "work-1", - Labels: map[string]string{ - fleetv1beta1.ParentResourceSnapshotIndexLabel: "0", - fleetv1beta1.CRPTrackingLabel: testName, - }, - Generation: 1, - }, - Status: fleetv1beta1.WorkStatus{ - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: fleetv1beta1.WorkConditionTypeApplied, - Reason: "applied", - ObservedGeneration: 1, - LastTransitionTime: oldTransitionTime, - }, - }, - }, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Namespace: fmt.Sprintf(utils.NamespaceNameFormat, cluster2Name), - Name: "work-1", - Labels: map[string]string{ - fleetv1beta1.ParentResourceSnapshotIndexLabel: "0", - fleetv1beta1.CRPTrackingLabel: testName, - }, - Generation: 1, - }, - Status: fleetv1beta1.WorkStatus{ - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: fleetv1beta1.WorkConditionTypeApplied, - Reason: "applied", - ObservedGeneration: 1, - LastTransitionTime: oldTransitionTime, - }, - }, - }, - }, - }, - want: true, - wantStatus: &fleetv1beta1.ClusterResourcePlacementStatus{ - SelectedResources: selectedResources, - ObservedResourceIndex: "0", - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementAppliedConditionType), - Reason: ResourceApplySucceededReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType), - Reason: "Scheduled", - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementSynchronizedConditionType), - Reason: SynchronizeSucceededReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - }, - PlacementStatuses: []fleetv1beta1.ResourcePlacementStatus{ - { - ClusterName: cluster1Name, - FailedPlacements: []fleetv1beta1.FailedResourcePlacement{}, Conditions: []metav1.Condition{ { Status: metav1.ConditionTrue, Type: string(fleetv1beta1.ResourcesAppliedConditionType), - Reason: ResourceApplySucceededReason, + Reason: condition.ApplySucceededReason, ObservedGeneration: crpGeneration, LastTransitionTime: metav1.NewTime(currentTime), }, { Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourceWorkSynchronizedConditionType), - Reason: WorkSynchronizeSucceededReason, + Type: string(fleetv1beta1.ResourcesAvailableConditionType), + Reason: condition.AvailableReason, ObservedGeneration: crpGeneration, LastTransitionTime: metav1.NewTime(currentTime), }, { Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourceScheduledConditionType), - Reason: "ScheduleSucceeded", - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - }, - }, - { - ClusterName: cluster2Name, - FailedPlacements: []fleetv1beta1.FailedResourcePlacement{}, - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourcesAppliedConditionType), - Reason: ResourceApplySucceededReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourceWorkSynchronizedConditionType), - Reason: WorkSynchronizeSucceededReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourceScheduledConditionType), - Reason: "ScheduleSucceeded", - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - }, - }, - }, - }, - }, - { - name: "the placement has not been synced, validating the lastTransitionTime", - crpStatus: fleetv1beta1.ClusterResourcePlacementStatus{ - ObservedResourceIndex: "0", - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ClusterResourcePlacementAppliedConditionType), - Reason: ApplyPendingReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType), - Reason: "Scheduled", - ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - { - Status: metav1.ConditionFalse, - Type: string(fleetv1beta1.ClusterResourcePlacementSynchronizedConditionType), - Reason: SynchronizePendingReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - }, - PlacementStatuses: []fleetv1beta1.ResourcePlacementStatus{ - { - ClusterName: cluster1Name, - FailedPlacements: []fleetv1beta1.FailedResourcePlacement{}, - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourcesAppliedConditionType), - Reason: ResourceApplySucceededReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourceWorkSynchronizedConditionType), - Reason: WorkSynchronizeSucceededReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourceScheduledConditionType), - Reason: "ScheduleSucceeded", - ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - }, - }, - { - ClusterName: cluster2Name, - FailedPlacements: []fleetv1beta1.FailedResourcePlacement{}, - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ResourcesAppliedConditionType), - Reason: ResourceApplyPendingReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - { - Status: metav1.ConditionFalse, - Type: string(fleetv1beta1.ResourceWorkSynchronizedConditionType), - Reason: WorkSynchronizePendingReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourceScheduledConditionType), - Reason: "ScheduleSucceeded", - ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - }, - }, - }, - }, - policy: placementPolicyForTest(), - latestPolicySnapshot: &fleetv1beta1.ClusterSchedulingPolicySnapshot{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf(fleetv1beta1.PolicySnapshotNameFmt, testName, 0), - Labels: map[string]string{ - fleetv1beta1.PolicyIndexLabel: "0", - fleetv1beta1.IsLatestSnapshotLabel: "true", - fleetv1beta1.CRPTrackingLabel: testName, - }, - OwnerReferences: []metav1.OwnerReference{ - { - Name: testName, - BlockOwnerDeletion: ptr.To(true), - Controller: ptr.To(true), - APIVersion: fleetAPIVersion, - Kind: "ClusterResourcePlacement", - }, - }, - Annotations: map[string]string{ - fleetv1beta1.NumberOfClustersAnnotation: strconv.Itoa(3), - }, - Generation: 1, - }, - Status: fleetv1beta1.SchedulingPolicySnapshotStatus{ - ObservedCRPGeneration: crpGeneration, - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.PolicySnapshotScheduled), - Reason: "Scheduled", - Message: "message", - ObservedGeneration: 1, - }, - }, - ClusterDecisions: []fleetv1beta1.ClusterDecision{ - { - ClusterName: cluster1Name, - Selected: true, - Reason: "success", - }, - { - ClusterName: cluster2Name, - Selected: true, - Reason: "success", - }, - }, - }, - }, - latestResourceSnapshot: &fleetv1beta1.ClusterResourceSnapshot{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf(fleetv1beta1.ResourceSnapshotNameFmt, testName, 0), - Labels: map[string]string{ - fleetv1beta1.ResourceIndexLabel: "0", - fleetv1beta1.CRPTrackingLabel: testName, - fleetv1beta1.IsLatestSnapshotLabel: "true", - }, - OwnerReferences: []metav1.OwnerReference{ - { - Name: testName, - BlockOwnerDeletion: ptr.To(true), - Controller: ptr.To(true), - APIVersion: fleetAPIVersion, - Kind: "ClusterResourcePlacement", - }, - }, - Annotations: map[string]string{ - fleetv1beta1.ResourceGroupHashAnnotation: "hash", - fleetv1beta1.NumberOfResourceSnapshotsAnnotation: "1", - }, - }, - }, - clusterResourceBindings: []fleetv1beta1.ClusterResourceBinding{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "binding-1", - Labels: map[string]string{ - fleetv1beta1.CRPTrackingLabel: testName, - }, - Generation: 1, - }, - Spec: fleetv1beta1.ResourceBindingSpec{ - State: fleetv1beta1.BindingStateBound, - ResourceSnapshotName: fmt.Sprintf(fleetv1beta1.ResourceSnapshotNameFmt, testName, 0), - SchedulingPolicySnapshotName: fmt.Sprintf(fleetv1beta1.PolicySnapshotNameFmt, testName, 0), - TargetCluster: cluster1Name, - }, - Status: fleetv1beta1.ResourceBindingStatus{ - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionFalse, - Type: string(fleetv1beta1.ResourceBindingBound), - Reason: "resourceBindingTrue", - ObservedGeneration: 1, - LastTransitionTime: oldTransitionTime, - }, - }, - }, - }, - }, - want: true, - wantStatus: &fleetv1beta1.ClusterResourcePlacementStatus{ - SelectedResources: selectedResources, - ObservedResourceIndex: "0", - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ClusterResourcePlacementAppliedConditionType), - Reason: ApplyPendingReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType), - Reason: "Scheduled", - ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - { - Status: metav1.ConditionFalse, - Type: string(fleetv1beta1.ClusterResourcePlacementSynchronizedConditionType), - Reason: SynchronizePendingReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - }, - PlacementStatuses: []fleetv1beta1.ResourcePlacementStatus{ - { - ClusterName: cluster1Name, - FailedPlacements: []fleetv1beta1.FailedResourcePlacement{}, - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ResourcesAppliedConditionType), - Reason: ResourceApplyPendingReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - { - Status: metav1.ConditionFalse, - Type: string(fleetv1beta1.ResourceWorkSynchronizedConditionType), - Reason: WorkSynchronizeFailedReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourceScheduledConditionType), - Reason: "ScheduleSucceeded", - ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - }, - }, - { - ClusterName: cluster2Name, - FailedPlacements: []fleetv1beta1.FailedResourcePlacement{}, - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ResourcesAppliedConditionType), - Reason: ResourceApplyPendingReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - { - Status: metav1.ConditionFalse, - Type: string(fleetv1beta1.ResourceWorkSynchronizedConditionType), - Reason: WorkSynchronizePendingReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourceScheduledConditionType), - Reason: "ScheduleSucceeded", - ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - }, - }, - }, - }, - }, - { - name: "the placement apply failed in one of the cluster, validating the lastTransitionTime", - crpStatus: fleetv1beta1.ClusterResourcePlacementStatus{ - ObservedResourceIndex: "0", - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ClusterResourcePlacementAppliedConditionType), - Reason: ApplyPendingReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType), - Reason: "Scheduled", - ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - { - Status: metav1.ConditionFalse, - Type: string(fleetv1beta1.ClusterResourcePlacementSynchronizedConditionType), - Reason: SynchronizePendingReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - }, - PlacementStatuses: []fleetv1beta1.ResourcePlacementStatus{ - { - ClusterName: cluster1Name, - FailedPlacements: []fleetv1beta1.FailedResourcePlacement{}, - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourcesAppliedConditionType), - Reason: ResourceApplySucceededReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourceWorkSynchronizedConditionType), - Reason: WorkSynchronizeSucceededReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourceScheduledConditionType), - Reason: "ScheduleSucceeded", - ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - }, - }, - { - ClusterName: cluster2Name, - FailedPlacements: []fleetv1beta1.FailedResourcePlacement{}, - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ResourcesAppliedConditionType), - Reason: ResourceApplyPendingReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - { - Status: metav1.ConditionFalse, - Type: string(fleetv1beta1.ResourceWorkSynchronizedConditionType), - Reason: WorkSynchronizePendingReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourceScheduledConditionType), - Reason: "ScheduleSucceeded", - ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - }, - }, - }, - }, - policy: placementPolicyForTest(), - latestPolicySnapshot: &fleetv1beta1.ClusterSchedulingPolicySnapshot{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf(fleetv1beta1.PolicySnapshotNameFmt, testName, 0), - Labels: map[string]string{ - fleetv1beta1.PolicyIndexLabel: "0", - fleetv1beta1.IsLatestSnapshotLabel: "true", - fleetv1beta1.CRPTrackingLabel: testName, - }, - OwnerReferences: []metav1.OwnerReference{ - { - Name: testName, - BlockOwnerDeletion: ptr.To(true), - Controller: ptr.To(true), - APIVersion: fleetAPIVersion, - Kind: "ClusterResourcePlacement", - }, - }, - Annotations: map[string]string{ - fleetv1beta1.NumberOfClustersAnnotation: strconv.Itoa(3), - }, - Generation: 1, - }, - Status: fleetv1beta1.SchedulingPolicySnapshotStatus{ - ObservedCRPGeneration: crpGeneration, - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.PolicySnapshotScheduled), - Reason: "Scheduled", - Message: "message", - ObservedGeneration: 1, - }, - }, - ClusterDecisions: []fleetv1beta1.ClusterDecision{ - { - ClusterName: cluster1Name, - Selected: true, - Reason: "success", - }, - { - ClusterName: cluster2Name, - Selected: true, - Reason: "success", - }, - }, - }, - }, - latestResourceSnapshot: &fleetv1beta1.ClusterResourceSnapshot{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf(fleetv1beta1.ResourceSnapshotNameFmt, testName, 0), - Labels: map[string]string{ - fleetv1beta1.ResourceIndexLabel: "0", - fleetv1beta1.CRPTrackingLabel: testName, - fleetv1beta1.IsLatestSnapshotLabel: "true", - }, - OwnerReferences: []metav1.OwnerReference{ - { - Name: testName, - BlockOwnerDeletion: ptr.To(true), - Controller: ptr.To(true), - APIVersion: fleetAPIVersion, - Kind: "ClusterResourcePlacement", - }, - }, - Annotations: map[string]string{ - fleetv1beta1.ResourceGroupHashAnnotation: "hash", - fleetv1beta1.NumberOfResourceSnapshotsAnnotation: "1", - }, - }, - }, - clusterResourceBindings: []fleetv1beta1.ClusterResourceBinding{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "binding-1", - Labels: map[string]string{ - fleetv1beta1.CRPTrackingLabel: testName, - }, - Generation: 1, - }, - Spec: fleetv1beta1.ResourceBindingSpec{ - State: fleetv1beta1.BindingStateBound, - ResourceSnapshotName: "not-latest-snapshot", - SchedulingPolicySnapshotName: fmt.Sprintf(fleetv1beta1.PolicySnapshotNameFmt, testName, 0), - TargetCluster: cluster1Name, - }, - Status: fleetv1beta1.ResourceBindingStatus{ - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourceBindingBound), - Reason: "resourceBindingTrue", - ObservedGeneration: 1, - LastTransitionTime: oldTransitionTime, - }, - }, - }, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Name: "binding-2", - Labels: map[string]string{ - fleetv1beta1.CRPTrackingLabel: testName, - }, - Generation: 1, - }, - Spec: fleetv1beta1.ResourceBindingSpec{ - State: fleetv1beta1.BindingStateBound, - ResourceSnapshotName: fmt.Sprintf(fleetv1beta1.ResourceSnapshotNameFmt, testName, 0), - SchedulingPolicySnapshotName: fmt.Sprintf(fleetv1beta1.PolicySnapshotNameFmt, testName, 0), - TargetCluster: cluster2Name, - }, - Status: fleetv1beta1.ResourceBindingStatus{ - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourceBindingBound), - Reason: "resourceBindingTrue", - ObservedGeneration: 1, - LastTransitionTime: oldTransitionTime, - }, - }, - }, - }, - }, - works: []fleetv1beta1.Work{ - { - ObjectMeta: metav1.ObjectMeta{ - Namespace: fmt.Sprintf(utils.NamespaceNameFormat, cluster2Name), - Name: "work-2", - Labels: map[string]string{ - fleetv1beta1.ParentResourceSnapshotIndexLabel: "0", - fleetv1beta1.CRPTrackingLabel: testName, - }, - Generation: 1, - }, - Status: fleetv1beta1.WorkStatus{ - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionFalse, - Type: fleetv1beta1.WorkConditionTypeApplied, - Reason: "applied", - ObservedGeneration: 1, - LastTransitionTime: oldTransitionTime, - }, - }, - ManifestConditions: []fleetv1beta1.ManifestCondition{ - { - Identifier: fleetv1beta1.WorkResourceIdentifier{ - Version: "v1", - Kind: "Configmap", - Namespace: "test", - Name: "test-1", - }, - Conditions: []metav1.Condition{ - { - Type: fleetv1beta1.WorkConditionTypeApplied, - Status: metav1.ConditionFalse, - LastTransitionTime: oldTransitionTime, - ObservedGeneration: 1, - }, - }, - }, - }, - }, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Namespace: fmt.Sprintf(utils.NamespaceNameFormat, cluster2Name), - Name: "work-3", - Labels: map[string]string{ - fleetv1beta1.ParentResourceSnapshotIndexLabel: "0", - fleetv1beta1.CRPTrackingLabel: testName, - fleetv1beta1.EnvelopeNameLabel: "envelope-1", - fleetv1beta1.EnvelopeNamespaceLabel: "envelope-ns", - fleetv1beta1.EnvelopeTypeLabel: string(fleetv1beta1.ConfigMapEnvelopeType), - }, - Generation: 1, - }, - Status: fleetv1beta1.WorkStatus{ - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionFalse, - Type: fleetv1beta1.WorkConditionTypeApplied, - Reason: "applied", - ObservedGeneration: 1, - LastTransitionTime: oldTransitionTime, - }, - }, - ManifestConditions: []fleetv1beta1.ManifestCondition{ - { - Identifier: fleetv1beta1.WorkResourceIdentifier{ - Version: "v1", - Kind: "Other", - Name: "test-2", - }, - Conditions: []metav1.Condition{ - { - Type: fleetv1beta1.WorkConditionTypeApplied, - Status: metav1.ConditionFalse, - LastTransitionTime: oldTransitionTime, - ObservedGeneration: 1, - }, - }, - }, - }, - }, - }, - }, - want: true, - wantStatus: &fleetv1beta1.ClusterResourcePlacementStatus{ - SelectedResources: selectedResources, - ObservedResourceIndex: "0", - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ClusterResourcePlacementAppliedConditionType), - Reason: ApplyPendingReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType), - Reason: "Scheduled", - ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - { - Status: metav1.ConditionFalse, - Type: string(fleetv1beta1.ClusterResourcePlacementSynchronizedConditionType), - Reason: SynchronizePendingReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - }, - PlacementStatuses: []fleetv1beta1.ResourcePlacementStatus{ - { - ClusterName: cluster1Name, - FailedPlacements: []fleetv1beta1.FailedResourcePlacement{}, - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ResourcesAppliedConditionType), - Reason: ResourceApplyPendingReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - { - Status: metav1.ConditionFalse, - Type: string(fleetv1beta1.ResourceWorkSynchronizedConditionType), - Reason: WorkSynchronizePendingReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourceScheduledConditionType), - Reason: "ScheduleSucceeded", - ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - }, - }, - { - ClusterName: cluster2Name, - FailedPlacements: []fleetv1beta1.FailedResourcePlacement{ - { - ResourceIdentifier: fleetv1beta1.ResourceIdentifier{ - Version: "v1", - Kind: "Configmap", - Namespace: "test", - Name: "test-1", - }, - Condition: metav1.Condition{ - Type: fleetv1beta1.WorkConditionTypeApplied, - Status: metav1.ConditionFalse, - LastTransitionTime: oldTransitionTime, - ObservedGeneration: 1, - }, - }, - { - ResourceIdentifier: fleetv1beta1.ResourceIdentifier{ - Version: "v1", - Kind: "Other", - Name: "test-2", - Envelope: &fleetv1beta1.EnvelopeIdentifier{ - Name: "envelope-1", - Namespace: "envelope-ns", - Type: fleetv1beta1.ConfigMapEnvelopeType, - }, - }, - Condition: metav1.Condition{ - Type: fleetv1beta1.WorkConditionTypeApplied, - Status: metav1.ConditionFalse, - LastTransitionTime: oldTransitionTime, - ObservedGeneration: 1, - }, - }, - }, - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionFalse, - Type: string(fleetv1beta1.ResourcesAppliedConditionType), - Reason: ResourceApplyFailedReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourceWorkSynchronizedConditionType), - Reason: WorkSynchronizeSucceededReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourceScheduledConditionType), - Reason: "ScheduleSucceeded", - ObservedGeneration: crpGeneration, - LastTransitionTime: oldTransitionTime, - }, - }, - }, - }, - }, - }, - // TODO add more tests - } - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - crp := &fleetv1beta1.ClusterResourcePlacement{ - ObjectMeta: metav1.ObjectMeta{ - Name: testName, - }, - Spec: fleetv1beta1.ClusterResourcePlacementSpec{ - ResourceSelectors: []fleetv1beta1.ClusterResourceSelector{ - { - Group: corev1.GroupName, - Version: "v1", - Kind: "Service", - LabelSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{"region": "east"}, - }, - }, - }, - Policy: tc.policy, - }, - Status: tc.crpStatus, - } - scheme := serviceScheme(t) - var objects []client.Object - for i := range tc.clusterResourceBindings { - objects = append(objects, &tc.clusterResourceBindings[i]) - } - for i := range tc.works { - objects = append(objects, &tc.works[i]) - } - fakeClient := fake.NewClientBuilder(). - WithScheme(scheme). - WithObjects(objects...). - Build() - r := Reconciler{ - Client: fakeClient, - Scheme: scheme, - Recorder: record.NewFakeRecorder(10), - } - crp.Generation = crpGeneration - got, err := r.setPlacementStatus(context.Background(), crp, selectedResources, tc.latestPolicySnapshot, tc.latestResourceSnapshot) - if err != nil { - t.Fatalf("setPlacementStatus() failed: %v", err) - } - if got != tc.want { - t.Errorf("setPlacementStatus() = %v, want %v", got, tc.want) - } - - if diff := cmp.Diff(tc.wantStatus, &crp.Status, statusCmpOptions...); diff != "" { - t.Errorf("buildPlacementStatus() status mismatch (-want, +got):\n%s", diff) - } - }) - } -} - -func TestBuildFailedResourcePlacements(t *testing.T) { - tests := map[string]struct { - work *fleetv1beta1.Work - wantIsPending bool - wantRes []fleetv1beta1.FailedResourcePlacement - }{ - "pending if not applied": { - work: &fleetv1beta1.Work{}, - wantIsPending: true, - wantRes: nil, - }, - "No resource if applied successfully": { - work: &fleetv1beta1.Work{ - ObjectMeta: metav1.ObjectMeta{ - Generation: 1, - }, - Status: fleetv1beta1.WorkStatus{ - Conditions: []metav1.Condition{ - { - Type: fleetv1beta1.WorkConditionTypeApplied, - ObservedGeneration: 1, - Status: metav1.ConditionTrue, - }, - }, - }, - }, - wantIsPending: false, - wantRes: nil, - }, - "pending if applied not on the latest generation": { - work: &fleetv1beta1.Work{ - ObjectMeta: metav1.ObjectMeta{ - Generation: 2, - }, - Status: fleetv1beta1.WorkStatus{ - Conditions: []metav1.Condition{ - { - Type: fleetv1beta1.WorkConditionTypeApplied, - ObservedGeneration: 1, - Status: metav1.ConditionTrue, - }, - }, - }, - }, - wantIsPending: true, - wantRes: nil, - }, - "report failure if applied failed with multiple object": { - work: &fleetv1beta1.Work{ - ObjectMeta: metav1.ObjectMeta{ - Generation: 1, - }, - Status: fleetv1beta1.WorkStatus{ - Conditions: []metav1.Condition{ - { - Type: fleetv1beta1.WorkConditionTypeApplied, - ObservedGeneration: 1, - Status: metav1.ConditionFalse, - }, - }, - ManifestConditions: []fleetv1beta1.ManifestCondition{ - { - Identifier: fleetv1beta1.WorkResourceIdentifier{ - Ordinal: 1, - Group: corev1.GroupName, - Version: "v1", - Kind: "secret", - Name: "secretName", - Namespace: "app", - }, - Conditions: []metav1.Condition{ - { - Type: fleetv1beta1.WorkConditionTypeApplied, - ObservedGeneration: 1, - Status: metav1.ConditionFalse, - }, - }, - }, - { - Identifier: fleetv1beta1.WorkResourceIdentifier{ - Ordinal: 1, - Group: corev1.GroupName, - Version: "v1", - Kind: "pod", - Name: "secretPod", - Namespace: "app", - }, - Conditions: []metav1.Condition{ - { - Type: fleetv1beta1.WorkConditionTypeApplied, - ObservedGeneration: 2, - Status: metav1.ConditionFalse, - }, - }, - }, - }, - }, - }, - wantIsPending: false, - wantRes: []fleetv1beta1.FailedResourcePlacement{ - { - ResourceIdentifier: fleetv1beta1.ResourceIdentifier{ - Group: corev1.GroupName, - Version: "v1", - Kind: "secret", - Name: "secretName", - Namespace: "app", - }, - Condition: metav1.Condition{ - Type: fleetv1beta1.WorkConditionTypeApplied, - ObservedGeneration: 1, - Status: metav1.ConditionFalse, - }, - }, - { - ResourceIdentifier: fleetv1beta1.ResourceIdentifier{ - Group: corev1.GroupName, - Version: "v1", - Kind: "pod", - Name: "secretPod", - Namespace: "app", - }, - Condition: metav1.Condition{ - Type: fleetv1beta1.WorkConditionTypeApplied, - ObservedGeneration: 2, - Status: metav1.ConditionFalse, - }, - }, - }, - }, - "report failure if applied failed with an envelop object": { - work: &fleetv1beta1.Work{ - ObjectMeta: metav1.ObjectMeta{ - Generation: 1, - Labels: map[string]string{ - fleetv1beta1.ParentBindingLabel: "bindingName", - fleetv1beta1.CRPTrackingLabel: "testCRPName", - fleetv1beta1.EnvelopeTypeLabel: string(fleetv1beta1.ConfigMapEnvelopeType), - fleetv1beta1.EnvelopeNameLabel: "envelop-configmap", - fleetv1beta1.EnvelopeNamespaceLabel: "app", - }, - }, - Status: fleetv1beta1.WorkStatus{ - Conditions: []metav1.Condition{ - { - Type: fleetv1beta1.WorkConditionTypeApplied, - ObservedGeneration: 1, - Status: metav1.ConditionFalse, - }, - }, - ManifestConditions: []fleetv1beta1.ManifestCondition{ - { - Identifier: fleetv1beta1.WorkResourceIdentifier{ - Ordinal: 1, - Group: corev1.GroupName, - Version: "v1", - Kind: "secret", - Name: "secretName", - Namespace: "app", - }, - Conditions: []metav1.Condition{ - { - Type: fleetv1beta1.WorkConditionTypeApplied, - ObservedGeneration: 1, - Status: metav1.ConditionFalse, - }, - }, - }, - }, - }, - }, - wantIsPending: false, - wantRes: []fleetv1beta1.FailedResourcePlacement{ - { - ResourceIdentifier: fleetv1beta1.ResourceIdentifier{ - Group: corev1.GroupName, - Version: "v1", - Kind: "secret", - Name: "secretName", - Namespace: "app", - Envelope: &fleetv1beta1.EnvelopeIdentifier{ - Name: "envelop-configmap", - Namespace: "app", - Type: fleetv1beta1.ConfigMapEnvelopeType, - }, - }, - Condition: metav1.Condition{ - - Type: fleetv1beta1.WorkConditionTypeApplied, - ObservedGeneration: 1, - Status: metav1.ConditionFalse, - }, - }, - }, - }, - } - for name, tt := range tests { - t.Run(name, func(t *testing.T) { - gotIsPending, gotRes := buildFailedResourcePlacements(tt.work) - if tt.wantIsPending != gotIsPending { - t.Errorf("buildFailedResourcePlacements `%s` mismatch, want: %t, got : %t", name, tt.wantIsPending, gotIsPending) - } - if diff := cmp.Diff(tt.wantRes, gotRes, statusCmpOptions...); diff != "" { - t.Errorf("buildFailedResourcePlacements `%s` status mismatch (-want, +got):\n%s", name, diff) - } - }) - } -} - -func TestSetPlacementStatus_useNewConditions(t *testing.T) { - currentTime := time.Now() - oldTransitionTime := metav1.NewTime(currentTime.Add(-1 * time.Hour)) - - crpGeneration := int64(25) - selectedResources := []fleetv1beta1.ResourceIdentifier{ - { - Group: "", - Version: "v1", - Kind: "Service", - Name: "svc-name", - Namespace: "svc-namespace", - }, - { - Group: "", - Version: "v1", - Kind: "Deployment", - Name: "deployment-name", - Namespace: "deployment-namespace", - }, - { - Group: "", - Version: "v1", - Kind: "ConfigMap", - Name: "config-name", - Namespace: "config-namespace", - }, - } - tests := []struct { - name string - crpStatus fleetv1beta1.ClusterResourcePlacementStatus - policy *fleetv1beta1.PlacementPolicy - latestPolicySnapshot *fleetv1beta1.ClusterSchedulingPolicySnapshot - latestResourceSnapshot *fleetv1beta1.ClusterResourceSnapshot - clusterResourceBindings []fleetv1beta1.ClusterResourceBinding - works []fleetv1beta1.Work - want bool - wantStatus *fleetv1beta1.ClusterResourcePlacementStatus - wantErr error - }{ - { - name: "empty policy and resource status", - latestPolicySnapshot: &fleetv1beta1.ClusterSchedulingPolicySnapshot{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf(fleetv1beta1.PolicySnapshotNameFmt, testName, 0), - Labels: map[string]string{ - fleetv1beta1.PolicyIndexLabel: "0", - fleetv1beta1.IsLatestSnapshotLabel: "true", - fleetv1beta1.CRPTrackingLabel: testName, - }, - Annotations: map[string]string{ - fleetv1beta1.NumberOfClustersAnnotation: strconv.Itoa(3), - }, - }, - }, - latestResourceSnapshot: &fleetv1beta1.ClusterResourceSnapshot{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf(fleetv1beta1.ResourceSnapshotNameFmt, testName, 0), - Labels: map[string]string{ - fleetv1beta1.ResourceIndexLabel: "0", - fleetv1beta1.CRPTrackingLabel: testName, - fleetv1beta1.IsLatestSnapshotLabel: "true", - }, - Annotations: map[string]string{ - fleetv1beta1.ResourceGroupHashAnnotation: "hash", - fleetv1beta1.NumberOfResourceSnapshotsAnnotation: "1", - }, - }, - }, - want: false, - wantStatus: &fleetv1beta1.ClusterResourcePlacementStatus{ - SelectedResources: selectedResources, - ObservedResourceIndex: "0", - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType), - Reason: SchedulingUnknownReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - }, - PlacementStatuses: []fleetv1beta1.ResourcePlacementStatus{}, - }, - }, - { - name: "unknown status of policy snapshot", - latestPolicySnapshot: &fleetv1beta1.ClusterSchedulingPolicySnapshot{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf(fleetv1beta1.PolicySnapshotNameFmt, testName, 0), - Labels: map[string]string{ - fleetv1beta1.PolicyIndexLabel: "0", - fleetv1beta1.IsLatestSnapshotLabel: "true", - fleetv1beta1.CRPTrackingLabel: testName, - }, - Annotations: map[string]string{ - fleetv1beta1.NumberOfClustersAnnotation: strconv.Itoa(3), - }, - Generation: 1, - }, - Status: fleetv1beta1.SchedulingPolicySnapshotStatus{ - ObservedCRPGeneration: crpGeneration, - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.PolicySnapshotScheduled), - Reason: "Pending", - Message: "message", - ObservedGeneration: 1, - }, - }, - ClusterDecisions: nil, - }, - }, - latestResourceSnapshot: &fleetv1beta1.ClusterResourceSnapshot{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf(fleetv1beta1.ResourceSnapshotNameFmt, testName, 0), - Labels: map[string]string{ - fleetv1beta1.ResourceIndexLabel: "0", - fleetv1beta1.CRPTrackingLabel: testName, - fleetv1beta1.IsLatestSnapshotLabel: "true", - }, - Annotations: map[string]string{ - fleetv1beta1.ResourceGroupHashAnnotation: "hash", - fleetv1beta1.NumberOfResourceSnapshotsAnnotation: "1", - }, - }, - }, - want: false, - wantStatus: &fleetv1beta1.ClusterResourcePlacementStatus{ - SelectedResources: selectedResources, - ObservedResourceIndex: "0", - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType), - Reason: SchedulingUnknownReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - }, - PlacementStatuses: []fleetv1beta1.ResourcePlacementStatus{}, - }, - }, - { - name: "scheduler does not report the latest status for policy snapshot (annotation change)", - latestPolicySnapshot: &fleetv1beta1.ClusterSchedulingPolicySnapshot{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf(fleetv1beta1.PolicySnapshotNameFmt, testName, 0), - Labels: map[string]string{ - fleetv1beta1.PolicyIndexLabel: "0", - fleetv1beta1.IsLatestSnapshotLabel: "true", - fleetv1beta1.CRPTrackingLabel: testName, - }, - Annotations: map[string]string{ - fleetv1beta1.NumberOfClustersAnnotation: strconv.Itoa(3), - }, - Generation: 1, - }, - Status: fleetv1beta1.SchedulingPolicySnapshotStatus{ - ObservedCRPGeneration: crpGeneration - 1, - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.PolicySnapshotScheduled), - Reason: "Scheduled", - Message: "message", - ObservedGeneration: 1, - }, - }, - ClusterDecisions: nil, - }, - }, - latestResourceSnapshot: &fleetv1beta1.ClusterResourceSnapshot{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf(fleetv1beta1.ResourceSnapshotNameFmt, testName, 0), - Labels: map[string]string{ - fleetv1beta1.ResourceIndexLabel: "0", - fleetv1beta1.CRPTrackingLabel: testName, - fleetv1beta1.IsLatestSnapshotLabel: "true", - }, - Annotations: map[string]string{ - fleetv1beta1.ResourceGroupHashAnnotation: "hash", - fleetv1beta1.NumberOfResourceSnapshotsAnnotation: "1", - }, - }, - }, - want: false, - wantStatus: &fleetv1beta1.ClusterResourcePlacementStatus{ - SelectedResources: selectedResources, - ObservedResourceIndex: "0", - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType), - Reason: SchedulingUnknownReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - }, - PlacementStatuses: []fleetv1beta1.ResourcePlacementStatus{}, - }, - }, - { - // should not happen in the production as the policySnapshot is immutable - name: "scheduler does not report the latest status for policy snapshot and snapshot observation does not match", - latestPolicySnapshot: &fleetv1beta1.ClusterSchedulingPolicySnapshot{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf(fleetv1beta1.PolicySnapshotNameFmt, testName, 0), - Labels: map[string]string{ - fleetv1beta1.PolicyIndexLabel: "0", - fleetv1beta1.IsLatestSnapshotLabel: "true", - fleetv1beta1.CRPTrackingLabel: testName, - }, - Annotations: map[string]string{ - fleetv1beta1.NumberOfClustersAnnotation: strconv.Itoa(3), - }, - Generation: 2, - }, - Status: fleetv1beta1.SchedulingPolicySnapshotStatus{ - ObservedCRPGeneration: crpGeneration, - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.PolicySnapshotScheduled), - Reason: "Scheduled", - Message: "message", - ObservedGeneration: 1, - }, - }, - }, - }, - latestResourceSnapshot: &fleetv1beta1.ClusterResourceSnapshot{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf(fleetv1beta1.ResourceSnapshotNameFmt, testName, 0), - Labels: map[string]string{ - fleetv1beta1.ResourceIndexLabel: "0", - fleetv1beta1.CRPTrackingLabel: testName, - fleetv1beta1.IsLatestSnapshotLabel: "true", - }, - Annotations: map[string]string{ - fleetv1beta1.ResourceGroupHashAnnotation: "hash", - fleetv1beta1.NumberOfResourceSnapshotsAnnotation: "1", - }, - }, - }, - want: false, - wantStatus: &fleetv1beta1.ClusterResourcePlacementStatus{ - SelectedResources: selectedResources, - ObservedResourceIndex: "0", - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType), - Reason: SchedulingUnknownReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - }, - PlacementStatuses: []fleetv1beta1.ResourcePlacementStatus{}, - }, - }, - { - name: "the placement has been scheduled and no clusterResourcebindings and works", - policy: placementPolicyForTest(), - latestPolicySnapshot: &fleetv1beta1.ClusterSchedulingPolicySnapshot{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf(fleetv1beta1.PolicySnapshotNameFmt, testName, 0), - Labels: map[string]string{ - fleetv1beta1.PolicyIndexLabel: "0", - fleetv1beta1.IsLatestSnapshotLabel: "true", - fleetv1beta1.CRPTrackingLabel: testName, - }, - Annotations: map[string]string{ - fleetv1beta1.NumberOfClustersAnnotation: strconv.Itoa(3), - }, - Generation: 1, - }, - Status: fleetv1beta1.SchedulingPolicySnapshotStatus{ - ObservedCRPGeneration: crpGeneration, - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.PolicySnapshotScheduled), - Reason: "Scheduled", - Message: "message", - ObservedGeneration: 1, - }, - }, - ClusterDecisions: []fleetv1beta1.ClusterDecision{ - { - ClusterName: "member-1", - Selected: true, - Reason: "success", - }, - { - ClusterName: "member-2", - Selected: true, - Reason: "success", - }, - { - ClusterName: "member-3", - Selected: true, - Reason: "success", - }, - { - ClusterName: "member-4", - Reason: "failed", - }, - }, - }, - }, - latestResourceSnapshot: &fleetv1beta1.ClusterResourceSnapshot{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf(fleetv1beta1.ResourceSnapshotNameFmt, testName, 0), - Labels: map[string]string{ - fleetv1beta1.ResourceIndexLabel: "0", - fleetv1beta1.CRPTrackingLabel: testName, - fleetv1beta1.IsLatestSnapshotLabel: "true", - }, - Annotations: map[string]string{ - fleetv1beta1.ResourceGroupHashAnnotation: "hash", - fleetv1beta1.NumberOfResourceSnapshotsAnnotation: "1", - }, - }, - }, - want: true, - wantStatus: &fleetv1beta1.ClusterResourcePlacementStatus{ - SelectedResources: selectedResources, - ObservedResourceIndex: "0", - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ClusterResourcePlacementRolloutStartedConditionType), - Reason: condition.RolloutStartedUnknownReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType), - Reason: "Scheduled", - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - }, - PlacementStatuses: []fleetv1beta1.ResourcePlacementStatus{ - { - ClusterName: "member-1", - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ResourceRolloutStartedConditionType), - Reason: condition.RolloutStartedUnknownReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourceScheduledConditionType), - Reason: condition.ScheduleSucceededReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - }, - }, - { - ClusterName: "member-2", - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ResourceRolloutStartedConditionType), - Reason: condition.RolloutStartedUnknownReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourceScheduledConditionType), - Reason: condition.ScheduleSucceededReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - }, - }, - { - ClusterName: "member-3", - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ResourceRolloutStartedConditionType), - Reason: condition.RolloutStartedUnknownReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourceScheduledConditionType), - Reason: condition.ScheduleSucceededReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - }, - }, - }, - }, - }, - { - // TODO special handling no cluster is selected - name: "the placement has been scheduled for pickAll; none of clusters are selected; no clusterResourceBindings and works", - latestPolicySnapshot: &fleetv1beta1.ClusterSchedulingPolicySnapshot{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf(fleetv1beta1.PolicySnapshotNameFmt, testName, 0), - Labels: map[string]string{ - fleetv1beta1.PolicyIndexLabel: "0", - fleetv1beta1.IsLatestSnapshotLabel: "true", - fleetv1beta1.CRPTrackingLabel: testName, - }, - Annotations: map[string]string{ - fleetv1beta1.NumberOfClustersAnnotation: strconv.Itoa(3), - }, - Generation: 1, - }, - Status: fleetv1beta1.SchedulingPolicySnapshotStatus{ - ObservedCRPGeneration: crpGeneration, - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.PolicySnapshotScheduled), - Reason: "Scheduled", - Message: "message", - ObservedGeneration: 1, - }, - }, - ClusterDecisions: []fleetv1beta1.ClusterDecision{ - { - ClusterName: "member-1", - Reason: "failed", - }, - { - ClusterName: "member-2", - Reason: "failed", - }, - }, - }, - }, - latestResourceSnapshot: &fleetv1beta1.ClusterResourceSnapshot{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf(fleetv1beta1.ResourceSnapshotNameFmt, testName, 0), - Labels: map[string]string{ - fleetv1beta1.ResourceIndexLabel: "0", - fleetv1beta1.CRPTrackingLabel: testName, - fleetv1beta1.IsLatestSnapshotLabel: "true", - }, - Annotations: map[string]string{ - fleetv1beta1.ResourceGroupHashAnnotation: "hash", - fleetv1beta1.NumberOfResourceSnapshotsAnnotation: "1", - }, - }, - }, - want: false, - wantStatus: &fleetv1beta1.ClusterResourcePlacementStatus{ - SelectedResources: selectedResources, - ObservedResourceIndex: "0", - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType), - Reason: "Scheduled", - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - }, - PlacementStatuses: []fleetv1beta1.ResourcePlacementStatus{}, - }, - }, - { - name: "the placement scheduling failed", - policy: placementPolicyForTest(), - latestPolicySnapshot: &fleetv1beta1.ClusterSchedulingPolicySnapshot{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf(fleetv1beta1.PolicySnapshotNameFmt, testName, 0), - Labels: map[string]string{ - fleetv1beta1.PolicyIndexLabel: "0", - fleetv1beta1.IsLatestSnapshotLabel: "true", - fleetv1beta1.CRPTrackingLabel: testName, - }, - Annotations: map[string]string{ - fleetv1beta1.NumberOfClustersAnnotation: strconv.Itoa(3), - }, - Generation: 1, - }, - Status: fleetv1beta1.SchedulingPolicySnapshotStatus{ - ObservedCRPGeneration: crpGeneration, - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionFalse, - Type: string(fleetv1beta1.PolicySnapshotScheduled), - Reason: "SchedulingFailed", - Message: "message", - ObservedGeneration: 1, - }, - }, - ClusterDecisions: []fleetv1beta1.ClusterDecision{ - { - ClusterName: "member-1", - Selected: true, - Reason: "success", - }, - { - ClusterName: "member-2", - Selected: false, - Reason: "score is low", - }, - { - ClusterName: "member-3", - Selected: false, - Reason: "score is low", - }, - }, - }, - }, - latestResourceSnapshot: &fleetv1beta1.ClusterResourceSnapshot{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf(fleetv1beta1.ResourceSnapshotNameFmt, testName, 0), - Labels: map[string]string{ - fleetv1beta1.ResourceIndexLabel: "0", - fleetv1beta1.CRPTrackingLabel: testName, - fleetv1beta1.IsLatestSnapshotLabel: "true", - }, - Annotations: map[string]string{ - fleetv1beta1.ResourceGroupHashAnnotation: "hash", - fleetv1beta1.NumberOfResourceSnapshotsAnnotation: "1", - }, - }, - }, - want: true, - wantStatus: &fleetv1beta1.ClusterResourcePlacementStatus{ - SelectedResources: selectedResources, - ObservedResourceIndex: "0", - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ClusterResourcePlacementRolloutStartedConditionType), - Reason: condition.RolloutStartedUnknownReason, - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - { - Status: metav1.ConditionFalse, - Type: string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType), - Reason: "SchedulingFailed", - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - }, - PlacementStatuses: []fleetv1beta1.ResourcePlacementStatus{ - { - ClusterName: "member-1", - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionUnknown, - Type: string(fleetv1beta1.ResourceRolloutStartedConditionType), - Reason: condition.RolloutStartedUnknownReason, + Type: string(fleetv1beta1.ResourceOverriddenConditionType), + Reason: condition.OverriddenSucceededReason, ObservedGeneration: crpGeneration, LastTransitionTime: metav1.NewTime(currentTime), }, { Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourceScheduledConditionType), - Reason: condition.ScheduleSucceededReason, + Type: string(fleetv1beta1.ResourceRolloutStartedConditionType), + Reason: condition.RolloutStartedReason, ObservedGeneration: crpGeneration, LastTransitionTime: metav1.NewTime(currentTime), }, - }, - }, - { - Conditions: []metav1.Condition{ { - Status: metav1.ConditionFalse, + Status: metav1.ConditionTrue, Type: string(fleetv1beta1.ResourceScheduledConditionType), - Reason: ResourceScheduleFailedReason, + Reason: condition.ScheduleSucceededReason, ObservedGeneration: crpGeneration, LastTransitionTime: metav1.NewTime(currentTime), }, - }, - }, - { - Conditions: []metav1.Condition{ { - Status: metav1.ConditionFalse, - Type: string(fleetv1beta1.ResourceScheduledConditionType), - Reason: ResourceScheduleFailedReason, + Status: metav1.ConditionTrue, + Type: string(fleetv1beta1.ResourceWorkSynchronizedConditionType), + Reason: condition.WorkSynchronizedReason, ObservedGeneration: crpGeneration, LastTransitionTime: metav1.NewTime(currentTime), }, @@ -3122,12 +978,11 @@ func TestSetPlacementStatus_useNewConditions(t *testing.T) { }, }, }, - // TODO special handling when selected cluster is 0 { - name: "the placement scheduling succeeded when numberOfClusters is 0", + name: "the placement is completed with clusterResourceBindings and works (no overrides)", policy: &fleetv1beta1.PlacementPolicy{ PlacementType: fleetv1beta1.PickNPlacementType, - NumberOfClusters: ptr.To(int32(0)), + NumberOfClusters: ptr.To(int32(1)), }, latestPolicySnapshot: &fleetv1beta1.ClusterSchedulingPolicySnapshot{ ObjectMeta: metav1.ObjectMeta{ @@ -3137,17 +992,8 @@ func TestSetPlacementStatus_useNewConditions(t *testing.T) { fleetv1beta1.IsLatestSnapshotLabel: "true", fleetv1beta1.CRPTrackingLabel: testName, }, - OwnerReferences: []metav1.OwnerReference{ - { - Name: testName, - BlockOwnerDeletion: ptr.To(true), - Controller: ptr.To(true), - APIVersion: fleetAPIVersion, - Kind: "ClusterResourcePlacement", - }, - }, Annotations: map[string]string{ - fleetv1beta1.NumberOfClustersAnnotation: strconv.Itoa(0), + fleetv1beta1.NumberOfClustersAnnotation: strconv.Itoa(1), }, Generation: 1, }, @@ -3165,89 +1011,11 @@ func TestSetPlacementStatus_useNewConditions(t *testing.T) { ClusterDecisions: []fleetv1beta1.ClusterDecision{ { ClusterName: "member-1", - Selected: false, - Reason: "filtered", + Selected: true, + Reason: "success", }, { ClusterName: "member-2", - Selected: false, - Reason: "filtered", - }, - }, - }, - }, - latestResourceSnapshot: &fleetv1beta1.ClusterResourceSnapshot{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf(fleetv1beta1.ResourceSnapshotNameFmt, testName, 0), - Labels: map[string]string{ - fleetv1beta1.ResourceIndexLabel: "0", - fleetv1beta1.CRPTrackingLabel: testName, - fleetv1beta1.IsLatestSnapshotLabel: "true", - }, - OwnerReferences: []metav1.OwnerReference{ - { - Name: testName, - BlockOwnerDeletion: ptr.To(true), - Controller: ptr.To(true), - APIVersion: fleetAPIVersion, - Kind: "ClusterResourcePlacement", - }, - }, - Annotations: map[string]string{ - fleetv1beta1.ResourceGroupHashAnnotation: "hash", - fleetv1beta1.NumberOfResourceSnapshotsAnnotation: "0", - }, - }, - }, - want: false, - wantStatus: &fleetv1beta1.ClusterResourcePlacementStatus{ - SelectedResources: selectedResources, - ObservedResourceIndex: "0", - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType), - Reason: "Scheduled", - ObservedGeneration: crpGeneration, - LastTransitionTime: metav1.NewTime(currentTime), - }, - }, - PlacementStatuses: []fleetv1beta1.ResourcePlacementStatus{}, - }, - }, - { - name: "the placement is completed with clusterResourcebindings and works", - policy: &fleetv1beta1.PlacementPolicy{ - PlacementType: fleetv1beta1.PickNPlacementType, - NumberOfClusters: ptr.To(int32(1)), - }, - latestPolicySnapshot: &fleetv1beta1.ClusterSchedulingPolicySnapshot{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf(fleetv1beta1.PolicySnapshotNameFmt, testName, 0), - Labels: map[string]string{ - fleetv1beta1.PolicyIndexLabel: "0", - fleetv1beta1.IsLatestSnapshotLabel: "true", - fleetv1beta1.CRPTrackingLabel: testName, - }, - Annotations: map[string]string{ - fleetv1beta1.NumberOfClustersAnnotation: strconv.Itoa(1), - }, - Generation: 1, - }, - Status: fleetv1beta1.SchedulingPolicySnapshotStatus{ - ObservedCRPGeneration: crpGeneration, - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.PolicySnapshotScheduled), - Reason: "Scheduled", - Message: "message", - ObservedGeneration: 1, - }, - }, - ClusterDecisions: []fleetv1beta1.ClusterDecision{ - { - ClusterName: "member-1", Selected: true, Reason: "success", }, @@ -3282,19 +1050,57 @@ func TestSetPlacementStatus_useNewConditions(t *testing.T) { Generation: 1, }, Spec: fleetv1beta1.ResourceBindingSpec{ - ResourceSnapshotName: fmt.Sprintf(fleetv1beta1.ResourceSnapshotNameFmt, testName, 0), - ResourceOverrideSnapshots: []fleetv1beta1.NamespacedName{ + ResourceSnapshotName: fmt.Sprintf(fleetv1beta1.ResourceSnapshotNameFmt, testName, 0), + SchedulingPolicySnapshotName: fmt.Sprintf(fleetv1beta1.PolicySnapshotNameFmt, testName, 0), + TargetCluster: "member-1", + }, + Status: fleetv1beta1.ResourceBindingStatus{ + Conditions: []metav1.Condition{ { - Name: "override-1", - Namespace: "override-ns", + Status: metav1.ConditionTrue, + Type: string(fleetv1beta1.ResourceBindingRolloutStarted), + Reason: condition.RolloutStartedReason, + ObservedGeneration: 1, }, { - Name: "override-2", + Status: metav1.ConditionTrue, + Type: string(fleetv1beta1.ResourceBindingOverridden), + Reason: condition.OverrideNotSpecifiedReason, + ObservedGeneration: 1, + }, + { + Status: metav1.ConditionTrue, + Type: string(fleetv1beta1.ResourceBindingWorkSynchronized), + Reason: condition.WorkSynchronizedReason, + ObservedGeneration: 1, + }, + { + Status: metav1.ConditionTrue, + Type: string(fleetv1beta1.ResourceBindingApplied), + Reason: condition.ApplySucceededReason, + ObservedGeneration: 1, + }, + { + Status: metav1.ConditionTrue, + Type: string(fleetv1beta1.ResourceBindingAvailable), + Reason: condition.AvailableReason, + ObservedGeneration: 1, }, }, - ClusterResourceOverrideSnapshots: []string{"o-1", "o-2"}, - SchedulingPolicySnapshotName: fmt.Sprintf(fleetv1beta1.PolicySnapshotNameFmt, testName, 0), - TargetCluster: "member-1", + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "binding-2", + Labels: map[string]string{ + fleetv1beta1.CRPTrackingLabel: testName, + }, + Generation: 1, + }, + Spec: fleetv1beta1.ResourceBindingSpec{ + ResourceSnapshotName: fmt.Sprintf(fleetv1beta1.ResourceSnapshotNameFmt, testName, 0), + SchedulingPolicySnapshotName: fmt.Sprintf(fleetv1beta1.PolicySnapshotNameFmt, testName, 0), + TargetCluster: "member-2", }, Status: fleetv1beta1.ResourceBindingStatus{ Conditions: []metav1.Condition{ @@ -3307,7 +1113,7 @@ func TestSetPlacementStatus_useNewConditions(t *testing.T) { { Status: metav1.ConditionTrue, Type: string(fleetv1beta1.ResourceBindingOverridden), - Reason: condition.OverriddenSucceededReason, + Reason: condition.OverrideNotSpecifiedReason, ObservedGeneration: 1, }, { @@ -3354,7 +1160,7 @@ func TestSetPlacementStatus_useNewConditions(t *testing.T) { { Status: metav1.ConditionTrue, Type: string(fleetv1beta1.ClusterResourcePlacementOverriddenConditionType), - Reason: condition.OverriddenSucceededReason, + Reason: condition.OverrideNotSpecifiedReason, ObservedGeneration: crpGeneration, LastTransitionTime: metav1.NewTime(currentTime), }, @@ -3382,17 +1188,54 @@ func TestSetPlacementStatus_useNewConditions(t *testing.T) { }, PlacementStatuses: []fleetv1beta1.ResourcePlacementStatus{ { - ClusterName: "member-1", - ApplicableClusterResourceOverrides: []string{"o-1", "o-2"}, - ApplicableResourceOverrides: []fleetv1beta1.NamespacedName{ + ClusterName: "member-1", + Conditions: []metav1.Condition{ { - Name: "override-1", - Namespace: "override-ns", + Status: metav1.ConditionTrue, + Type: string(fleetv1beta1.ResourcesAppliedConditionType), + Reason: condition.ApplySucceededReason, + ObservedGeneration: crpGeneration, + LastTransitionTime: metav1.NewTime(currentTime), }, { - Name: "override-2", + Status: metav1.ConditionTrue, + Type: string(fleetv1beta1.ResourcesAvailableConditionType), + Reason: condition.AvailableReason, + ObservedGeneration: crpGeneration, + LastTransitionTime: metav1.NewTime(currentTime), + }, + { + Status: metav1.ConditionTrue, + Type: string(fleetv1beta1.ResourceOverriddenConditionType), + Reason: condition.OverrideNotSpecifiedReason, + ObservedGeneration: crpGeneration, + LastTransitionTime: metav1.NewTime(currentTime), + }, + { + Status: metav1.ConditionTrue, + Type: string(fleetv1beta1.ResourceRolloutStartedConditionType), + Reason: condition.RolloutStartedReason, + ObservedGeneration: crpGeneration, + LastTransitionTime: metav1.NewTime(currentTime), + }, + { + Status: metav1.ConditionTrue, + Type: string(fleetv1beta1.ResourceScheduledConditionType), + Reason: condition.ScheduleSucceededReason, + ObservedGeneration: crpGeneration, + LastTransitionTime: metav1.NewTime(currentTime), + }, + { + Status: metav1.ConditionTrue, + Type: string(fleetv1beta1.ResourceWorkSynchronizedConditionType), + Reason: condition.WorkSynchronizedReason, + ObservedGeneration: crpGeneration, + LastTransitionTime: metav1.NewTime(currentTime), }, }, + }, + { + ClusterName: "member-2", Conditions: []metav1.Condition{ { Status: metav1.ConditionTrue, @@ -3411,7 +1254,7 @@ func TestSetPlacementStatus_useNewConditions(t *testing.T) { { Status: metav1.ConditionTrue, Type: string(fleetv1beta1.ResourceOverriddenConditionType), - Reason: condition.OverriddenSucceededReason, + Reason: condition.OverrideNotSpecifiedReason, ObservedGeneration: crpGeneration, LastTransitionTime: metav1.NewTime(currentTime), }, @@ -4530,7 +2373,7 @@ func TestSetPlacementStatus_useNewConditions(t *testing.T) { { Status: metav1.ConditionTrue, Type: string(fleetv1beta1.ResourceBindingOverridden), - Reason: condition.OverriddenSucceededReason, + Reason: condition.OverrideNotSpecifiedReason, ObservedGeneration: 1, }, { @@ -4759,7 +2602,7 @@ func TestSetPlacementStatus_useNewConditions(t *testing.T) { { Status: metav1.ConditionTrue, Type: string(fleetv1beta1.ClusterResourcePlacementOverriddenConditionType), - Reason: condition.OverriddenSucceededReason, + Reason: condition.OverrideNotSpecifiedReason, ObservedGeneration: crpGeneration, LastTransitionTime: metav1.NewTime(currentTime), }, @@ -4839,7 +2682,7 @@ func TestSetPlacementStatus_useNewConditions(t *testing.T) { { Status: metav1.ConditionTrue, Type: string(fleetv1beta1.ResourceOverriddenConditionType), - Reason: condition.OverriddenSucceededReason, + Reason: condition.OverrideNotSpecifiedReason, ObservedGeneration: crpGeneration, LastTransitionTime: metav1.NewTime(currentTime), }, @@ -4870,7 +2713,7 @@ func TestSetPlacementStatus_useNewConditions(t *testing.T) { }, }, { - name: "update the CRP and it rollout status becomes unknown", + name: "update the CRP and it rollout status becomes unknown (reset the existing conditions)", policy: &fleetv1beta1.PlacementPolicy{ PlacementType: fleetv1beta1.PickNPlacementType, NumberOfClusters: ptr.To(int32(1)), @@ -5027,37 +2870,16 @@ func TestSetPlacementStatus_useNewConditions(t *testing.T) { fleetv1beta1.IsLatestSnapshotLabel: "true", }, Annotations: map[string]string{ - fleetv1beta1.ResourceGroupHashAnnotation: "hash", - fleetv1beta1.NumberOfResourceSnapshotsAnnotation: "1", - }, - }, - }, - want: true, - wantStatus: &fleetv1beta1.ClusterResourcePlacementStatus{ - SelectedResources: selectedResources, - ObservedResourceIndex: "0", - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementAppliedConditionType), - Reason: condition.ApplySucceededReason, - ObservedGeneration: 1, - LastTransitionTime: oldTransitionTime, - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementAvailableConditionType), - Reason: condition.AvailableReason, - ObservedGeneration: 1, - LastTransitionTime: oldTransitionTime, - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementOverriddenConditionType), - Reason: condition.OverriddenSucceededReason, - ObservedGeneration: 1, - LastTransitionTime: oldTransitionTime, + fleetv1beta1.ResourceGroupHashAnnotation: "hash", + fleetv1beta1.NumberOfResourceSnapshotsAnnotation: "1", }, + }, + }, + want: true, + wantStatus: &fleetv1beta1.ClusterResourcePlacementStatus{ + SelectedResources: selectedResources, + ObservedResourceIndex: "0", + Conditions: []metav1.Condition{ { Status: metav1.ConditionUnknown, Type: string(fleetv1beta1.ClusterResourcePlacementRolloutStartedConditionType), @@ -5072,39 +2894,11 @@ func TestSetPlacementStatus_useNewConditions(t *testing.T) { ObservedGeneration: crpGeneration, LastTransitionTime: oldTransitionTime, }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ClusterResourcePlacementWorkSynchronizedConditionType), - Reason: condition.WorkSynchronizedReason, - ObservedGeneration: 1, - LastTransitionTime: oldTransitionTime, - }, }, PlacementStatuses: []fleetv1beta1.ResourcePlacementStatus{ { ClusterName: "member-1", Conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourcesAppliedConditionType), - Reason: condition.ApplySucceededReason, - ObservedGeneration: 1, - LastTransitionTime: oldTransitionTime, - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourcesAvailableConditionType), - Reason: condition.AvailableReason, - ObservedGeneration: 1, - LastTransitionTime: oldTransitionTime, - }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourceOverriddenConditionType), - Reason: condition.OverriddenSucceededReason, - ObservedGeneration: 1, - LastTransitionTime: oldTransitionTime, - }, { Status: metav1.ConditionUnknown, Type: string(fleetv1beta1.ResourceRolloutStartedConditionType), @@ -5119,13 +2913,6 @@ func TestSetPlacementStatus_useNewConditions(t *testing.T) { ObservedGeneration: crpGeneration, LastTransitionTime: oldTransitionTime, }, - { - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourceWorkSynchronizedConditionType), - Reason: condition.WorkSynchronizedReason, - ObservedGeneration: 1, - LastTransitionTime: oldTransitionTime, - }, }, }, }, @@ -5600,6 +3387,210 @@ func TestSetPlacementStatus_useNewConditions(t *testing.T) { }, }, }, + { + name: "the placement cannot be fulfilled for pickN (reset existing status)", + policy: &fleetv1beta1.PlacementPolicy{ + PlacementType: fleetv1beta1.PickNPlacementType, + NumberOfClusters: ptr.To(int32(3)), + }, + crpStatus: fleetv1beta1.ClusterResourcePlacementStatus{ + SelectedResources: selectedResources, + ObservedResourceIndex: "0", + Conditions: []metav1.Condition{ + { + Status: metav1.ConditionTrue, + Type: string(fleetv1beta1.ClusterResourcePlacementAppliedConditionType), + Reason: condition.ApplySucceededReason, + ObservedGeneration: 1, + LastTransitionTime: oldTransitionTime, + }, + { + Status: metav1.ConditionTrue, + Type: string(fleetv1beta1.ClusterResourcePlacementAvailableConditionType), + Reason: condition.AvailableReason, + ObservedGeneration: 1, + LastTransitionTime: oldTransitionTime, + }, + { + Status: metav1.ConditionTrue, + Type: string(fleetv1beta1.ClusterResourcePlacementOverriddenConditionType), + Reason: condition.OverriddenSucceededReason, + ObservedGeneration: 1, + LastTransitionTime: oldTransitionTime, + }, + { + Status: metav1.ConditionUnknown, + Type: string(fleetv1beta1.ClusterResourcePlacementRolloutStartedConditionType), + Reason: condition.RolloutStartedUnknownReason, + ObservedGeneration: crpGeneration, + LastTransitionTime: metav1.NewTime(currentTime), + }, + { + Status: metav1.ConditionTrue, + Type: string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType), + Reason: "Scheduled", + ObservedGeneration: crpGeneration, + LastTransitionTime: oldTransitionTime, + }, + { + Status: metav1.ConditionTrue, + Type: string(fleetv1beta1.ClusterResourcePlacementWorkSynchronizedConditionType), + Reason: condition.WorkSynchronizedReason, + ObservedGeneration: 1, + LastTransitionTime: oldTransitionTime, + }, + }, + PlacementStatuses: []fleetv1beta1.ResourcePlacementStatus{ + { + ClusterName: "member-1", + Conditions: []metav1.Condition{ + { + Status: metav1.ConditionTrue, + Type: string(fleetv1beta1.ResourcesAppliedConditionType), + Reason: condition.ApplySucceededReason, + ObservedGeneration: 1, + LastTransitionTime: oldTransitionTime, + }, + { + Status: metav1.ConditionTrue, + Type: string(fleetv1beta1.ResourcesAvailableConditionType), + Reason: condition.AvailableReason, + ObservedGeneration: 1, + LastTransitionTime: oldTransitionTime, + }, + { + Status: metav1.ConditionTrue, + Type: string(fleetv1beta1.ResourceOverriddenConditionType), + Reason: condition.OverriddenSucceededReason, + ObservedGeneration: 1, + LastTransitionTime: oldTransitionTime, + }, + { + Status: metav1.ConditionUnknown, + Type: string(fleetv1beta1.ResourceRolloutStartedConditionType), + Reason: condition.RolloutStartedUnknownReason, + ObservedGeneration: crpGeneration, + LastTransitionTime: metav1.NewTime(currentTime), + }, + { + Status: metav1.ConditionTrue, + Type: string(fleetv1beta1.ResourceScheduledConditionType), + Reason: condition.ScheduleSucceededReason, + ObservedGeneration: crpGeneration, + LastTransitionTime: oldTransitionTime, + }, + { + Status: metav1.ConditionTrue, + Type: string(fleetv1beta1.ResourceWorkSynchronizedConditionType), + Reason: condition.WorkSynchronizedReason, + ObservedGeneration: 1, + LastTransitionTime: oldTransitionTime, + }, + }, + }, + }, + }, + latestPolicySnapshot: &fleetv1beta1.ClusterSchedulingPolicySnapshot{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf(fleetv1beta1.PolicySnapshotNameFmt, testName, 0), + Labels: map[string]string{ + fleetv1beta1.PolicyIndexLabel: "0", + fleetv1beta1.IsLatestSnapshotLabel: "true", + fleetv1beta1.CRPTrackingLabel: testName, + }, + Generation: 1, + }, + Status: fleetv1beta1.SchedulingPolicySnapshotStatus{ + ObservedCRPGeneration: crpGeneration, + Conditions: []metav1.Condition{ + { + Status: metav1.ConditionFalse, + Type: string(fleetv1beta1.PolicySnapshotScheduled), + Reason: "Failed", + ObservedGeneration: 1, + }, + }, + ClusterDecisions: []fleetv1beta1.ClusterDecision{ + { + ClusterName: "member-1", + Selected: true, + Reason: "success", + }, + { + ClusterName: "unselected-cluster", + Reason: "failed", + }, + }, + }, + }, + latestResourceSnapshot: &fleetv1beta1.ClusterResourceSnapshot{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf(fleetv1beta1.ResourceSnapshotNameFmt, testName, 0), + Labels: map[string]string{ + fleetv1beta1.ResourceIndexLabel: "0", + fleetv1beta1.CRPTrackingLabel: testName, + fleetv1beta1.IsLatestSnapshotLabel: "true", + }, + Annotations: map[string]string{ + fleetv1beta1.ResourceGroupHashAnnotation: "hash", + fleetv1beta1.NumberOfResourceSnapshotsAnnotation: "1", + }, + }, + }, + want: true, + wantStatus: &fleetv1beta1.ClusterResourcePlacementStatus{ + SelectedResources: selectedResources, + ObservedResourceIndex: "0", + Conditions: []metav1.Condition{ + { + Status: metav1.ConditionUnknown, + Type: string(fleetv1beta1.ClusterResourcePlacementRolloutStartedConditionType), + Reason: condition.RolloutStartedUnknownReason, + ObservedGeneration: crpGeneration, + LastTransitionTime: metav1.NewTime(currentTime), + }, + { + Status: metav1.ConditionFalse, + Type: string(fleetv1beta1.ClusterResourcePlacementScheduledConditionType), + Reason: "Failed", + ObservedGeneration: crpGeneration, + LastTransitionTime: metav1.NewTime(currentTime), + }, + }, + PlacementStatuses: []fleetv1beta1.ResourcePlacementStatus{ + { + ClusterName: "member-1", + Conditions: []metav1.Condition{ + { + Status: metav1.ConditionUnknown, + Type: string(fleetv1beta1.ResourceRolloutStartedConditionType), + Reason: condition.RolloutStartedUnknownReason, + ObservedGeneration: crpGeneration, + LastTransitionTime: metav1.NewTime(currentTime), + }, + { + Status: metav1.ConditionTrue, + Type: string(fleetv1beta1.ResourceScheduledConditionType), + Reason: condition.ScheduleSucceededReason, + ObservedGeneration: crpGeneration, + LastTransitionTime: oldTransitionTime, + }, + }, + }, + { + Conditions: []metav1.Condition{ + { + Status: metav1.ConditionFalse, + Type: string(fleetv1beta1.ResourceScheduledConditionType), + Reason: ResourceScheduleFailedReason, + ObservedGeneration: crpGeneration, + LastTransitionTime: metav1.NewTime(currentTime), + }, + }, + }, + }, + }, + }, } for _, tc := range tests { @@ -5636,10 +3627,9 @@ func TestSetPlacementStatus_useNewConditions(t *testing.T) { WithObjects(objects...). Build() r := Reconciler{ - Client: fakeClient, - Scheme: scheme, - Recorder: record.NewFakeRecorder(10), - UseNewConditions: true, + Client: fakeClient, + Scheme: scheme, + Recorder: record.NewFakeRecorder(10), } crp.Generation = crpGeneration got, err := r.setPlacementStatus(context.Background(), crp, selectedResources, tc.latestPolicySnapshot, tc.latestResourceSnapshot) @@ -6620,10 +4610,9 @@ func TestSetFailedPlacementsPerCluster(t *testing.T) { WithObjects(objects...). Build() r := Reconciler{ - Client: fakeClient, - Scheme: scheme, - Recorder: record.NewFakeRecorder(10), - UseNewConditions: true, + Client: fakeClient, + Scheme: scheme, + Recorder: record.NewFakeRecorder(10), } err := r.setFailedPlacementsPerCluster(ctx, crp, binding, status) if !errors.Is(err, tc.wantErr) { @@ -7378,10 +5367,9 @@ func TestSetResourcePlacementStatusPerCluster(t *testing.T) { WithObjects(objects...). Build() r := Reconciler{ - Client: fakeClient, - Scheme: scheme, - Recorder: record.NewFakeRecorder(10), - UseNewConditions: true, + Client: fakeClient, + Scheme: scheme, + Recorder: record.NewFakeRecorder(10), } status := fleetv1beta1.ResourcePlacementStatus{ClusterName: cluster} got, err := r.setResourcePlacementStatusPerCluster(ctx, crp, resourceSnapshot, tc.binding, &status) diff --git a/pkg/controllers/clusterresourceplacement/suite_test.go b/pkg/controllers/clusterresourceplacement/suite_test.go index 1a9e01a25..e265decd9 100644 --- a/pkg/controllers/clusterresourceplacement/suite_test.go +++ b/pkg/controllers/clusterresourceplacement/suite_test.go @@ -23,12 +23,12 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/envtest" - "sigs.k8s.io/controller-runtime/pkg/log/zap" "sigs.k8s.io/controller-runtime/pkg/manager" metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" placementv1beta1 "go.goms.io/fleet/apis/placement/v1beta1" "go.goms.io/fleet/cmd/hubagent/options" + "go.goms.io/fleet/pkg/controllers/clusterresourcebindingwatcher" "go.goms.io/fleet/pkg/controllers/clusterresourceplacementwatcher" "go.goms.io/fleet/pkg/controllers/clusterschedulingpolicysnapshot" "go.goms.io/fleet/pkg/utils" @@ -56,17 +56,20 @@ func TestAPIs(t *testing.T) { } var _ = BeforeSuite(func() { - klog.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) - ctx, cancel = context.WithCancel(context.TODO()) + By("Setup klog") + var err error + fs := flag.NewFlagSet("klog", flag.ContinueOnError) + klog.InitFlags(fs) + Expect(fs.Parse([]string{"--v", "5", "-add_dir_header", "true"})).Should(Succeed()) + By("bootstrapping test environment") testEnv = &envtest.Environment{ CRDDirectoryPaths: []string{filepath.Join("../../../", "config", "crd", "bases")}, ErrorIfCRDPathMissing: true, } - var err error cfg, err = testEnv.Start() Expect(err).Should(Succeed()) Expect(cfg).NotTo(BeNil()) @@ -130,6 +133,12 @@ var _ = BeforeSuite(func() { }).SetupWithManager(mgr) Expect(err).Should(Succeed(), "failed to create clusterResourcePlacement watcher") + err = (&clusterresourcebindingwatcher.Reconciler{ + Client: mgr.GetClient(), + PlacementController: crpController, + }).SetupWithManager(mgr) + Expect(err).Should(Succeed(), "failed to create clusterResourceBinding watcher") + ctx, cancel = context.WithCancel(context.TODO()) // Run the controller manager go func() { diff --git a/pkg/controllers/overrider/clusterresource_controller.go b/pkg/controllers/overrider/clusterresource_controller.go index 53bd1d91c..98f81a298 100644 --- a/pkg/controllers/overrider/clusterresource_controller.go +++ b/pkg/controllers/overrider/clusterresource_controller.go @@ -15,7 +15,6 @@ import ( "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/tools/record" "k8s.io/klog/v2" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" @@ -32,7 +31,6 @@ import ( // ClusterResourceReconciler reconciles a clusterResourceOverride object. type ClusterResourceReconciler struct { Reconciler - recorder record.EventRecorder } // Reconcile triggers a single reconcile round when scheduling policy has changed. @@ -151,7 +149,6 @@ func (r *ClusterResourceReconciler) ensureClusterResourceOverrideSnapshot(ctx co // SetupWithManager sets up the controller with the Manager. func (r *ClusterResourceReconciler) SetupWithManager(mgr ctrl.Manager) error { - r.recorder = mgr.GetEventRecorderFor("clusterResourceReconciler") return ctrl.NewControllerManagedBy(mgr). Named("clusterresourceoverride-controller"). For(&placementv1alpha1.ClusterResourceOverride{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})). diff --git a/pkg/controllers/rollout/controller.go b/pkg/controllers/rollout/controller.go index 8dd6e61f5..fc7b862dd 100644 --- a/pkg/controllers/rollout/controller.go +++ b/pkg/controllers/rollout/controller.go @@ -141,9 +141,9 @@ func (r *Reconciler) Reconcile(ctx context.Context, req runtime.Request) (runtim if !needRoll { klog.V(2).InfoS("No bindings are out of date, stop rolling", "clusterResourcePlacement", crpName) - // There will be a corner case that rollout controller succeeds to update the binding spec to the latest one, but - // fail to update the binding conditions. - // Here it will reconcile the binding status. + // There is a corner case that rollout controller succeeds to update the binding spec to the latest one, + // but fails to update the binding conditions when it reconciled it last time. + // Here it will correct the binding status just in case this happens last time. return runtime.Result{}, r.checkAndUpdateStaleBindingsStatus(ctx, allBindings) } klog.V(2).InfoS("Picked the bindings to be updated", "clusterResourcePlacement", crpName, "numberOfBindings", len(toBeUpdatedBindings), "numberOfStaleBindings", len(staleBoundBindings)) @@ -334,6 +334,7 @@ func (r *Reconciler) pickBindingsToRoll(ctx context.Context, allBindings []*flee // classify the bindings into different categories // TODO: calculate the time we need to wait for the first applied but not ready binding to be ready. + // return wait time longer if the rollout is stuck on failed apply/available bindings crpKObj := klog.KObj(crp) for idx := range allBindings { binding := allBindings[idx] @@ -341,8 +342,9 @@ func (r *Reconciler) pickBindingsToRoll(ctx context.Context, allBindings []*flee switch binding.Spec.State { case fleetv1beta1.BindingStateUnscheduled: appliedCondition := binding.GetCondition(string(fleetv1beta1.ResourceBindingApplied)) - if condition.IsConditionStatusFalse(appliedCondition, binding.Generation) { - klog.V(3).InfoS("Found an failed to apply unscheduled binding", "clusterResourcePlacement", crpKObj, "binding", bindingKObj) + availableCondition := binding.GetCondition(string(fleetv1beta1.ResourceBindingAvailable)) + if condition.IsConditionStatusFalse(appliedCondition, binding.Generation) || condition.IsConditionStatusFalse(availableCondition, binding.Generation) { + klog.V(3).InfoS("Found a failed to be ready unscheduled binding", "clusterResourcePlacement", crpKObj, "binding", bindingKObj) } else { canBeReadyBindings = append(canBeReadyBindings, binding) } @@ -364,7 +366,6 @@ func (r *Reconciler) pickBindingsToRoll(ctx context.Context, allBindings []*flee case fleetv1beta1.BindingStateScheduled: // the scheduler has picked a cluster for this binding schedulerTargetedBinds = append(schedulerTargetedBinds, binding) - // this binding has not been bound yet, so it is an update candidate // pickFromResourceMatchedOverridesForTargetCluster always returns the ordered list of the overrides. cro, ro, err := r.pickFromResourceMatchedOverridesForTargetCluster(ctx, binding, matchedCROs, matchedROs) @@ -380,14 +381,15 @@ func (r *Reconciler) pickBindingsToRoll(ctx context.Context, allBindings []*flee klog.V(3).InfoS("Found a ready bound binding", "clusterResourcePlacement", crpKObj, "binding", bindingKObj) readyBindings = append(readyBindings, binding) } + // check if the binding is failed or still on going appliedCondition := binding.GetCondition(string(fleetv1beta1.ResourceBindingApplied)) - if condition.IsConditionStatusFalse(appliedCondition, binding.Generation) { - klog.V(3).InfoS("Found a failed to apply bound binding", "clusterResourcePlacement", crpKObj, "binding", bindingKObj) + availableCondition := binding.GetCondition(string(fleetv1beta1.ResourceBindingAvailable)) + if condition.IsConditionStatusFalse(appliedCondition, binding.Generation) || condition.IsConditionStatusFalse(availableCondition, binding.Generation) { + klog.V(3).InfoS("Found a failed to be ready bound binding", "clusterResourcePlacement", crpKObj, "binding", bindingKObj) bindingFailed = true } else { canBeReadyBindings = append(canBeReadyBindings, binding) } - // pickFromResourceMatchedOverridesForTargetCluster always returns the ordered list of the overrides. cro, ro, err := r.pickFromResourceMatchedOverridesForTargetCluster(ctx, binding, matchedCROs, matchedROs) if err != nil { @@ -407,26 +409,7 @@ func (r *Reconciler) pickBindingsToRoll(ctx context.Context, allBindings []*flee } } - // calculate the target number of bindings - targetNumber := 0 - - // note that if the policy will be overwritten if it is nil in this controller. - switch { - case crp.Spec.Policy.PlacementType == fleetv1beta1.PickAllPlacementType: - // we use the scheduler picked bindings as the target number since there is no target in the CRP - targetNumber = len(schedulerTargetedBinds) - case crp.Spec.Policy.PlacementType == fleetv1beta1.PickFixedPlacementType: - // we use the length of the given cluster names are targets - targetNumber = len(crp.Spec.Policy.ClusterNames) - case crp.Spec.Policy.PlacementType == fleetv1beta1.PickNPlacementType: - // we use the given number as the target - targetNumber = int(*crp.Spec.Policy.NumberOfClusters) - default: - // should never happen - klog.ErrorS(controller.NewUnexpectedBehaviorError(fmt.Errorf("unknown placement type")), - "Encountered an invalid placementType", "clusterResourcePlacement", crpKObj) - targetNumber = 0 - } + targetNumber := r.calculateRealTarget(crp, schedulerTargetedBinds) klog.V(2).InfoS("Calculated the targetNumber", "clusterResourcePlacement", crpKObj, "targetNumber", targetNumber, "readyBindingNumber", len(readyBindings), "canBeUnavailableBindingNumber", len(canBeUnavailableBindings), "canBeReadyBindingNumber", len(canBeReadyBindings), "boundingCandidateNumber", len(boundingCandidates), @@ -499,6 +482,31 @@ func (r *Reconciler) pickBindingsToRoll(ctx context.Context, allBindings []*flee return toBeUpdatedBindingList, staleUnselectedBinding, true, nil } +func (r *Reconciler) calculateRealTarget(crp *fleetv1beta1.ClusterResourcePlacement, schedulerTargetedBinds []*fleetv1beta1.ClusterResourceBinding) int { + crpKObj := klog.KObj(crp) + // calculate the target number of bindings + targetNumber := 0 + + // note that if the policy will be overwritten if it is nil in this controller. + switch { + case crp.Spec.Policy.PlacementType == fleetv1beta1.PickAllPlacementType: + // we use the scheduler picked bindings as the target number since there is no target in the CRP + targetNumber = len(schedulerTargetedBinds) + case crp.Spec.Policy.PlacementType == fleetv1beta1.PickFixedPlacementType: + // we use the length of the given cluster names are targets + targetNumber = len(crp.Spec.Policy.ClusterNames) + case crp.Spec.Policy.PlacementType == fleetv1beta1.PickNPlacementType: + // we use the given number as the target + targetNumber = int(*crp.Spec.Policy.NumberOfClusters) + default: + // should never happen + klog.ErrorS(controller.NewUnexpectedBehaviorError(fmt.Errorf("unknown placement type")), + "Encountered an invalid placementType", "clusterResourcePlacement", crpKObj) + targetNumber = 0 + } + return targetNumber +} + // isBindingReady checks if a binding is considered ready. // A binding with not trackable resources is considered ready if the binding's current spec has been available before // the ready cutoff time. diff --git a/pkg/controllers/workgenerator/controller.go b/pkg/controllers/workgenerator/controller.go index 756691908..47d30bdf2 100644 --- a/pkg/controllers/workgenerator/controller.go +++ b/pkg/controllers/workgenerator/controller.go @@ -51,16 +51,6 @@ import ( "go.goms.io/fleet/pkg/utils/labels" ) -const ( - allWorkSyncedReason = "AllWorkSynced" - syncWorkFailedReason = "SyncWorkFailed" - workNeedSyncedReason = "StillNeedToSyncWork" - workNotAppliedReason = "NotAllWorkHaveBeenApplied" - allWorkAppliedReason = "AllWorkHaveBeenApplied" - workNotAvailableReason = "NotAllWorkAreAvailable" - allWorkAvailableReason = "AllWorkAreAvailable" -) - var ( errResourceSnapshotNotFound = errors.New("the master resource snapshot is not found") ) @@ -136,15 +126,17 @@ func (r *Reconciler) Reconcile(ctx context.Context, req controllerruntime.Reques if overrideSucceeded { overrideReason := condition.OverriddenSucceededReason + overrideMessage := "Successfully applied the override rules on the resources" if len(resourceBinding.Spec.ClusterResourceOverrideSnapshots) == 0 && len(resourceBinding.Spec.ResourceOverrideSnapshots) == 0 { overrideReason = condition.OverrideNotSpecifiedReason + overrideMessage = "No override rules are configured for the selected resources" } resourceBinding.SetConditions(metav1.Condition{ Status: metav1.ConditionTrue, Type: string(fleetv1beta1.ResourceBindingOverridden), Reason: overrideReason, - Message: "Successfully applied the override rules on the resources", + Message: overrideMessage, ObservedGeneration: resourceBinding.Generation, }) } @@ -167,34 +159,19 @@ func (r *Reconciler) Reconcile(ctx context.Context, req controllerruntime.Reques ObservedGeneration: resourceBinding.Generation, }) } else { - // TODO: remove the deprecated "resourceBound" condition when we switch to the new condition model - resourceBinding.SetConditions(metav1.Condition{ - Status: metav1.ConditionFalse, - Type: string(fleetv1beta1.ResourceBindingBound), - Reason: syncWorkFailedReason, - Message: errorMessage, - ObservedGeneration: resourceBinding.Generation, - }) resourceBinding.SetConditions(metav1.Condition{ Status: metav1.ConditionFalse, Type: string(fleetv1beta1.ResourceBindingWorkSynchronized), - Reason: syncWorkFailedReason, + Reason: condition.SyncWorkFailedReason, Message: fmt.Sprintf("Failed to sychronize the work to the latest: %s", errorMessage), ObservedGeneration: resourceBinding.Generation, }) } } else { - // TODO: remove the deprecated "resourceBound" condition when we switch to the new condition model - resourceBinding.SetConditions(metav1.Condition{ - Status: metav1.ConditionTrue, - Type: string(fleetv1beta1.ResourceBindingBound), - Reason: allWorkSyncedReason, - ObservedGeneration: resourceBinding.Generation, - }) resourceBinding.SetConditions(metav1.Condition{ Status: metav1.ConditionTrue, Type: string(fleetv1beta1.ResourceBindingWorkSynchronized), - Reason: allWorkSyncedReason, + Reason: condition.AllWorkSyncedReason, ObservedGeneration: resourceBinding.Generation, Message: "All of the works are synchronized to the latest", }) @@ -203,7 +180,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req controllerruntime.Reques resourceBinding.SetConditions(metav1.Condition{ Status: metav1.ConditionFalse, Type: string(fleetv1beta1.ResourceBindingApplied), - Reason: workNeedSyncedReason, + Reason: condition.WorkNeedSyncedReason, Message: "In the processing of synchronizing the work to the member cluster", ObservedGeneration: resourceBinding.Generation, }) @@ -642,7 +619,7 @@ func buildAllWorkAppliedCondition(works map[string]*fleetv1beta1.Work, binding * return metav1.Condition{ Status: metav1.ConditionTrue, Type: string(fleetv1beta1.ResourceBindingApplied), - Reason: allWorkAppliedReason, + Reason: condition.AllWorkAppliedReason, Message: "All corresponding work objects are applied", ObservedGeneration: binding.GetGeneration(), } @@ -650,7 +627,7 @@ func buildAllWorkAppliedCondition(works map[string]*fleetv1beta1.Work, binding * return metav1.Condition{ Status: metav1.ConditionFalse, Type: string(fleetv1beta1.ResourceBindingApplied), - Reason: workNotAppliedReason, + Reason: condition.WorkNotAppliedReason, Message: fmt.Sprintf("Work object %s is not applied", notAppliedWork), ObservedGeneration: binding.GetGeneration(), } @@ -673,7 +650,7 @@ func buildAllWorkAvailableCondition(works map[string]*fleetv1beta1.Work, binding } if allAvailable { klog.V(2).InfoS("All works associated with the binding are available", "binding", klog.KObj(binding)) - reason := allWorkAvailableReason + reason := condition.AllWorkAvailableReason message := "All corresponding work objects are available" if len(notTrackableWork) > 0 { reason = work.WorkNotTrackableReason @@ -691,7 +668,7 @@ func buildAllWorkAvailableCondition(works map[string]*fleetv1beta1.Work, binding return metav1.Condition{ Status: metav1.ConditionFalse, Type: string(fleetv1beta1.ResourceBindingAvailable), - Reason: workNotAvailableReason, + Reason: condition.WorkNotAvailableReason, Message: fmt.Sprintf("Work object %s is not available", notAvailableWork), ObservedGeneration: binding.GetGeneration(), } diff --git a/pkg/controllers/workgenerator/controller_integration_test.go b/pkg/controllers/workgenerator/controller_integration_test.go index c63926703..5418e3288 100644 --- a/pkg/controllers/workgenerator/controller_integration_test.go +++ b/pkg/controllers/workgenerator/controller_integration_test.go @@ -1190,9 +1190,9 @@ var _ = Describe("Test Work Generator Controller", func() { func verifyBindingStatusSyncedNotApplied(binding *placementv1beta1.ClusterResourceBinding, hasOverride, workSync bool) { Eventually(func() string { Expect(k8sClient.Get(ctx, types.NamespacedName{Name: binding.Name}, binding)).Should(Succeed()) - appliedReason := workNotAppliedReason + appliedReason := condition.WorkNotAppliedReason if workSync { - appliedReason = workNeedSyncedReason + appliedReason = condition.WorkNeedSyncedReason } overrideReason := condition.OverrideNotSpecifiedReason if hasOverride { @@ -1207,16 +1207,10 @@ func verifyBindingStatusSyncedNotApplied(binding *placementv1beta1.ClusterResour Reason: overrideReason, ObservedGeneration: binding.GetGeneration(), }, - { - Type: string(placementv1beta1.ResourceBindingBound), - Status: metav1.ConditionTrue, - Reason: allWorkSyncedReason, - ObservedGeneration: binding.GetGeneration(), - }, { Type: string(placementv1beta1.ResourceBindingWorkSynchronized), Status: metav1.ConditionTrue, - Reason: allWorkSyncedReason, + Reason: condition.AllWorkSyncedReason, ObservedGeneration: binding.GetGeneration(), }, { @@ -1246,28 +1240,22 @@ func verifyBindStatusAppliedNotAvailable(binding *placementv1beta1.ClusterResour Reason: overrideReason, ObservedGeneration: binding.GetGeneration(), }, - { - Type: string(placementv1beta1.ResourceBindingBound), - Status: metav1.ConditionTrue, - Reason: allWorkSyncedReason, - ObservedGeneration: binding.GetGeneration(), - }, { Type: string(placementv1beta1.ResourceBindingWorkSynchronized), Status: metav1.ConditionTrue, - Reason: allWorkSyncedReason, + Reason: condition.AllWorkSyncedReason, ObservedGeneration: binding.GetGeneration(), }, { Type: string(placementv1beta1.ResourceBindingApplied), Status: metav1.ConditionTrue, - Reason: allWorkAppliedReason, + Reason: condition.AllWorkAppliedReason, ObservedGeneration: binding.GetGeneration(), }, { Type: string(placementv1beta1.ResourceBindingAvailable), Status: metav1.ConditionFalse, - Reason: workNotAvailableReason, + Reason: condition.WorkNotAvailableReason, ObservedGeneration: binding.GetGeneration(), }, }, @@ -1291,28 +1279,22 @@ func verifyBindStatusAvail(binding *placementv1beta1.ClusterResourceBinding, has Reason: overrideReason, ObservedGeneration: binding.GetGeneration(), }, - { - Type: string(placementv1beta1.ResourceBindingBound), - Status: metav1.ConditionTrue, - Reason: allWorkSyncedReason, - ObservedGeneration: binding.GetGeneration(), - }, { Type: string(placementv1beta1.ResourceBindingWorkSynchronized), Status: metav1.ConditionTrue, - Reason: allWorkSyncedReason, + Reason: condition.AllWorkSyncedReason, ObservedGeneration: binding.GetGeneration(), }, { Type: string(placementv1beta1.ResourceBindingApplied), Status: metav1.ConditionTrue, - Reason: allWorkAppliedReason, + Reason: condition.AllWorkAppliedReason, ObservedGeneration: binding.GetGeneration(), }, { Type: string(placementv1beta1.ResourceBindingAvailable), Status: metav1.ConditionTrue, - Reason: allWorkAvailableReason, + Reason: condition.AllWorkAvailableReason, ObservedGeneration: binding.GetGeneration(), }, }, diff --git a/pkg/controllers/workgenerator/controller_test.go b/pkg/controllers/workgenerator/controller_test.go index e8f35447b..3cbabf271 100644 --- a/pkg/controllers/workgenerator/controller_test.go +++ b/pkg/controllers/workgenerator/controller_test.go @@ -14,6 +14,7 @@ import ( fleetv1beta1 "go.goms.io/fleet/apis/placement/v1beta1" "go.goms.io/fleet/pkg/controllers/work" + "go.goms.io/fleet/pkg/utils/condition" "go.goms.io/fleet/pkg/utils/controller" ) @@ -165,7 +166,7 @@ func TestBuildAllWorkAppliedCondition(t *testing.T) { want: metav1.Condition{ Status: metav1.ConditionTrue, Type: string(fleetv1beta1.ResourceBindingApplied), - Reason: allWorkAppliedReason, + Reason: condition.AllWorkAppliedReason, ObservedGeneration: 1, }, }, @@ -206,7 +207,7 @@ func TestBuildAllWorkAppliedCondition(t *testing.T) { want: metav1.Condition{ Status: metav1.ConditionFalse, Type: string(fleetv1beta1.ResourceBindingApplied), - Reason: workNotAppliedReason, + Reason: condition.WorkNotAppliedReason, ObservedGeneration: 1, }, }, @@ -238,7 +239,7 @@ func TestBuildAllWorkAppliedCondition(t *testing.T) { want: metav1.Condition{ Status: metav1.ConditionFalse, Type: string(fleetv1beta1.ResourceBindingApplied), - Reason: workNotAppliedReason, + Reason: condition.WorkNotAppliedReason, ObservedGeneration: 1, }, }, @@ -279,7 +280,7 @@ func TestBuildAllWorkAppliedCondition(t *testing.T) { want: metav1.Condition{ Status: metav1.ConditionFalse, Type: string(fleetv1beta1.ResourceBindingApplied), - Reason: workNotAppliedReason, + Reason: condition.WorkNotAppliedReason, ObservedGeneration: 1, }, }, @@ -345,7 +346,7 @@ func TestBuildAllWorkAvailableCondition(t *testing.T) { want: metav1.Condition{ Status: metav1.ConditionTrue, Type: string(fleetv1beta1.ResourceBindingAvailable), - Reason: allWorkAvailableReason, + Reason: condition.AllWorkAvailableReason, ObservedGeneration: 1, }, }, @@ -423,7 +424,7 @@ func TestBuildAllWorkAvailableCondition(t *testing.T) { want: metav1.Condition{ Status: metav1.ConditionFalse, Type: string(fleetv1beta1.ResourceBindingAvailable), - Reason: workNotAvailableReason, + Reason: condition.WorkNotAvailableReason, Message: "work object work2 is not available", ObservedGeneration: 1, }, @@ -459,7 +460,7 @@ func TestBuildAllWorkAvailableCondition(t *testing.T) { want: metav1.Condition{ Status: metav1.ConditionFalse, Type: string(fleetv1beta1.ResourceBindingAvailable), - Reason: workNotAvailableReason, + Reason: condition.WorkNotAvailableReason, Message: "work object work2 is not available", ObservedGeneration: 1, }, diff --git a/pkg/utils/condition/condition.go b/pkg/utils/condition/condition.go index 1c3cd9a46..9386add71 100644 --- a/pkg/utils/condition/condition.go +++ b/pkg/utils/condition/condition.go @@ -16,9 +16,6 @@ import ( // A group of condition reason string which is used to populate the placement condition. const ( - // ScheduleSucceededReason is the reason string of placement condition if scheduling succeeded. - ScheduleSucceededReason = "Scheduled" - // RolloutStartedUnknownReason is the reason string of placement condition if rollout status is // unknown. RolloutStartedUnknownReason = "RolloutStartedUnknown" @@ -73,6 +70,33 @@ const ( AvailableReason = "ResourceAvailable" ) +// A group of condition reason string which is used to populate the placement condition per cluster. +const ( + // ScheduleSucceededReason is the reason string of placement condition if scheduling succeeded. + ScheduleSucceededReason = "Scheduled" + + // AllWorkSyncedReason is the reason string of placement condition if all works are synchronized. + AllWorkSyncedReason = "AllWorkSynced" + + // SyncWorkFailedReason is the reason string of placement condition if some works failed to synchronize. + SyncWorkFailedReason = "SyncWorkFailed" + + // WorkNeedSyncedReason is the reason string of placement condition if some works are in the processing of synchronizing. + WorkNeedSyncedReason = "StillNeedToSyncWork" + + // WorkNotAppliedReason is the reason string of placement condition if some works are not applied. + WorkNotAppliedReason = "NotAllWorkHaveBeenApplied" + + // AllWorkAppliedReason is the reason string of placement condition if all works are applied. + AllWorkAppliedReason = "AllWorkHaveBeenApplied" + + // WorkNotAvailableReason is the reason string of placement condition if some works are not available. + WorkNotAvailableReason = "NotAllWorkAreAvailable" + + // AllWorkAvailableReason is the reason string of placement condition if all works are available. + AllWorkAvailableReason = "AllWorkAreAvailable" +) + // EqualCondition compares one condition with another; it ignores the LastTransitionTime and Message fields, // and will consider the ObservedGeneration values from the two conditions a match if the current // condition is newer. @@ -113,14 +137,14 @@ func IsConditionStatusFalse(cond *metav1.Condition, latestGeneration int64) bool return cond != nil && cond.Status == metav1.ConditionFalse && cond.ObservedGeneration == latestGeneration } -// resourceCondition is all the resource related condition, for example, scheduled condition is not included. -type resourceCondition int +// ResourceCondition is all the resource related condition, for example, scheduled condition is not included. +type ResourceCondition int // The following conditions are in ordered. // Once the placement is scheduled, it will be divided into following stages. // Used to populate the CRP conditions. const ( - RolloutStartedCondition resourceCondition = iota + RolloutStartedCondition ResourceCondition = iota OverriddenCondition WorkSynchronizedCondition AppliedCondition @@ -128,7 +152,7 @@ const ( TotalCondition ) -func (c resourceCondition) EventReasonForTrue() string { +func (c ResourceCondition) EventReasonForTrue() string { return []string{ "PlacementRolloutStarted", "PlacementOverriddenSucceeded", @@ -138,7 +162,7 @@ func (c resourceCondition) EventReasonForTrue() string { }[c] } -func (c resourceCondition) EventMessageForTrue() string { +func (c ResourceCondition) EventMessageForTrue() string { return []string{ "Started rolling out the latest resources", "Placement has been successfully overridden", @@ -149,7 +173,7 @@ func (c resourceCondition) EventMessageForTrue() string { } // ResourcePlacementConditionType returns the resource condition type per cluster used by cluster resource placement. -func (c resourceCondition) ResourcePlacementConditionType() fleetv1beta1.ResourcePlacementConditionType { +func (c ResourceCondition) ResourcePlacementConditionType() fleetv1beta1.ResourcePlacementConditionType { return []fleetv1beta1.ResourcePlacementConditionType{ fleetv1beta1.ResourceRolloutStartedConditionType, fleetv1beta1.ResourceOverriddenConditionType, @@ -160,7 +184,7 @@ func (c resourceCondition) ResourcePlacementConditionType() fleetv1beta1.Resourc } // ResourceBindingConditionType returns the binding condition type used by cluster resource binding. -func (c resourceCondition) ResourceBindingConditionType() fleetv1beta1.ResourceBindingConditionType { +func (c ResourceCondition) ResourceBindingConditionType() fleetv1beta1.ResourceBindingConditionType { return []fleetv1beta1.ResourceBindingConditionType{ fleetv1beta1.ResourceBindingRolloutStarted, fleetv1beta1.ResourceBindingOverridden, @@ -171,7 +195,7 @@ func (c resourceCondition) ResourceBindingConditionType() fleetv1beta1.ResourceB } // ClusterResourcePlacementConditionType returns the CRP condition type used by CRP. -func (c resourceCondition) ClusterResourcePlacementConditionType() fleetv1beta1.ClusterResourcePlacementConditionType { +func (c ResourceCondition) ClusterResourcePlacementConditionType() fleetv1beta1.ClusterResourcePlacementConditionType { return []fleetv1beta1.ClusterResourcePlacementConditionType{ fleetv1beta1.ClusterResourcePlacementRolloutStartedConditionType, fleetv1beta1.ClusterResourcePlacementOverriddenConditionType, @@ -182,13 +206,13 @@ func (c resourceCondition) ClusterResourcePlacementConditionType() fleetv1beta1. } // UnknownResourceConditionPerCluster returns the unknown resource condition. -func (c resourceCondition) UnknownResourceConditionPerCluster(generation int64) metav1.Condition { +func (c ResourceCondition) UnknownResourceConditionPerCluster(generation int64) metav1.Condition { return []metav1.Condition{ { Status: metav1.ConditionUnknown, Type: string(fleetv1beta1.ResourceRolloutStartedConditionType), Reason: RolloutStartedUnknownReason, - Message: "In the process of deciding whether to rolling out the latest resources or not", + Message: "In the process of deciding whether to roll out the latest resources or not", ObservedGeneration: generation, }, { @@ -223,13 +247,13 @@ func (c resourceCondition) UnknownResourceConditionPerCluster(generation int64) } // UnknownClusterResourcePlacementCondition returns the unknown cluster resource placement condition. -func (c resourceCondition) UnknownClusterResourcePlacementCondition(generation int64, clusterCount int) metav1.Condition { +func (c ResourceCondition) UnknownClusterResourcePlacementCondition(generation int64, clusterCount int) metav1.Condition { return []metav1.Condition{ { Status: metav1.ConditionUnknown, Type: string(fleetv1beta1.ClusterResourcePlacementRolloutStartedConditionType), Reason: RolloutStartedUnknownReason, - Message: fmt.Sprintf("There are still %d cluster(s) in the process of deciding whether to rolling out the latest resources or not", clusterCount), + Message: fmt.Sprintf("There are still %d cluster(s) in the process of deciding whether to roll out the latest resources or not", clusterCount), ObservedGeneration: generation, }, { @@ -264,7 +288,7 @@ func (c resourceCondition) UnknownClusterResourcePlacementCondition(generation i } // FalseClusterResourcePlacementCondition returns the false cluster resource placement condition. -func (c resourceCondition) FalseClusterResourcePlacementCondition(generation int64, clusterCount int) metav1.Condition { +func (c ResourceCondition) FalseClusterResourcePlacementCondition(generation int64, clusterCount int) metav1.Condition { return []metav1.Condition{ { Status: metav1.ConditionFalse, @@ -305,7 +329,7 @@ func (c resourceCondition) FalseClusterResourcePlacementCondition(generation int } // TrueClusterResourcePlacementCondition returns the true cluster resource placement condition. -func (c resourceCondition) TrueClusterResourcePlacementCondition(generation int64, clusterCount int) metav1.Condition { +func (c ResourceCondition) TrueClusterResourcePlacementCondition(generation int64, clusterCount int) metav1.Condition { return []metav1.Condition{ { Status: metav1.ConditionTrue, diff --git a/test/e2e/actuals_test.go b/test/e2e/actuals_test.go index 17b50d086..547d68b54 100644 --- a/test/e2e/actuals_test.go +++ b/test/e2e/actuals_test.go @@ -18,7 +18,9 @@ import ( placementv1beta1 "go.goms.io/fleet/apis/placement/v1beta1" "go.goms.io/fleet/pkg/controllers/clusterresourceplacement" + "go.goms.io/fleet/pkg/controllers/work" scheduler "go.goms.io/fleet/pkg/scheduler/framework" + "go.goms.io/fleet/pkg/utils/condition" "go.goms.io/fleet/test/e2e/framework" ) @@ -90,48 +92,106 @@ func workNamespacePlacedOnClusterActual(cluster *framework.Cluster) func() error } } -func crpSyncFailedConditions(generation int64) []metav1.Condition { +func crpScheduleFailedConditions(generation int64) []metav1.Condition { return []metav1.Condition{ { Type: string(placementv1beta1.ClusterResourcePlacementScheduledConditionType), - Status: metav1.ConditionTrue, - Reason: scheduler.FullyScheduledReason, + Status: metav1.ConditionFalse, ObservedGeneration: generation, + Reason: scheduler.NotFullyScheduledReason, }, + } +} + +func crpSchedulePartiallyFailedConditions(generation int64) []metav1.Condition { + return []metav1.Condition{ { - Type: string(placementv1beta1.ClusterResourcePlacementSynchronizedConditionType), + Type: string(placementv1beta1.ClusterResourcePlacementScheduledConditionType), Status: metav1.ConditionFalse, - Reason: clusterresourceplacement.SynchronizePendingReason, + ObservedGeneration: generation, + Reason: scheduler.NotFullyScheduledReason, + }, + { + Type: string(placementv1beta1.ClusterResourcePlacementRolloutStartedConditionType), + Status: metav1.ConditionTrue, + Reason: condition.RolloutStartedReason, + ObservedGeneration: generation, + }, + { + Type: string(placementv1beta1.ClusterResourcePlacementOverriddenConditionType), + Status: metav1.ConditionTrue, + Reason: condition.OverrideNotSpecifiedReason, + ObservedGeneration: generation, + }, + { + Type: string(placementv1beta1.ClusterResourcePlacementWorkSynchronizedConditionType), + Status: metav1.ConditionTrue, + Reason: condition.WorkSynchronizedReason, ObservedGeneration: generation, }, { Type: string(placementv1beta1.ClusterResourcePlacementAppliedConditionType), - Status: metav1.ConditionUnknown, - Reason: clusterresourceplacement.ApplyPendingReason, + Status: metav1.ConditionTrue, + Reason: condition.ApplySucceededReason, + ObservedGeneration: generation, + }, + { + Type: string(placementv1beta1.ClusterResourcePlacementAvailableConditionType), + Status: metav1.ConditionTrue, + Reason: condition.AvailableReason, ObservedGeneration: generation, }, } } -func crpRolloutFailedConditions(generation int64) []metav1.Condition { +func crpRolloutStuckConditions(generation int64) []metav1.Condition { return []metav1.Condition{ { Type: string(placementv1beta1.ClusterResourcePlacementScheduledConditionType), + Status: metav1.ConditionTrue, + Reason: scheduler.FullyScheduledReason, + ObservedGeneration: generation, + }, + { + Type: string(placementv1beta1.ClusterResourcePlacementRolloutStartedConditionType), Status: metav1.ConditionFalse, + Reason: condition.RolloutNotStartedYetReason, + ObservedGeneration: generation, + }, + } +} + +func crpAppliedFailedConditions(generation int64) []metav1.Condition { + return []metav1.Condition{ + { + Type: string(placementv1beta1.ClusterResourcePlacementScheduledConditionType), + Status: metav1.ConditionTrue, + Reason: scheduler.FullyScheduledReason, ObservedGeneration: generation, - Reason: scheduler.NotFullyScheduledReason, }, { - Type: string(placementv1beta1.ClusterResourcePlacementSynchronizedConditionType), + Type: string(placementv1beta1.ClusterResourcePlacementRolloutStartedConditionType), Status: metav1.ConditionTrue, + Reason: condition.RolloutStartedReason, ObservedGeneration: generation, - Reason: clusterresourceplacement.SynchronizeSucceededReason, }, { - Type: string(placementv1beta1.ClusterResourcePlacementAppliedConditionType), + Type: string(placementv1beta1.ClusterResourcePlacementOverriddenConditionType), + Status: metav1.ConditionTrue, + Reason: condition.OverrideNotSpecifiedReason, + ObservedGeneration: generation, + }, + { + Type: string(placementv1beta1.ClusterResourcePlacementWorkSynchronizedConditionType), Status: metav1.ConditionTrue, + Reason: condition.WorkSynchronizedReason, + ObservedGeneration: generation, + }, + { + Type: string(placementv1beta1.ClusterResourcePlacementAppliedConditionType), + Status: metav1.ConditionFalse, + Reason: condition.ApplyFailedReason, ObservedGeneration: generation, - Reason: clusterresourceplacement.ApplySucceededReason, }, } } @@ -145,15 +205,33 @@ func crpRolloutCompletedConditions(generation int64) []metav1.Condition { ObservedGeneration: generation, }, { - Type: string(placementv1beta1.ClusterResourcePlacementSynchronizedConditionType), + Type: string(placementv1beta1.ClusterResourcePlacementRolloutStartedConditionType), + Status: metav1.ConditionTrue, + Reason: condition.RolloutStartedReason, + ObservedGeneration: generation, + }, + { + Type: string(placementv1beta1.ClusterResourcePlacementOverriddenConditionType), + Status: metav1.ConditionTrue, + Reason: condition.OverrideNotSpecifiedReason, + ObservedGeneration: generation, + }, + { + Type: string(placementv1beta1.ClusterResourcePlacementWorkSynchronizedConditionType), Status: metav1.ConditionTrue, - Reason: clusterresourceplacement.SynchronizeSucceededReason, + Reason: condition.WorkSynchronizedReason, ObservedGeneration: generation, }, { Type: string(placementv1beta1.ClusterResourcePlacementAppliedConditionType), Status: metav1.ConditionTrue, - Reason: clusterresourceplacement.ApplySucceededReason, + Reason: condition.ApplySucceededReason, + ObservedGeneration: generation, + }, + { + Type: string(placementv1beta1.ClusterResourcePlacementAvailableConditionType), + Status: metav1.ConditionTrue, + Reason: condition.AvailableReason, ObservedGeneration: generation, }, } @@ -164,19 +242,13 @@ func resourcePlacementSyncPendingConditions(generation int64) []metav1.Condition { Type: string(placementv1beta1.ResourceScheduledConditionType), Status: metav1.ConditionTrue, - Reason: clusterresourceplacement.ResourceScheduleSucceededReason, + Reason: condition.ScheduleSucceededReason, ObservedGeneration: generation, }, { - Type: string(placementv1beta1.ResourceWorkSynchronizedConditionType), + Type: string(placementv1beta1.ResourceRolloutStartedConditionType), Status: metav1.ConditionFalse, - Reason: clusterresourceplacement.WorkSynchronizePendingReason, - ObservedGeneration: generation, - }, - { - Type: string(placementv1beta1.ResourcesAppliedConditionType), - Status: metav1.ConditionUnknown, - Reason: clusterresourceplacement.ResourceApplyPendingReason, + Reason: condition.RolloutNotStartedYetReason, ObservedGeneration: generation, }, } @@ -187,42 +259,77 @@ func resourcePlacementApplyFailedConditions(generation int64) []metav1.Condition { Type: string(placementv1beta1.ResourceScheduledConditionType), Status: metav1.ConditionTrue, - Reason: clusterresourceplacement.ResourceScheduleSucceededReason, + Reason: condition.ScheduleSucceededReason, + ObservedGeneration: generation, + }, + { + Type: string(placementv1beta1.ResourceRolloutStartedConditionType), + Status: metav1.ConditionTrue, + Reason: condition.RolloutStartedReason, + ObservedGeneration: generation, + }, + { + Type: string(placementv1beta1.ResourceOverriddenConditionType), + Status: metav1.ConditionTrue, + Reason: condition.OverrideNotSpecifiedReason, ObservedGeneration: generation, }, { Type: string(placementv1beta1.ResourceWorkSynchronizedConditionType), Status: metav1.ConditionTrue, - Reason: clusterresourceplacement.WorkSynchronizeSucceededReason, + Reason: condition.AllWorkSyncedReason, ObservedGeneration: generation, }, { Type: string(placementv1beta1.ResourcesAppliedConditionType), Status: metav1.ConditionFalse, - Reason: clusterresourceplacement.ResourceApplyFailedReason, + Reason: condition.WorkNotAppliedReason, ObservedGeneration: generation, }, } } -func resourcePlacementRolloutCompletedConditions(generation int64) []metav1.Condition { +func resourcePlacementRolloutCompletedConditions(generation int64, resourceIsTrackable bool) []metav1.Condition { + availableConditionReason := work.WorkNotTrackableReason + if resourceIsTrackable { + availableConditionReason = condition.AllWorkAvailableReason + } + return []metav1.Condition{ { Type: string(placementv1beta1.ResourceScheduledConditionType), Status: metav1.ConditionTrue, - Reason: clusterresourceplacement.ResourceScheduleSucceededReason, + Reason: condition.ScheduleSucceededReason, + ObservedGeneration: generation, + }, + { + Type: string(placementv1beta1.ResourceRolloutStartedConditionType), + Status: metav1.ConditionTrue, + Reason: condition.RolloutStartedReason, + ObservedGeneration: generation, + }, + { + Type: string(placementv1beta1.ResourceOverriddenConditionType), + Status: metav1.ConditionTrue, + Reason: condition.OverrideNotSpecifiedReason, ObservedGeneration: generation, }, { Type: string(placementv1beta1.ResourceWorkSynchronizedConditionType), Status: metav1.ConditionTrue, - Reason: clusterresourceplacement.WorkSynchronizeSucceededReason, + Reason: condition.AllWorkSyncedReason, ObservedGeneration: generation, }, { Type: string(placementv1beta1.ResourcesAppliedConditionType), Status: metav1.ConditionTrue, - Reason: clusterresourceplacement.ResourceApplySucceededReason, + Reason: condition.AllWorkAppliedReason, + ObservedGeneration: generation, + }, + { + Type: string(placementv1beta1.ResourcesAvailableConditionType), + Status: metav1.ConditionTrue, + Reason: availableConditionReason, ObservedGeneration: generation, }, } @@ -262,6 +369,7 @@ func crpStatusUpdatedActual( wantSelectedResourceIdentifiers []placementv1beta1.ResourceIdentifier, wantSelectedClusters, wantUnselectedClusters []string, wantObservedResourceIndex string, + resourceIsTrackable bool, ) func() error { crpName := fmt.Sprintf(crpNameTemplate, GinkgoParallelProcess()) @@ -275,7 +383,7 @@ func crpStatusUpdatedActual( for _, name := range wantSelectedClusters { wantPlacementStatus = append(wantPlacementStatus, placementv1beta1.ResourcePlacementStatus{ ClusterName: name, - Conditions: resourcePlacementRolloutCompletedConditions(crp.Generation), + Conditions: resourcePlacementRolloutCompletedConditions(crp.Generation, resourceIsTrackable), }) } for i := 0; i < len(wantUnselectedClusters); i++ { @@ -284,9 +392,28 @@ func crpStatusUpdatedActual( }) } - wantCRPConditions := crpRolloutCompletedConditions(crp.Generation) + var wantCRPConditions []metav1.Condition + if len(wantSelectedClusters) > 0 { + wantCRPConditions = crpRolloutCompletedConditions(crp.Generation) + } else { + wantCRPConditions = []metav1.Condition{ + // we don't set the remaining resource conditions. + { + Type: string(placementv1beta1.ClusterResourcePlacementScheduledConditionType), + Status: metav1.ConditionTrue, + Reason: scheduler.FullyScheduledReason, + ObservedGeneration: crp.Generation, + }, + } + } + if len(wantUnselectedClusters) > 0 { - wantCRPConditions = crpRolloutFailedConditions(crp.Generation) + if len(wantSelectedClusters) > 0 { + wantCRPConditions = crpSchedulePartiallyFailedConditions(crp.Generation) + } else { + // we don't set the remaining resource conditions if there is no clusters to select + wantCRPConditions = crpScheduleFailedConditions(crp.Generation) + } } // Note that the CRP controller will only keep decisions regarding unselected clusters for a CRP if: diff --git a/test/e2e/enveloped_object_placement_test.go b/test/e2e/enveloped_object_placement_test.go index 95f78890b..0f84744cd 100644 --- a/test/e2e/enveloped_object_placement_test.go +++ b/test/e2e/enveloped_object_placement_test.go @@ -89,7 +89,7 @@ var _ = Describe("placing wrapped resources using a CRP", Ordered, func() { }) It("should update CRP status as expected", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(wantSelectedResources, allMemberClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(wantSelectedResources, allMemberClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -116,7 +116,9 @@ var _ = Describe("placing wrapped resources using a CRP", Ordered, func() { }) It("should update CRP status with failed to apply resourceQuota", func() { - crpStatusUpdatedActual := checkForOneClusterFailedToApplyStatus(wantSelectedResources) + // rolloutStarted is false, but other conditions are true. + // "The rollout is being blocked by the rollout strategy in 2 cluster(s)", + crpStatusUpdatedActual := checkForRolloutStuckOnOneFailedClusterStatus(wantSelectedResources) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -131,7 +133,7 @@ var _ = Describe("placing wrapped resources using a CRP", Ordered, func() { }) It("should update CRP status as success again", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(wantSelectedResources, allMemberClusterNames, nil, "2") + crpStatusUpdatedActual := crpStatusUpdatedActual(wantSelectedResources, allMemberClusterNames, nil, "2", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -221,10 +223,10 @@ func checkEnvelopQuotaAndMutationWebhookPlacement(memberCluster *framework.Clust } } -func checkForOneClusterFailedToApplyStatus(wantSelectedResources []placementv1beta1.ResourceIdentifier) func() error { +func checkForRolloutStuckOnOneFailedClusterStatus(wantSelectedResources []placementv1beta1.ResourceIdentifier) func() error { crpName := fmt.Sprintf(crpNameTemplate, GinkgoParallelProcess()) workNamespaceName := fmt.Sprintf(workNamespaceNameTemplate, GinkgoParallelProcess()) - failedResourcePlacement := []placementv1beta1.FailedResourcePlacement{ + wantFailedResourcePlacement := []placementv1beta1.FailedResourcePlacement{ { ResourceIdentifier: placementv1beta1.ResourceIdentifier{ Kind: "ResourceQuota", @@ -250,7 +252,7 @@ func checkForOneClusterFailedToApplyStatus(wantSelectedResources []placementv1be if err := hubClient.Get(ctx, types.NamespacedName{Name: crpName}, crp); err != nil { return err } - wantCRPConditions := crpSyncFailedConditions(crp.Generation) + wantCRPConditions := crpRolloutStuckConditions(crp.Generation) if diff := cmp.Diff(crp.Status.Conditions, wantCRPConditions, crpStatusCmpOptions...); diff != "" { return fmt.Errorf("CRP status diff (-got, +want): %s", diff) } @@ -271,7 +273,7 @@ func checkForOneClusterFailedToApplyStatus(wantSelectedResources []placementv1be for _, placementStatus := range crp.Status.PlacementStatuses { // this is the cluster that got the new enveloped resource that was malformed if len(placementStatus.FailedPlacements) != 0 { - if diff := cmp.Diff(placementStatus.FailedPlacements, failedResourcePlacement, crpStatusCmpOptions...); diff != "" { + if diff := cmp.Diff(placementStatus.FailedPlacements, wantFailedResourcePlacement, crpStatusCmpOptions...); diff != "" { return fmt.Errorf("CRP status diff (-got, +want): %s", diff) } // check that the applied error message is correct diff --git a/test/e2e/placement_pickall_test.go b/test/e2e/placement_pickall_test.go index 64d5d6f96..4d3c3b5b9 100644 --- a/test/e2e/placement_pickall_test.go +++ b/test/e2e/placement_pickall_test.go @@ -48,7 +48,7 @@ var _ = Describe("placing resources using a CRP with no placement policy specifi }) It("should update CRP status as expected", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -93,7 +93,7 @@ var _ = Describe("placing resources using a CRP of PickAll placement type", func }) It("should update CRP status as expected", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -160,7 +160,7 @@ var _ = Describe("placing resources using a CRP of PickAll placement type", func }) It("should update CRP status as expected", func() { - statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster1EastProdName}, nil, "0") + statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster1EastProdName}, nil, "0", false) Eventually(statusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -271,7 +271,7 @@ var _ = Describe("placing resources using a CRP of PickAll placement type", func }) It("should update CRP status as expected", func() { - statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster3WestProdName}, nil, "0") + statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster3WestProdName}, nil, "0", false) Eventually(statusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -346,7 +346,7 @@ var _ = Describe("placing resources using a CRP of PickAll placement type", func }) It("should update CRP status as expected", func() { - statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), nil, nil, "0") + statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), nil, nil, "0", false) Eventually(statusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -414,7 +414,7 @@ var _ = Describe("placing resources using a CRP of PickAll placement type", func }) It("should update CRP status as expected", func() { - statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster2EastCanaryName, memberCluster3WestProdName}, nil, "0") + statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster2EastCanaryName, memberCluster3WestProdName}, nil, "0", false) Eventually(statusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -495,7 +495,7 @@ var _ = Describe("placing resources using a CRP of PickAll placement type", func }) It("should update CRP status as expected", func() { - statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster2EastCanaryName, memberCluster3WestProdName}, nil, "0") + statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster2EastCanaryName, memberCluster3WestProdName}, nil, "0", false) Eventually(statusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -567,7 +567,7 @@ var _ = Describe("placing resources using a CRP of PickAll placement type", func }) It("should update CRP status as expected", func() { - statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster2EastCanaryName, memberCluster3WestProdName}, nil, "0") + statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster2EastCanaryName, memberCluster3WestProdName}, nil, "0", false) Eventually(statusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -648,7 +648,7 @@ var _ = Describe("placing resources using a CRP of PickAll placement type", func }) It("should update CRP status as expected", func() { - statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), nil, nil, "0") + statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), nil, nil, "0", false) Eventually(statusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -721,7 +721,7 @@ var _ = Describe("placing resources using a CRP of PickAll placement type", func }) It("should update CRP status as expected", func() { - statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster2EastCanaryName}, nil, "0") + statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster2EastCanaryName}, nil, "0", false) Eventually(statusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -797,7 +797,7 @@ var _ = Describe("placing resources using a CRP of PickAll placement type", func }) It("should update CRP status as expected", func() { - statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster1EastProdName, memberCluster2EastCanaryName}, nil, "0") + statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster1EastProdName, memberCluster2EastCanaryName}, nil, "0", false) Eventually(statusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -896,7 +896,7 @@ var _ = Describe("placing resources using a CRP of PickAll placement type", func }) It("should update CRP status as expected", func() { - statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster1EastProdName}, nil, "0") + statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster1EastProdName}, nil, "0", false) Eventually(statusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -972,7 +972,7 @@ var _ = Describe("placing resources using a CRP of PickAll placement type", func }) It("should update CRP status as expected", func() { - statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), nil, nil, "0") + statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), nil, nil, "0", false) Eventually(statusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) diff --git a/test/e2e/placement_pickfixed_test.go b/test/e2e/placement_pickfixed_test.go index 8bc016930..9907407e6 100644 --- a/test/e2e/placement_pickfixed_test.go +++ b/test/e2e/placement_pickfixed_test.go @@ -54,7 +54,7 @@ var _ = Describe("placing resources using a CRP of PickFixed placement type", fu }) It("should update CRP status as expected", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster1EastProdName}, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster1EastProdName}, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -112,7 +112,7 @@ var _ = Describe("placing resources using a CRP of PickFixed placement type", fu }) It("should update CRP status as expected", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster2EastCanaryName}, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster2EastCanaryName}, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -168,7 +168,7 @@ var _ = Describe("placing resources using a CRP of PickFixed placement type", fu }) It("should update CRP status as expected", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), nil, []string{memberCluster4UnhealthyName, memberCluster5LeftName, memberCluster6NonExistentName}, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), nil, []string{memberCluster4UnhealthyName, memberCluster5LeftName, memberCluster6NonExistentName}, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) diff --git a/test/e2e/placement_pickn_test.go b/test/e2e/placement_pickn_test.go index fbccdbcfb..82ce27489 100644 --- a/test/e2e/placement_pickn_test.go +++ b/test/e2e/placement_pickn_test.go @@ -55,7 +55,7 @@ var _ = Describe("placing resources using a CRP of PickN placement", func() { }) It("should update CRP status as expected", func() { - statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster3WestProdName}, nil, "0") + statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster3WestProdName}, nil, "0", false) Eventually(statusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -122,7 +122,7 @@ var _ = Describe("placing resources using a CRP of PickN placement", func() { }) It("should update CRP status as expected", func() { - statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster3WestProdName}, nil, "0") + statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster3WestProdName}, nil, "0", false) Eventually(statusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -192,7 +192,7 @@ var _ = Describe("placing resources using a CRP of PickN placement", func() { }) It("should update CRP status as expected", func() { - statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster3WestProdName, memberCluster2EastCanaryName}, nil, "0") + statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster3WestProdName, memberCluster2EastCanaryName}, nil, "0", false) Eventually(statusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -270,7 +270,7 @@ var _ = Describe("placing resources using a CRP of PickN placement", func() { }) It("should update CRP status as expected", func() { - statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster1EastProdName, memberCluster2EastCanaryName}, nil, "0") + statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster1EastProdName, memberCluster2EastCanaryName}, nil, "0", false) Eventually(statusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -385,7 +385,7 @@ var _ = Describe("placing resources using a CRP of PickN placement", func() { }) It("should update CRP status as expected", func() { - statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster1EastProdName, memberCluster3WestProdName}, nil, "0") + statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster1EastProdName, memberCluster3WestProdName}, nil, "0", false) Eventually(statusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -464,7 +464,7 @@ var _ = Describe("placing resources using a CRP of PickN placement", func() { }) It("should update CRP status as expected", func() { - statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster1EastProdName, memberCluster2EastCanaryName}, []string{memberCluster3WestProdName, memberCluster4UnhealthyName, memberCluster5LeftName}, "0") + statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster1EastProdName, memberCluster2EastCanaryName}, []string{memberCluster3WestProdName, memberCluster4UnhealthyName, memberCluster5LeftName}, "0", false) Eventually(statusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -542,7 +542,7 @@ var _ = Describe("placing resources using a CRP of PickN placement", func() { }) It("should update CRP status as expected", func() { - statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), nil, nil, "0") + statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), nil, nil, "0", false) Eventually(statusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) diff --git a/test/e2e/placement_selecting_resources_test.go b/test/e2e/placement_selecting_resources_test.go index 2d939c1c4..f193dd44b 100644 --- a/test/e2e/placement_selecting_resources_test.go +++ b/test/e2e/placement_selecting_resources_test.go @@ -23,7 +23,6 @@ import ( placementv1beta1 "go.goms.io/fleet/apis/placement/v1beta1" "go.goms.io/fleet/pkg/controllers/clusterresourceplacement" "go.goms.io/fleet/pkg/controllers/work" - scheduler "go.goms.io/fleet/pkg/scheduler/framework" "go.goms.io/fleet/pkg/utils" "go.goms.io/fleet/test/e2e/framework" ) @@ -66,7 +65,7 @@ var _ = Describe("creating CRP and selecting resources by name", Ordered, func() }) It("should update CRP status as expected", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP %s status as expected", crpName) }) @@ -133,7 +132,7 @@ var _ = Describe("creating CRP and selecting resources by label", Ordered, func( }) It("should update CRP status as expected", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP %s status as expected", crpName) }) @@ -205,7 +204,7 @@ var _ = Describe("validating CRP when cluster-scoped resources become selected a }) It("should update CRP status as expected", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual([]placementv1beta1.ResourceIdentifier{}, allMemberClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual([]placementv1beta1.ResourceIdentifier{}, allMemberClusterNames, nil, "0", true) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP %s status as expected", crpName) }) @@ -222,7 +221,7 @@ var _ = Describe("validating CRP when cluster-scoped resources become selected a }) It("should update CRP status as expected", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "1") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "1", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP %s status as expected", crpName) }) @@ -294,7 +293,7 @@ var _ = Describe("validating CRP when cluster-scoped resources become unselected }) It("should update CRP status as expected", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP %s status as expected", crpName) }) @@ -313,7 +312,8 @@ var _ = Describe("validating CRP when cluster-scoped resources become unselected It("should remove the selected resources on member clusters", checkIfRemovedWorkResourcesFromAllMemberClusters) It("should update CRP status as expected", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual([]placementv1beta1.ResourceIdentifier{}, allMemberClusterNames, nil, "1") + // If there are no resources selected, the available condition reason will become "AllWorkAreAvailable". + crpStatusUpdatedActual := crpStatusUpdatedActual([]placementv1beta1.ResourceIdentifier{}, allMemberClusterNames, nil, "1", true) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP %s status as expected", crpName) }) @@ -370,7 +370,7 @@ var _ = Describe("validating CRP when cluster-scoped and namespace-scoped resour }) It("should update CRP status as expected", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP %s status as expected", crpName) }) @@ -387,7 +387,7 @@ var _ = Describe("validating CRP when cluster-scoped and namespace-scoped resour It("should update the selected resources on member clusters", checkIfPlacedNamespaceResourceOnAllMemberClusters) It("should update CRP status as expected", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "1") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "1", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP %s status as expected", crpName) }) @@ -406,7 +406,7 @@ var _ = Describe("validating CRP when cluster-scoped and namespace-scoped resour It("should update the selected resources on member clusters", checkIfPlacedWorkResourcesOnAllMemberClusters) It("should update CRP status as expected", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "2") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "2", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP %s status as expected", crpName) }) @@ -471,7 +471,7 @@ var _ = Describe("validating CRP when adding resources in a matching namespace", Version: "v1", }, } - crpStatusUpdatedActual := crpStatusUpdatedActual(wantSelectedResourceIdentifiers, allMemberClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(wantSelectedResourceIdentifiers, allMemberClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP %s status as expected", crpName) }) @@ -493,7 +493,7 @@ var _ = Describe("validating CRP when adding resources in a matching namespace", }) It("should update CRP status as expected", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "1") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "1", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP %s status as expected", crpName) }) @@ -552,7 +552,7 @@ var _ = Describe("validating CRP when deleting resources in a matching namespace }) It("should update CRP status as expected", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP %s status as expected", crpName) }) @@ -571,7 +571,7 @@ var _ = Describe("validating CRP when deleting resources in a matching namespace Version: "v1", }, } - crpStatusUpdatedActual := crpStatusUpdatedActual(wantSelectedResourceIdentifiers, allMemberClusterNames, nil, "1") + crpStatusUpdatedActual := crpStatusUpdatedActual(wantSelectedResourceIdentifiers, allMemberClusterNames, nil, "1", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP %s status as expected", crpName) }) @@ -736,26 +736,7 @@ var _ = Describe("validating CRP when failed to apply resources", Ordered, func( workNamespaceName := fmt.Sprintf(workNamespaceNameTemplate, GinkgoParallelProcess()) appConfigMapName := fmt.Sprintf(appConfigMapNameTemplate, GinkgoParallelProcess()) wantStatus := placementv1beta1.ClusterResourcePlacementStatus{ - Conditions: []metav1.Condition{ - { - Type: string(placementv1beta1.ClusterResourcePlacementScheduledConditionType), - Status: metav1.ConditionTrue, - Reason: scheduler.FullyScheduledReason, - ObservedGeneration: crp.Generation, - }, - { - Type: string(placementv1beta1.ClusterResourcePlacementSynchronizedConditionType), - Status: metav1.ConditionTrue, - Reason: clusterresourceplacement.SynchronizeSucceededReason, - ObservedGeneration: crp.Generation, - }, - { - Type: string(placementv1beta1.ClusterResourcePlacementAppliedConditionType), - Status: metav1.ConditionFalse, - Reason: clusterresourceplacement.ApplyFailedReason, - ObservedGeneration: crp.Generation, - }, - }, + Conditions: crpAppliedFailedConditions(crp.Generation), PlacementStatuses: []placementv1beta1.ResourcePlacementStatus{ { ClusterName: memberCluster1EastProdName, @@ -774,34 +755,15 @@ var _ = Describe("validating CRP when failed to apply resources", Ordered, func( }, }, }, - Conditions: []metav1.Condition{ - { - Type: string(placementv1beta1.ResourceScheduledConditionType), - Status: metav1.ConditionTrue, - Reason: clusterresourceplacement.ResourceScheduleSucceededReason, - ObservedGeneration: crp.Generation, - }, - { - Type: string(placementv1beta1.ResourceWorkSynchronizedConditionType), - Status: metav1.ConditionTrue, - Reason: clusterresourceplacement.WorkSynchronizeSucceededReason, - ObservedGeneration: crp.Generation, - }, - { - Type: string(placementv1beta1.ResourcesAppliedConditionType), - Status: metav1.ConditionFalse, - Reason: clusterresourceplacement.ResourceApplyFailedReason, - ObservedGeneration: crp.Generation, - }, - }, + Conditions: resourcePlacementApplyFailedConditions(crp.Generation), }, { ClusterName: memberCluster2EastCanaryName, - Conditions: resourcePlacementRolloutCompletedConditions(crp.Generation), + Conditions: resourcePlacementRolloutCompletedConditions(crp.Generation, false), }, { ClusterName: memberCluster3WestProdName, - Conditions: resourcePlacementRolloutCompletedConditions(crp.Generation), + Conditions: resourcePlacementRolloutCompletedConditions(crp.Generation, false), }, }, SelectedResources: []placementv1beta1.ResourceIdentifier{ @@ -913,7 +875,7 @@ var _ = Describe("validating CRP when placing cluster scope resource (other than Name: clusterRoleName, }, } - crpStatusUpdatedActual := crpStatusUpdatedActual(wantSelectedResourceIdentifiers, allMemberClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(wantSelectedResourceIdentifiers, allMemberClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP %s status as expected", crpName) }) @@ -1014,7 +976,7 @@ var _ = Describe("validating CRP revision history allowing single revision when }) It("should update CRP status as expected", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(nil, allMemberClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(nil, allMemberClusterNames, nil, "0", true) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP %s status as expected", crpName) }) @@ -1038,7 +1000,7 @@ var _ = Describe("validating CRP revision history allowing single revision when }) It("should update CRP status as expected", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "1") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "1", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP %s status as expected", crpName) }) @@ -1110,7 +1072,7 @@ var _ = Describe("validating CRP revision history allowing multiple revisions wh }) It("should update CRP status as expected", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(nil, allMemberClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(nil, allMemberClusterNames, nil, "0", true) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP %s status as expected", crpName) }) @@ -1134,7 +1096,7 @@ var _ = Describe("validating CRP revision history allowing multiple revisions wh }) It("should update CRP status as expected", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "1") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "1", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP %s status as expected", crpName) }) @@ -1209,7 +1171,7 @@ var _ = Describe("validating CRP when selected resources cross the 1MB limit", O }) It("should update CRP status as expected", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(resourceIdentifiersForMultipleResourcesSnapshots(), []string{memberCluster1EastProdName, memberCluster2EastCanaryName}, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(resourceIdentifiersForMultipleResourcesSnapshots(), []string{memberCluster1EastProdName, memberCluster2EastCanaryName}, nil, "0", false) Eventually(crpStatusUpdatedActual, largeEventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP %s status as expected", crpName) }) diff --git a/test/e2e/rollout_test.go b/test/e2e/rollout_test.go index 06342d613..15bb6c9d0 100644 --- a/test/e2e/rollout_test.go +++ b/test/e2e/rollout_test.go @@ -9,6 +9,7 @@ import ( "encoding/json" "fmt" "strings" + "time" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -80,8 +81,9 @@ var _ = Describe("placing wrapped resources using a CRP", Ordered, func() { }) It("should update CRP status as expected", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(wantSelectedResources, allMemberClusterNames, nil, "0") - Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") + crpStatusUpdatedActual := crpStatusUpdatedActual(wantSelectedResources, allMemberClusterNames, nil, "0", false) + // For the development, at least it will take 4 minutes to be ready. + Eventually(crpStatusUpdatedActual, 6*time.Minute, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) It("should place the resources on all member clusters", func() { diff --git a/test/e2e/scheduler_watchers_test.go b/test/e2e/scheduler_watchers_test.go index 10a674aa1..ebe40b063 100644 --- a/test/e2e/scheduler_watchers_test.go +++ b/test/e2e/scheduler_watchers_test.go @@ -76,7 +76,7 @@ var _ = Describe("responding to specific member cluster changes", func() { It("should place resources on all member clusters", checkIfPlacedWorkResourcesOnAllMemberClusters) It("should pick only healthy clusters in the system", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -88,14 +88,14 @@ var _ = Describe("responding to specific member cluster changes", func() { markMemberClusterAsHealthy(fakeClusterName1ForWatcherTests) }) - It("should propagate works for the new cluster; can mark them as applied", func() { - verifyWorkPropagationAndMarkAsApplied(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) + It("should propagate works for the new cluster; can mark them as available", func() { + verifyWorkPropagationAndMarkAsAvailable(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) }) It("should pick the new cluster along with other healthy clusters", func() { targetClusterNames := allMemberClusterNames targetClusterNames = append(targetClusterNames, fakeClusterName1ForWatcherTests) - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -158,7 +158,7 @@ var _ = Describe("responding to specific member cluster changes", func() { }) It("should not pick any cluster", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), nil, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), nil, nil, "0", false) Eventually(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Should not select any cluster") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Should not select any cluster") }) @@ -178,12 +178,12 @@ var _ = Describe("responding to specific member cluster changes", func() { }) It("should propagate works for the updated cluster; can mark them as applied", func() { - verifyWorkPropagationAndMarkAsApplied(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) + verifyWorkPropagationAndMarkAsAvailable(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) }) It("should pick the new cluster", func() { targetClusterNames := []string{fakeClusterName1ForWatcherTests} - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -233,7 +233,7 @@ var _ = Describe("responding to specific member cluster changes", func() { It("should place resources on all member clusters", checkIfPlacedWorkResourcesOnAllMemberClusters) It("should pick only healthy clusters in the system", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -243,13 +243,13 @@ var _ = Describe("responding to specific member cluster changes", func() { }) It("should propagate works for the cluster; can mark them as applied", func() { - verifyWorkPropagationAndMarkAsApplied(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) + verifyWorkPropagationAndMarkAsAvailable(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) }) It("should pick the cluster, along with other healthy clusters", func() { targetClusterNames := allMemberClusterNames targetClusterNames = append(targetClusterNames, fakeClusterName1ForWatcherTests) - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -315,12 +315,12 @@ var _ = Describe("responding to specific member cluster changes", func() { }) It("should propagate works for the new cluster; can mark them as applied", func() { - verifyWorkPropagationAndMarkAsApplied(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) + verifyWorkPropagationAndMarkAsAvailable(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) }) It("should pick the cluster", func() { targetClusterNames := []string{fakeClusterName1ForWatcherTests} - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -339,7 +339,7 @@ var _ = Describe("responding to specific member cluster changes", func() { It("should keep the cluster in the scheduling decision (ignored during execution semantics)", func() { targetClusterNames := []string{fakeClusterName1ForWatcherTests} - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0", false) Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -389,13 +389,13 @@ var _ = Describe("responding to specific member cluster changes", func() { }) It("should propgate works for the new cluster; can mark them as applied", func() { - verifyWorkPropagationAndMarkAsApplied(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) + verifyWorkPropagationAndMarkAsAvailable(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) }) It("should pick the new cluster, along with other healthy clusters", func() { targetClusterNames := allMemberClusterNames targetClusterNames = append(targetClusterNames, fakeClusterName1ForWatcherTests) - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -407,7 +407,7 @@ var _ = Describe("responding to specific member cluster changes", func() { It("should keep the cluster in the scheduling decision", func() { targetClusterNames := allMemberClusterNames targetClusterNames = append(targetClusterNames, fakeClusterName1ForWatcherTests) - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0", false) Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -454,13 +454,13 @@ var _ = Describe("responding to specific member cluster changes", func() { }) It("should propagate works for the new cluster; can mark them as applied", func() { - verifyWorkPropagationAndMarkAsApplied(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) + verifyWorkPropagationAndMarkAsAvailable(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) }) It("should pick the new cluster, along with other healthy clusters", func() { targetClusterNames := allMemberClusterNames targetClusterNames = append(targetClusterNames, fakeClusterName1ForWatcherTests) - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -470,7 +470,7 @@ var _ = Describe("responding to specific member cluster changes", func() { }) It("should remove the cluster from the scheduling decision", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -514,7 +514,7 @@ var _ = Describe("responding to specific member cluster changes", func() { }) It("should report in CRP status that the cluster is not available", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), nil, []string{fakeClusterName1ForWatcherTests}, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), nil, []string{fakeClusterName1ForWatcherTests}, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -527,12 +527,12 @@ var _ = Describe("responding to specific member cluster changes", func() { }) It("should propagate works for the new cluster; can mark them as applied", func() { - verifyWorkPropagationAndMarkAsApplied(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) + verifyWorkPropagationAndMarkAsAvailable(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) }) It("should pick the new cluster", func() { targetClusterNames := []string{fakeClusterName1ForWatcherTests} - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -581,7 +581,7 @@ var _ = Describe("responding to specific member cluster changes", func() { }) It("should report in CRP status that the cluster is not available", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), nil, []string{fakeClusterName1ForWatcherTests}, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), nil, []string{fakeClusterName1ForWatcherTests}, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -591,12 +591,12 @@ var _ = Describe("responding to specific member cluster changes", func() { }) It("should propagate works for the new cluster; can mark them as applied", func() { - verifyWorkPropagationAndMarkAsApplied(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) + verifyWorkPropagationAndMarkAsAvailable(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) }) It("should pick the new cluster", func() { targetClusterNames := []string{fakeClusterName1ForWatcherTests} - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -645,12 +645,12 @@ var _ = Describe("responding to specific member cluster changes", func() { }) It("should propagate works for the new cluster; can mark them as applied", func() { - verifyWorkPropagationAndMarkAsApplied(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) + verifyWorkPropagationAndMarkAsAvailable(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) }) It("should pick the new cluster", func() { targetClusterNames := []string{fakeClusterName1ForWatcherTests} - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -660,7 +660,8 @@ var _ = Describe("responding to specific member cluster changes", func() { }) It("should report in CRP status that the cluster becomes not available", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), nil, []string{fakeClusterName1ForWatcherTests}, "0") + // resource are still applied in the cluster, crp available condition is true though the scheduled condition is false. + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), nil, []string{fakeClusterName1ForWatcherTests}, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -709,12 +710,12 @@ var _ = Describe("responding to specific member cluster changes", func() { }) It("should propagate works for the new cluster; can mark them as applied", func() { - verifyWorkPropagationAndMarkAsApplied(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) + verifyWorkPropagationAndMarkAsAvailable(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) }) It("should pick the new cluster", func() { targetClusterNames := []string{fakeClusterName1ForWatcherTests} - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -725,7 +726,7 @@ var _ = Describe("responding to specific member cluster changes", func() { It("should keep the cluster as picked", func() { targetClusterNames := []string{fakeClusterName1ForWatcherTests} - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0", false) Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Should keep the cluster as picked") }) @@ -770,7 +771,7 @@ var _ = Describe("responding to specific member cluster changes", func() { It("should place resources on all member clusters", checkIfPlacedWorkResourcesOnAllMemberClusters) It("should pick only healthy clusters in the system", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, []string{fakeClusterName1ForWatcherTests}, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, []string{fakeClusterName1ForWatcherTests}, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -783,14 +784,14 @@ var _ = Describe("responding to specific member cluster changes", func() { }) It("should propagate works for the new cluster; can mark them as applied", func() { - verifyWorkPropagationAndMarkAsApplied(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) + verifyWorkPropagationAndMarkAsAvailable(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) }) It("should pick the new cluster along with other healthy clusters", func() { - targetClusterNames := []string{} + var targetClusterNames []string targetClusterNames = append(targetClusterNames, allMemberClusterNames...) targetClusterNames = append(targetClusterNames, fakeClusterName1ForWatcherTests) - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -854,7 +855,7 @@ var _ = Describe("responding to specific member cluster changes", func() { }) It("should not pick any cluster", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), nil, []string{fakeClusterName1ForWatcherTests}, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), nil, []string{fakeClusterName1ForWatcherTests}, "0", false) Eventually(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Should not select any cluster") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Should not select any cluster") }) @@ -874,12 +875,12 @@ var _ = Describe("responding to specific member cluster changes", func() { }) It("should propagate works for the updated cluster; can mark them as applied", func() { - verifyWorkPropagationAndMarkAsApplied(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) + verifyWorkPropagationAndMarkAsAvailable(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) }) It("should pick the new cluster", func() { targetClusterNames := []string{fakeClusterName1ForWatcherTests} - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -943,7 +944,7 @@ var _ = Describe("responding to specific member cluster changes", func() { }) It("should not pick any cluster", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), nil, []string{fakeClusterName1ForWatcherTests}, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), nil, []string{fakeClusterName1ForWatcherTests}, "0", false) Eventually(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Should not select any cluster") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Should not select any cluster") }) @@ -953,12 +954,12 @@ var _ = Describe("responding to specific member cluster changes", func() { }) It("should propagate works for the updated cluster; can mark them as applied", func() { - verifyWorkPropagationAndMarkAsApplied(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) + verifyWorkPropagationAndMarkAsAvailable(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) }) It("should pick the new cluster", func() { targetClusterNames := []string{fakeClusterName1ForWatcherTests} - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -1011,7 +1012,7 @@ var _ = Describe("responding to specific member cluster changes", func() { It("should place resources on all member clusters", checkIfPlacedWorkResourcesOnAllMemberClusters) It("should pick only healthy clusters in the system", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, []string{fakeClusterName1ForWatcherTests, fakeClusterName2ForWatcherTests}, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, []string{fakeClusterName1ForWatcherTests, fakeClusterName2ForWatcherTests}, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -1022,7 +1023,7 @@ var _ = Describe("responding to specific member cluster changes", func() { }) It("should not pick the member cluster", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, []string{fakeClusterName1ForWatcherTests, fakeClusterName2ForWatcherTests}, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, []string{fakeClusterName1ForWatcherTests, fakeClusterName2ForWatcherTests}, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -1033,15 +1034,15 @@ var _ = Describe("responding to specific member cluster changes", func() { }) It("should propagate works for both new clusters; can mark them as applied", func() { - verifyWorkPropagationAndMarkAsApplied(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) - verifyWorkPropagationAndMarkAsApplied(fakeClusterName2ForWatcherTests, crpName, workResourceIdentifiers()) + verifyWorkPropagationAndMarkAsAvailable(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) + verifyWorkPropagationAndMarkAsAvailable(fakeClusterName2ForWatcherTests, crpName, workResourceIdentifiers()) }) It("should pick both new clusters, along with other clusters", func() { - targetClusterNames := []string{} + var targetClusterNames []string targetClusterNames = append(targetClusterNames, allMemberClusterNames...) targetClusterNames = append(targetClusterNames, fakeClusterName1ForWatcherTests, fakeClusterName2ForWatcherTests) - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -1095,7 +1096,7 @@ var _ = Describe("responding to specific member cluster changes", func() { It("should place resources on all member clusters", checkIfPlacedWorkResourcesOnAllMemberClusters) It("should pick only healthy clusters in the system", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, []string{fakeClusterName1ForWatcherTests}, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, []string{fakeClusterName1ForWatcherTests}, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -1106,7 +1107,7 @@ var _ = Describe("responding to specific member cluster changes", func() { }) It("should not pick the member cluster", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, []string{fakeClusterName1ForWatcherTests}, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, []string{fakeClusterName1ForWatcherTests}, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -1155,13 +1156,13 @@ var _ = Describe("responding to specific member cluster changes", func() { }) It("should propagate works for the new cluster; can mark them as applied", func() { - verifyWorkPropagationAndMarkAsApplied(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) + verifyWorkPropagationAndMarkAsAvailable(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) }) It("should pick the new cluster, along with other healthy clusters", func() { targetClusterNames := allMemberClusterNames targetClusterNames = append(targetClusterNames, fakeClusterName1ForWatcherTests) - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -1171,7 +1172,7 @@ var _ = Describe("responding to specific member cluster changes", func() { }) It("should remove the cluster from the scheduling decision", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, []string{fakeClusterName1ForWatcherTests}, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, []string{fakeClusterName1ForWatcherTests}, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -1235,12 +1236,12 @@ var _ = Describe("responding to specific member cluster changes", func() { }) It("should propagate works for the new cluster; can mark them as applied", func() { - verifyWorkPropagationAndMarkAsApplied(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) + verifyWorkPropagationAndMarkAsAvailable(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) }) It("should pick the new cluster", func() { targetClusterNames := []string{fakeClusterName1ForWatcherTests} - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -1259,7 +1260,7 @@ var _ = Describe("responding to specific member cluster changes", func() { It("should keep the cluster as picked", func() { targetClusterNames := []string{fakeClusterName1ForWatcherTests} - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0", false) Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Should keep the cluster as picked") }) @@ -1322,12 +1323,12 @@ var _ = Describe("responding to specific member cluster changes", func() { }) It("should propagate works for the new cluster; can mark them as applied", func() { - verifyWorkPropagationAndMarkAsApplied(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) + verifyWorkPropagationAndMarkAsAvailable(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) }) It("should pick the new cluster", func() { targetClusterNames := []string{fakeClusterName1ForWatcherTests} - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -1338,7 +1339,7 @@ var _ = Describe("responding to specific member cluster changes", func() { It("should keep the cluster as picked", func() { targetClusterNames := []string{fakeClusterName1ForWatcherTests} - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0", false) Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Should keep the cluster as picked") }) @@ -1397,15 +1398,15 @@ var _ = Describe("responding to specific member cluster changes", func() { It("should place resources on all real member clusters", checkIfPlacedWorkResourcesOnAllMemberClusters) It("should propagate works for both new clusters; can mark them as applied", func() { - verifyWorkPropagationAndMarkAsApplied(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) - verifyWorkPropagationAndMarkAsApplied(fakeClusterName2ForWatcherTests, crpName, workResourceIdentifiers()) + verifyWorkPropagationAndMarkAsAvailable(fakeClusterName1ForWatcherTests, crpName, workResourceIdentifiers()) + verifyWorkPropagationAndMarkAsAvailable(fakeClusterName2ForWatcherTests, crpName, workResourceIdentifiers()) }) It("should pick both new clusters, along with other clusters", func() { - targetClusterNames := []string{} + var targetClusterNames []string targetClusterNames = append(targetClusterNames, allMemberClusterNames...) targetClusterNames = append(targetClusterNames, fakeClusterName1ForWatcherTests, fakeClusterName2ForWatcherTests) - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP status as expected") Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) @@ -1423,10 +1424,10 @@ var _ = Describe("responding to specific member cluster changes", func() { }) It("should keep the cluster as picked", func() { - targetClusterNames := []string{} + var targetClusterNames []string targetClusterNames = append(targetClusterNames, allMemberClusterNames...) targetClusterNames = append(targetClusterNames, fakeClusterName1ForWatcherTests, fakeClusterName2ForWatcherTests) - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), targetClusterNames, nil, "0", false) Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to update CRP status as expected") }) diff --git a/test/e2e/setup.sh b/test/e2e/setup.sh index 6dbb7c885..e066ee64f 100755 --- a/test/e2e/setup.sh +++ b/test/e2e/setup.sh @@ -117,7 +117,6 @@ helm install hub-agent ../../charts/hub-agent/ \ --set image.pullPolicy=Never \ --set image.repository=$REGISTRY/$HUB_AGENT_IMAGE \ --set image.tag=$TAG \ - --set logVerbosity=2 \ --set namespace=fleet-system \ --set enableWebhook=true \ --set webhookClientConnectionType=service \ diff --git a/test/e2e/taint_toleration_test.go b/test/e2e/taint_toleration_test.go index 6ad02954c..130fb82bc 100644 --- a/test/e2e/taint_toleration_test.go +++ b/test/e2e/taint_toleration_test.go @@ -41,7 +41,7 @@ var _ = Describe("placing resource using a cluster resource placement with pickF }) It("should update cluster resource placement status as expected", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update cluster resource placement status as expected") }) @@ -87,7 +87,7 @@ var _ = Describe("placing resources using a cluster resource placement with no p }) It("should update cluster resource placement status as expected", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), selectedClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), selectedClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update cluster resource placement status as expected") }) @@ -110,7 +110,7 @@ var _ = Describe("placing resources using a cluster resource placement with no p }) It("should update cluster resource placement status as expected", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update cluster resource placement status as expected") }) @@ -156,7 +156,7 @@ var _ = Describe("placing resources using a cluster resource placement with no p }) It("should update cluster resource placement status as expected", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), selectedClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), selectedClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update cluster resource placement status as expected") }) @@ -179,7 +179,7 @@ var _ = Describe("placing resources using a cluster resource placement with no p }) It("should update cluster resource placement status as expected", func() { - crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "0") + crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "0", false) Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update cluster resource placement status as expected") }) @@ -256,7 +256,7 @@ var _ = Describe("picking N clusters with affinities and topology spread constra }) It("should update cluster resource placement status as expected", func() { - statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster1EastProdName}, []string{memberCluster2EastCanaryName}, "0") + statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), []string{memberCluster1EastProdName}, []string{memberCluster2EastCanaryName}, "0", false) Eventually(statusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update cluster resource placement status as expected") }) @@ -310,7 +310,7 @@ var _ = Describe("picking all clusters using pickAll placement policy, add taint }) It("should update cluster resource placement status as expected", func() { - statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "0") + statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "0", false) Eventually(statusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update cluster resource placement status as expected") }) @@ -322,7 +322,7 @@ var _ = Describe("picking all clusters using pickAll placement policy, add taint }) It("should still update cluster resource placement status as expected, no status updates", func() { - statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "0") + statusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, "0", false) Eventually(statusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update cluster resource placement status as expected") }) diff --git a/test/e2e/utils_test.go b/test/e2e/utils_test.go index 1b03562ea..ceb8d5ada 100644 --- a/test/e2e/utils_test.go +++ b/test/e2e/utils_test.go @@ -29,9 +29,11 @@ import ( clusterv1beta1 "go.goms.io/fleet/apis/cluster/v1beta1" placementv1beta1 "go.goms.io/fleet/apis/placement/v1beta1" imcv1beta1 "go.goms.io/fleet/pkg/controllers/internalmembercluster/v1beta1" + "go.goms.io/fleet/pkg/controllers/work" "go.goms.io/fleet/pkg/propertyprovider/aks" "go.goms.io/fleet/pkg/propertyprovider/aks/trackers" "go.goms.io/fleet/pkg/utils" + "go.goms.io/fleet/pkg/utils/condition" "go.goms.io/fleet/test/e2e/framework" ) @@ -758,14 +760,14 @@ func ensureCRPAndRelatedResourcesDeletion(crpName string, memberClusters []*fram cleanupWorkResources() } -// verifyWorkPropagationAndMarkAsApplied verifies that works derived from a specific CPR have been created +// verifyWorkPropagationAndMarkAsAvailable verifies that works derived from a specific CPR have been created // for a specific cluster, and marks these works in the specific member cluster's -// reserved namespace as applied. +// reserved namespace as applied and available. // // This is mostly used for simulating member agents for virtual clusters. // // Note that this utility function currently assumes that there is only one work object. -func verifyWorkPropagationAndMarkAsApplied(memberClusterName, crpName string, resourceIdentifiers []placementv1beta1.ResourceIdentifier) { +func verifyWorkPropagationAndMarkAsAvailable(memberClusterName, crpName string, resourceIdentifiers []placementv1beta1.ResourceIdentifier) { memberClusterReservedNS := fmt.Sprintf(utils.NamespaceNameFormat, memberClusterName) // Wait until the works are created. workList := placementv1beta1.WorkList{} @@ -784,23 +786,32 @@ func verifyWorkPropagationAndMarkAsApplied(memberClusterName, crpName string, re return nil }, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to list works") - for _, work := range workList.Items { - workName := work.Name + for _, item := range workList.Items { + workName := item.Name // To be on the safer set, update the status with retries. Eventually(func() error { - work := placementv1beta1.Work{} - if err := hubClient.Get(ctx, types.NamespacedName{Name: workName, Namespace: memberClusterReservedNS}, &work); err != nil { + w := placementv1beta1.Work{} + if err := hubClient.Get(ctx, types.NamespacedName{Name: workName, Namespace: memberClusterReservedNS}, &w); err != nil { return err } - // Set the resource applied condition to the work object. - meta.SetStatusCondition(&work.Status.Conditions, metav1.Condition{ + // Set the resource applied condition to the item object. + meta.SetStatusCondition(&w.Status.Conditions, metav1.Condition{ Type: placementv1beta1.WorkConditionTypeApplied, Status: metav1.ConditionTrue, LastTransitionTime: metav1.Now(), - Reason: "WorkApplied", + Reason: condition.AllWorkAvailableReason, Message: "Set to be applied", - ObservedGeneration: work.Generation, + ObservedGeneration: w.Generation, + }) + + meta.SetStatusCondition(&w.Status.Conditions, metav1.Condition{ + Type: placementv1beta1.WorkConditionTypeAvailable, + Status: metav1.ConditionTrue, + LastTransitionTime: metav1.Now(), + Reason: work.WorkNotTrackableReason, + Message: "Set to be available", + ObservedGeneration: w.Generation, }) // Set the manifest conditions. @@ -810,7 +821,7 @@ func verifyWorkPropagationAndMarkAsApplied(memberClusterName, crpName string, re // just in case the CRP controller changes its behavior in the future. for idx := range resourceIdentifiers { resourceIdentifier := resourceIdentifiers[idx] - work.Status.ManifestConditions = append(work.Status.ManifestConditions, placementv1beta1.ManifestCondition{ + w.Status.ManifestConditions = append(w.Status.ManifestConditions, placementv1beta1.ManifestCondition{ Identifier: placementv1beta1.WorkResourceIdentifier{ Group: resourceIdentifier.Group, Kind: resourceIdentifier.Kind, @@ -830,11 +841,22 @@ func verifyWorkPropagationAndMarkAsApplied(memberClusterName, crpName string, re Reason: "ManifestApplied", Message: "Set to be applied", }, + { + Type: placementv1beta1.WorkConditionTypeAvailable, + Status: metav1.ConditionTrue, + LastTransitionTime: metav1.Now(), + // Typically, this field is set to be the generation number of the + // applied object; here a dummy value is used as there is no object + // actually being applied in the case. + ObservedGeneration: 0, + Reason: "ManifestAvailable", + Message: "Set to be available", + }, }, }) } - return hubClient.Status().Update(ctx, &work) + return hubClient.Status().Update(ctx, &w) }, eventuallyDuration, eventuallyInterval).Should(Succeed()) } }