@@ -18,16 +18,17 @@ package updaterun
1818
1919import (
2020 "context"
21+ "encoding/json"
2122 "fmt"
2223 "strconv"
2324 "time"
2425
2526 "github.com/google/go-cmp/cmp"
2627 . "github.com/onsi/ginkgo/v2"
2728 . "github.com/onsi/gomega"
28- "github.com/prometheus/client_golang/prometheus"
2929 prometheusclientmodel "github.com/prometheus/client_model/go"
3030
31+ corev1 "k8s.io/api/core/v1"
3132 rbacv1 "k8s.io/api/rbac/v1"
3233 apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
3334 "k8s.io/apimachinery/pkg/api/errors"
@@ -38,6 +39,7 @@ import (
3839 "k8s.io/utils/ptr"
3940 "sigs.k8s.io/controller-runtime/pkg/client"
4041 "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
42+ ctrlmetrics "sigs.k8s.io/controller-runtime/pkg/metrics"
4143
4244 clusterv1beta1 "github.com/kubefleet-dev/kubefleet/apis/cluster/v1beta1"
4345 placementv1alpha1 "github.com/kubefleet-dev/kubefleet/apis/placement/v1alpha1"
@@ -54,13 +56,6 @@ const (
5456 // duration is the time to duration to check for Consistently
5557 duration = time .Second * 20
5658
57- // numTargetClusters is the number of scheduled clusters
58- numTargetClusters = 10
59- // numUnscheduledClusters is the number of unscheduled clusters
60- numUnscheduledClusters = 3
61- // numberOfClustersAnnotation is the number of clusters in the test latest policy snapshot
62- numberOfClustersAnnotation = numTargetClusters
63-
6459 // testResourceSnapshotIndex is the index of the test resource snapshot
6560 testResourceSnapshotIndex = "0"
6661)
7772 testUpdateStrategyName string
7873 testCROName string
7974 updateRunNamespacedName types.NamespacedName
80- testNamespace []byte
81- customRegistry * prometheus.Registry
8275)
8376
8477var _ = Describe ("Test the clusterStagedUpdateRun controller" , func () {
@@ -90,15 +83,13 @@ var _ = Describe("Test the clusterStagedUpdateRun controller", func() {
9083 testUpdateStrategyName = "updatestrategy-" + utils .RandStr ()
9184 testCROName = "cro-" + utils .RandStr ()
9285 updateRunNamespacedName = types.NamespacedName {Name : testUpdateRunName }
93-
94- customRegistry = initializeUpdateRunMetricsRegistry ()
9586 })
9687
9788 AfterEach (func () {
9889 By ("Checking the update run status metrics are removed" )
9990 // No metrics are emitted as all are removed after updateRun is deleted.
100- validateUpdateRunMetricsEmitted (customRegistry )
101- unregisterUpdateRunMetrics ( customRegistry )
91+ validateUpdateRunMetricsEmitted ()
92+ resetUpdateRunMetrics ( )
10293 })
10394
10495 Context ("Test reconciling a clusterStagedUpdateRun" , func () {
@@ -242,23 +233,14 @@ var _ = Describe("Test the clusterStagedUpdateRun controller", func() {
242233 })
243234})
244235
245- func initializeUpdateRunMetricsRegistry () * prometheus.Registry {
246- // Create a test registry
247- customRegistry := prometheus .NewRegistry ()
248- Expect (customRegistry .Register (metrics .FleetUpdateRunStatusLastTimestampSeconds )).Should (Succeed ())
249- // Reset metrics before each test
236+ func resetUpdateRunMetrics () {
250237 metrics .FleetUpdateRunStatusLastTimestampSeconds .Reset ()
251- return customRegistry
252- }
253-
254- func unregisterUpdateRunMetrics (registry * prometheus.Registry ) {
255- Expect (registry .Unregister (metrics .FleetUpdateRunStatusLastTimestampSeconds )).Should (BeTrue ())
256238}
257239
258240// validateUpdateRunMetricsEmitted validates the update run status metrics are emitted and are emitted in the correct order.
259- func validateUpdateRunMetricsEmitted (registry * prometheus. Registry , wantMetrics ... * prometheusclientmodel.Metric ) {
241+ func validateUpdateRunMetricsEmitted (wantMetrics ... * prometheusclientmodel.Metric ) {
260242 Eventually (func () error {
261- metricFamilies , err := registry .Gather ()
243+ metricFamilies , err := ctrlmetrics . Registry .Gather ()
262244 if err != nil {
263245 return fmt .Errorf ("failed to gather metrics: %w" , err )
264246 }
@@ -388,7 +370,7 @@ func generateTestClusterResourcePlacement() *placementv1beta1.ClusterResourcePla
388370 }
389371}
390372
391- func generateTestClusterSchedulingPolicySnapshot (idx int ) * placementv1beta1.ClusterSchedulingPolicySnapshot {
373+ func generateTestClusterSchedulingPolicySnapshot (idx , numberOfClustersAnnotation int ) * placementv1beta1.ClusterSchedulingPolicySnapshot {
392374 return & placementv1beta1.ClusterSchedulingPolicySnapshot {
393375 ObjectMeta : metav1.ObjectMeta {
394376 Name : fmt .Sprintf (placementv1beta1 .PolicySnapshotNameFmt , testCRPName , idx ),
@@ -410,6 +392,51 @@ func generateTestClusterSchedulingPolicySnapshot(idx int) *placementv1beta1.Clus
410392 }
411393}
412394
395+ func generateTestClusterResourceBindingsAndClusters (policySnapshotIndex int ) ([]* placementv1beta1.ClusterResourceBinding , []* clusterv1beta1.MemberCluster , []* clusterv1beta1.MemberCluster ) {
396+ numTargetClusters := 10
397+ numUnscheduledClusters := 3
398+ policySnapshotName := fmt .Sprintf (placementv1beta1 .PolicySnapshotNameFmt , testCRPName , policySnapshotIndex )
399+ resourceBindings := make ([]* placementv1beta1.ClusterResourceBinding , numTargetClusters + numUnscheduledClusters )
400+ targetClusters := make ([]* clusterv1beta1.MemberCluster , numTargetClusters )
401+ for i := range targetClusters {
402+ // split the clusters into 2 regions
403+ region := regionEastus
404+ if i % 2 == 0 {
405+ region = regionWestus
406+ }
407+ // reserse the order of the clusters by index
408+ targetClusters [i ] = generateTestMemberCluster (numTargetClusters - 1 - i , "cluster-" + strconv .Itoa (i ), map [string ]string {"group" : "prod" , "region" : region })
409+ resourceBindings [i ] = generateTestClusterResourceBinding (policySnapshotName , targetClusters [i ].Name , placementv1beta1 .BindingStateScheduled )
410+ }
411+
412+ unscheduledClusters := make ([]* clusterv1beta1.MemberCluster , numUnscheduledClusters )
413+ for i := range unscheduledClusters {
414+ unscheduledClusters [i ] = generateTestMemberCluster (i , "unscheduled-cluster-" + strconv .Itoa (i ), map [string ]string {"group" : "staging" })
415+ // update the policySnapshot name so that these clusters are considered to-be-deleted
416+ resourceBindings [numTargetClusters + i ] = generateTestClusterResourceBinding (policySnapshotName + "a" , unscheduledClusters [i ].Name , placementv1beta1 .BindingStateUnscheduled )
417+ }
418+ return resourceBindings , targetClusters , unscheduledClusters
419+ }
420+
421+ func generateSmallTestClusterResourceBindingsAndClusters (policySnapshotIndex int ) ([]* placementv1beta1.ClusterResourceBinding , []* clusterv1beta1.MemberCluster , []* clusterv1beta1.MemberCluster ) {
422+ numTargetClusters := 3
423+ policySnapshotName := fmt .Sprintf (placementv1beta1 .PolicySnapshotNameFmt , testCRPName , policySnapshotIndex )
424+ resourceBindings := make ([]* placementv1beta1.ClusterResourceBinding , numTargetClusters )
425+ targetClusters := make ([]* clusterv1beta1.MemberCluster , numTargetClusters )
426+ for i := range targetClusters {
427+ // split the clusters into 2 regions
428+ region := regionEastus
429+ if i % 2 == 0 {
430+ region = regionWestus
431+ }
432+ // reserse the order of the clusters by index
433+ targetClusters [i ] = generateTestMemberCluster (numTargetClusters - 1 - i , "cluster-" + strconv .Itoa (i ), map [string ]string {"group" : "prod" , "region" : region })
434+ resourceBindings [i ] = generateTestClusterResourceBinding (policySnapshotName , targetClusters [i ].Name , placementv1beta1 .BindingStateScheduled )
435+ }
436+ unscheduledClusters := make ([]* clusterv1beta1.MemberCluster , 0 )
437+ return resourceBindings , targetClusters , unscheduledClusters
438+ }
439+
413440func generateTestClusterResourceBinding (policySnapshotName , targetCluster string , state placementv1beta1.BindingState ) * placementv1beta1.ClusterResourceBinding {
414441 binding := & placementv1beta1.ClusterResourceBinding {
415442 ObjectMeta : metav1.ObjectMeta {
@@ -504,7 +531,36 @@ func generateTestClusterStagedUpdateStrategy() *placementv1beta1.ClusterStagedUp
504531 }
505532}
506533
534+ func generateTestClusterStagedUpdateStrategyWithSingleStage (afterStageTasks []placementv1beta1.AfterStageTask ) * placementv1beta1.ClusterStagedUpdateStrategy {
535+ return & placementv1beta1.ClusterStagedUpdateStrategy {
536+ ObjectMeta : metav1.ObjectMeta {
537+ Name : testUpdateStrategyName ,
538+ },
539+ Spec : placementv1beta1.StagedUpdateStrategySpec {
540+ Stages : []placementv1beta1.StageConfig {
541+ {
542+ Name : "stage1" ,
543+ LabelSelector : & metav1.LabelSelector {}, // Select all clusters.
544+ AfterStageTasks : afterStageTasks ,
545+ },
546+ },
547+ },
548+ }
549+ }
550+
507551func generateTestClusterResourceSnapshot () * placementv1beta1.ClusterResourceSnapshot {
552+ testNamespace , _ := json .Marshal (corev1.Namespace {
553+ TypeMeta : metav1.TypeMeta {
554+ APIVersion : "v1" ,
555+ Kind : "Namespace" ,
556+ },
557+ ObjectMeta : metav1.ObjectMeta {
558+ Name : "test-namespace" ,
559+ Labels : map [string ]string {
560+ "fleet.azure.com/name" : "test-namespace" ,
561+ },
562+ },
563+ })
508564 clusterResourceSnapshot := & placementv1beta1.ClusterResourceSnapshot {
509565 ObjectMeta : metav1.ObjectMeta {
510566 Name : testResourceSnapshotName ,
@@ -671,6 +727,8 @@ func generateTrueCondition(obj client.Object, condType any) metav1.Condition {
671727 switch cond {
672728 case placementv1beta1 .ResourceBindingAvailable :
673729 reason = condition .AvailableReason
730+ case placementv1beta1 .ResourceBindingDiffReported :
731+ reason = condition .DiffReportedStatusTrueReason
674732 }
675733 typeStr = string (cond )
676734 }
@@ -713,6 +771,8 @@ func generateFalseCondition(obj client.Object, condType any) metav1.Condition {
713771 switch cond {
714772 case placementv1beta1 .ResourceBindingApplied :
715773 reason = condition .ApplyFailedReason
774+ case placementv1beta1 .ResourceBindingDiffReported :
775+ reason = condition .DiffReportedStatusFalseReason
716776 }
717777 typeStr = string (cond )
718778 }
0 commit comments