From 54e242160833708627bf6a4d71bea836c5743963 Mon Sep 17 00:00:00 2001 From: Patrick Seidensal Date: Wed, 4 Mar 2026 09:02:25 +0100 Subject: [PATCH 1/3] rollout: Make maxNew configurable Refers to #3829 --- charts/fleet-crd/templates/crds.yaml | 33 +++++++- .../reconciler/bundle_controller.go | 2 +- .../controller/reconciler/bundle_status.go | 13 +-- .../reconciler/bundle_status_test.go | 63 +++++++++++++++ internal/cmd/controller/target/partition.go | 12 ++- .../cmd/controller/target/rollout_test.go | 80 +++++++++++++++++++ .../fleet.cattle.io/v1alpha1/bundle_types.go | 11 ++- .../v1alpha1/zz_generated.deepcopy.go | 5 ++ 8 files changed, 206 insertions(+), 13 deletions(-) create mode 100644 internal/cmd/controller/reconciler/bundle_status_test.go diff --git a/charts/fleet-crd/templates/crds.yaml b/charts/fleet-crd/templates/crds.yaml index 7cc6cd2cea..395f0ed38c 100644 --- a/charts/fleet-crd/templates/crds.yaml +++ b/charts/fleet-crd/templates/crds.yaml @@ -2226,6 +2226,18 @@ spec: default: 200' nullable: true type: integer + maxNew: + description: 'MaxNew is the maximum number of new BundleDeployments + that can be created + + in a single reconciliation. This limits the rate at which + new deployments + + are staged when a bundle is first applied to many clusters. + + default: 50' + nullable: true + type: integer maxUnavailable: anyOf: - type: integer @@ -3282,10 +3294,13 @@ spec: type: string type: object maxNew: - description: 'MaxNew is always 50. A bundle change can only stage - 50 + description: 'MaxNew is the maximum number of BundleDeployments + that can be created + + in a single reconciliation. Defaults to 50. Can be configured + via - bundledeployments at a time.' + rolloutStrategy.maxNew in the Bundle spec.' type: integer maxUnavailable: description: 'MaxUnavailable is the maximum number of unavailable @@ -8453,6 +8468,18 @@ spec: default: 200' nullable: true type: integer + maxNew: + description: 'MaxNew is the maximum number of new BundleDeployments + that can be created + + in a single reconciliation. This limits the rate at which + new deployments + + are staged when a bundle is first applied to many clusters. + + default: 50' + nullable: true + type: integer maxUnavailable: anyOf: - type: integer diff --git a/internal/cmd/controller/reconciler/bundle_controller.go b/internal/cmd/controller/reconciler/bundle_controller.go index bb546c9f96..92fc775862 100644 --- a/internal/cmd/controller/reconciler/bundle_controller.go +++ b/internal/cmd/controller/reconciler/bundle_controller.go @@ -292,7 +292,7 @@ func (r *BundleReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr } logger = logger.WithValues("manifestID", manifestID) - if err := resetStatus(&bundle.Status, matchedTargets); err != nil { + if err := resetStatus(&bundle.Status, matchedTargets, bundle.Spec.RolloutStrategy); err != nil { err = fmt.Errorf("failed to reset bundle status from targets: %w", err) return ctrl.Result{}, r.updateErrorStatus(ctx, bundleOrig, bundle, err) diff --git a/internal/cmd/controller/reconciler/bundle_status.go b/internal/cmd/controller/reconciler/bundle_status.go index 703380f1e8..08ddd20aca 100644 --- a/internal/cmd/controller/reconciler/bundle_status.go +++ b/internal/cmd/controller/reconciler/bundle_status.go @@ -8,12 +8,15 @@ import ( fleet "github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1" ) -const ( - maxNew = 50 -) +// defaultMaxNew mirrors the default in the target package, kept in sync for +// the status field which reflects the configured value. +const defaultMaxNew = 50 -func resetStatus(status *fleet.BundleStatus, allTargets []*target.Target) (err error) { - status.MaxNew = maxNew +func resetStatus(status *fleet.BundleStatus, allTargets []*target.Target, rollout *fleet.RolloutStrategy) (err error) { + status.MaxNew = defaultMaxNew + if rollout != nil && rollout.MaxNew != nil { + status.MaxNew = *rollout.MaxNew + } status.Summary = fleet.BundleSummary{} status.PartitionStatus = nil status.Unavailable = 0 diff --git a/internal/cmd/controller/reconciler/bundle_status_test.go b/internal/cmd/controller/reconciler/bundle_status_test.go new file mode 100644 index 0000000000..f850665485 --- /dev/null +++ b/internal/cmd/controller/reconciler/bundle_status_test.go @@ -0,0 +1,63 @@ +package reconciler + +import ( + "testing" + + "github.com/rancher/fleet/internal/cmd/controller/target" + fleet "github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1" +) + +func intPtr(i int) *int { + return &i +} + +func Test_resetStatus_MaxNew(t *testing.T) { + tests := []struct { + name string + rollout *fleet.RolloutStrategy + wantMaxNew int + }{ + { + name: "nil rollout strategy uses default maxNew", + rollout: nil, + wantMaxNew: defaultMaxNew, + }, + { + name: "rollout strategy without MaxNew uses default", + rollout: &fleet.RolloutStrategy{}, + wantMaxNew: defaultMaxNew, + }, + { + name: "rollout strategy with MaxNew configured uses it", + rollout: &fleet.RolloutStrategy{ + MaxNew: intPtr(100), + }, + wantMaxNew: 100, + }, + { + name: "rollout strategy with MaxNew of 0 prevents new deployments", + rollout: &fleet.RolloutStrategy{ + MaxNew: intPtr(0), + }, + wantMaxNew: 0, + }, + { + name: "rollout strategy with MaxNew larger than default is accepted", + rollout: &fleet.RolloutStrategy{ + MaxNew: intPtr(200), + }, + wantMaxNew: 200, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + status := &fleet.BundleStatus{} + if err := resetStatus(status, []*target.Target{}, tt.rollout); err != nil { + t.Fatalf("resetStatus() failed: %v", err) + } + if status.MaxNew != tt.wantMaxNew { + t.Errorf("MaxNew = %d, want %d", status.MaxNew, tt.wantMaxNew) + } + }) + } +} diff --git a/internal/cmd/controller/target/partition.go b/internal/cmd/controller/target/partition.go index 85044172bb..d0b3aaa0c3 100644 --- a/internal/cmd/controller/target/partition.go +++ b/internal/cmd/controller/target/partition.go @@ -8,6 +8,8 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +const defaultMaxNew = 50 + type partition struct { Status fleet.PartitionStatus Targets []*Target @@ -17,6 +19,12 @@ type partition struct { // It creates Deployments in allTargets if they are missing. // It updates Deployments in allTargets if they are out of sync (DeploymentID != StagedDeploymentID). func UpdatePartitions(status *fleet.BundleStatus, allTargets []*Target) (err error) { + rollout := getRollout(allTargets) + maxNew := defaultMaxNew + if rollout.MaxNew != nil { + maxNew = *rollout.MaxNew + } + partitions, err := partitions(allTargets) if err != nil { return err @@ -30,8 +38,8 @@ func UpdatePartitions(status *fleet.BundleStatus, allTargets []*Target) (err err for _, partition := range partitions { for _, target := range partition.Targets { - // for a new bundledeployment, only stage the first maxNew (50) targets - if target.Deployment == nil && status.NewlyCreated < status.MaxNew { + // for a new bundledeployment, only stage the first maxNew targets + if target.Deployment == nil && status.NewlyCreated < maxNew { status.NewlyCreated++ target.Deployment = &fleet.BundleDeployment{ ObjectMeta: metav1.ObjectMeta{ diff --git a/internal/cmd/controller/target/rollout_test.go b/internal/cmd/controller/target/rollout_test.go index f416c738fe..1058867785 100644 --- a/internal/cmd/controller/target/rollout_test.go +++ b/internal/cmd/controller/target/rollout_test.go @@ -141,6 +141,29 @@ func intPtr(i int) *int { return &i } +// createNewTargets creates targets without existing Deployments, simulating +// clusters that do not yet have a BundleDeployment. +func createNewTargets(count int) []*Target { + targets := make([]*Target, count) + for i := range count { + targets[i] = &Target{ + Cluster: &fleet.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "cluster-" + strconv.Itoa(i+1), + }, + }, + Bundle: &fleet.Bundle{ + ObjectMeta: metav1.ObjectMeta{ + Name: "bundle-1", + }, + }, + DeploymentID: "deployment-" + strconv.Itoa(i+1), + } + } + return targets +} + func Test_autoPartition(t *testing.T) { tests := []struct { name string @@ -476,3 +499,60 @@ func Test_manualPartition(t *testing.T) { }) } } + +func Test_UpdatePartitions_MaxNew(t *testing.T) { + tests := []struct { + name string + maxNew *int + targetCount int + wantNewlyCreated int + }{ + { + name: "maxNew configured on rollout strategy limits newly created deployments", + maxNew: intPtr(10), + targetCount: 100, + wantNewlyCreated: 10, + }, + { + name: "maxNew larger than target count creates all deployments", + maxNew: intPtr(200), + targetCount: 20, + wantNewlyCreated: 20, + }, + { + name: "maxNew of 0 creates no new deployments", + maxNew: intPtr(0), + targetCount: 10, + wantNewlyCreated: 0, + }, + { + name: "nil maxNew uses default of 50", + maxNew: nil, + targetCount: 100, + wantNewlyCreated: defaultMaxNew, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + targets := createNewTargets(tt.targetCount) + for _, tgt := range targets { + tgt.Bundle.Spec.RolloutStrategy = &fleet.RolloutStrategy{ + MaxNew: tt.maxNew, + } + } + if err := UpdatePartitions(&fleet.BundleStatus{}, targets); err != nil { + t.Fatalf("UpdatePartitions() failed: %v", err) + } + // Verify the right number of targets got a Deployment assigned + deploymentCount := 0 + for _, tgt := range targets { + if tgt.Deployment != nil { + deploymentCount++ + } + } + if deploymentCount != tt.wantNewlyCreated { + t.Errorf("targets with Deployment = %d, want %d", deploymentCount, tt.wantNewlyCreated) + } + }) + } +} diff --git a/pkg/apis/fleet.cattle.io/v1alpha1/bundle_types.go b/pkg/apis/fleet.cattle.io/v1alpha1/bundle_types.go index aef17f9c4e..1528f52d8e 100644 --- a/pkg/apis/fleet.cattle.io/v1alpha1/bundle_types.go +++ b/pkg/apis/fleet.cattle.io/v1alpha1/bundle_types.go @@ -200,6 +200,12 @@ type RolloutStrategy struct { // default: 200 // +nullable AutoPartitionThreshold *int `json:"autoPartitionThreshold,omitempty"` + // MaxNew is the maximum number of new BundleDeployments that can be created + // in a single reconciliation. This limits the rate at which new deployments + // are staged when a bundle is first applied to many clusters. + // default: 50 + // +nullable + MaxNew *int `json:"maxNew,omitempty"` // A list of definitions of partitions. If any target clusters do not match // the configuration they are added to partitions at the end following the // autoPartitionSize. @@ -383,8 +389,9 @@ type BundleStatus struct { // percentage of unavailable partitions. // +optional MaxUnavailablePartitions int `json:"maxUnavailablePartitions"` - // MaxNew is always 50. A bundle change can only stage 50 - // bundledeployments at a time. + // MaxNew is the maximum number of BundleDeployments that can be created + // in a single reconciliation. Defaults to 50. Can be configured via + // rolloutStrategy.maxNew in the Bundle spec. MaxNew int `json:"maxNew,omitempty"` // PartitionStatus lists the status of each partition. PartitionStatus []PartitionStatus `json:"partitions,omitempty"` diff --git a/pkg/apis/fleet.cattle.io/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/fleet.cattle.io/v1alpha1/zz_generated.deepcopy.go index bbd4786e72..8c11984897 100644 --- a/pkg/apis/fleet.cattle.io/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/fleet.cattle.io/v1alpha1/zz_generated.deepcopy.go @@ -2353,6 +2353,11 @@ func (in *RolloutStrategy) DeepCopyInto(out *RolloutStrategy) { *out = new(int) **out = **in } + if in.MaxNew != nil { + in, out := &in.MaxNew, &out.MaxNew + *out = new(int) + **out = **in + } if in.Partitions != nil { in, out := &in.Partitions, &out.Partitions *out = make([]Partition, len(*in)) From 743e5002cdf09952026e9f4a7144a533e5b3baef Mon Sep 17 00:00:00 2001 From: Patrick Seidensal Date: Wed, 4 Mar 2026 16:43:00 +0100 Subject: [PATCH 2/3] Fix: Set spec.MaxNew for CLI --- internal/cmd/cli/target.go | 23 +++++-- internal/cmd/cli/target_test.go | 110 ++++++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+), 5 deletions(-) create mode 100644 internal/cmd/cli/target_test.go diff --git a/internal/cmd/cli/target.go b/internal/cmd/cli/target.go index 962ac8c898..aa9451f713 100644 --- a/internal/cmd/cli/target.go +++ b/internal/cmd/cli/target.go @@ -152,11 +152,7 @@ func (t *Target) Run(cmd *cobra.Command, args []string) error { cmd.Println("---") cmd.Println(string(b)) - // Needs to be set to print all targets. UpdatePartitions will only - // create this many deployments if the bundle is new. - bundle.Status.MaxNew = len(matchedTargets) - - if err := target.UpdatePartitions(&bundle.Status, matchedTargets); err != nil { + if err := stageAllTargets(bundle, matchedTargets); err != nil { return err } for _, target := range matchedTargets { @@ -177,3 +173,20 @@ func (t *Target) Run(cmd *cobra.Command, args []string) error { return nil } + +// stageAllTargets overrides maxNew to the total number of matched targets so +// that UpdatePartitions stages a deployment for every target, not just the +// first target.DefaultMaxNew. +// +// NOTE: mutating bundle.Spec.RolloutStrategy is visible to UpdatePartitions +// because target.Manager.Targets() stores the same bundle pointer in every +// target's Bundle field, and UpdatePartitions reads MaxNew from +// targets[0].Bundle.Spec.RolloutStrategy. +func stageAllTargets(bundle *v1alpha1.Bundle, matchedTargets []*target.Target) error { + count := len(matchedTargets) + if bundle.Spec.RolloutStrategy == nil { + bundle.Spec.RolloutStrategy = &v1alpha1.RolloutStrategy{} + } + bundle.Spec.RolloutStrategy.MaxNew = &count + return target.UpdatePartitions(&bundle.Status, matchedTargets) +} diff --git a/internal/cmd/cli/target_test.go b/internal/cmd/cli/target_test.go new file mode 100644 index 0000000000..d1db6b1acf --- /dev/null +++ b/internal/cmd/cli/target_test.go @@ -0,0 +1,110 @@ +package cli + +import ( + "strconv" + "testing" + + "github.com/rancher/fleet/internal/cmd/controller/target" + fleet "github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// newTargetsWithoutDeployments creates targets that share a single bundle +// pointer, matching what the real target builder produces. +func newTargetsWithoutDeployments(bundle *fleet.Bundle, count int) []*target.Target { + targets := make([]*target.Target, count) + for i := range count { + targets[i] = &target.Target{ + Cluster: &fleet.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "cluster-" + strconv.Itoa(i+1), + }, + }, + Bundle: bundle, + DeploymentID: "deployment-" + strconv.Itoa(i+1), + } + } + return targets +} + +func Test_stageAllTargets(t *testing.T) { + tests := []struct { + name string + targetCount int + }{ + { + name: "stages all targets when count exceeds default maxNew", + targetCount: 100, + }, + { + name: "stages all targets when count is below default maxNew", + targetCount: 10, + }, + { + name: "no targets produces no deployments", + targetCount: 0, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + bundle := &fleet.Bundle{ObjectMeta: metav1.ObjectMeta{Name: "bundle-1"}} + targets := newTargetsWithoutDeployments(bundle, tt.targetCount) + + if err := stageAllTargets(bundle, targets); err != nil { + t.Fatalf("stageAllTargets() failed: %v", err) + } + + deploymentCount := 0 + for _, tgt := range targets { + if tgt.Deployment != nil { + deploymentCount++ + } + } + if deploymentCount != tt.targetCount { + t.Errorf("staged %d deployments, want %d", deploymentCount, tt.targetCount) + } + }) + } +} + +func Test_stageAllTargets_overwritesExistingMaxNew(t *testing.T) { + // MaxNew=2 is less than the target count (5); if stageAllTargets does not + // overwrite it, UpdatePartitions would only stage 2 deployments. + two := 2 + bundle := &fleet.Bundle{ObjectMeta: metav1.ObjectMeta{Name: "bundle-1"}} + bundle.Spec.RolloutStrategy = &fleet.RolloutStrategy{MaxNew: &two} + targets := newTargetsWithoutDeployments(bundle, 5) + + if err := stageAllTargets(bundle, targets); err != nil { + t.Fatalf("stageAllTargets() failed: %v", err) + } + + deploymentCount := 0 + for _, tgt := range targets { + if tgt.Deployment != nil { + deploymentCount++ + } + } + if deploymentCount != 5 { + t.Errorf("staged %d deployments, want 5", deploymentCount) + } +} + +func Test_stageAllTargets_preservesExistingRolloutStrategy(t *testing.T) { + ten := 10 + existing := &fleet.RolloutStrategy{ + AutoPartitionThreshold: &ten, + } + bundle := &fleet.Bundle{ObjectMeta: metav1.ObjectMeta{Name: "bundle-1"}} + bundle.Spec.RolloutStrategy = existing + targets := newTargetsWithoutDeployments(bundle, 5) + + if err := stageAllTargets(bundle, targets); err != nil { + t.Fatalf("stageAllTargets() failed: %v", err) + } + + if bundle.Spec.RolloutStrategy.AutoPartitionThreshold == nil || *bundle.Spec.RolloutStrategy.AutoPartitionThreshold != 10 { + t.Error("existing rollout strategy fields were overwritten") + } +} From 3614e7805d434aedbcdfb6d25ec4b190941ce8ef Mon Sep 17 00:00:00 2001 From: Patrick Seidensal Date: Wed, 4 Mar 2026 16:46:36 +0100 Subject: [PATCH 3/3] Remove MaxNew from bundle status --- charts/fleet-crd/templates/crds.yaml | 9 --- internal/cmd/cli/target_test.go | 2 +- .../reconciler/bundle_controller.go | 2 +- .../controller/reconciler/bundle_status.go | 10 +-- .../reconciler/bundle_status_test.go | 63 ------------------- internal/cmd/controller/target/partition.go | 4 +- .../cmd/controller/target/rollout_test.go | 2 +- internal/cmd/controller/target/target.go | 5 ++ .../fleet.cattle.io/v1alpha1/bundle_types.go | 4 -- 9 files changed, 10 insertions(+), 91 deletions(-) delete mode 100644 internal/cmd/controller/reconciler/bundle_status_test.go diff --git a/charts/fleet-crd/templates/crds.yaml b/charts/fleet-crd/templates/crds.yaml index 395f0ed38c..56c67b504a 100644 --- a/charts/fleet-crd/templates/crds.yaml +++ b/charts/fleet-crd/templates/crds.yaml @@ -3293,15 +3293,6 @@ spec: nullable: true type: string type: object - maxNew: - description: 'MaxNew is the maximum number of BundleDeployments - that can be created - - in a single reconciliation. Defaults to 50. Can be configured - via - - rolloutStrategy.maxNew in the Bundle spec.' - type: integer maxUnavailable: description: 'MaxUnavailable is the maximum number of unavailable deployments. See diff --git a/internal/cmd/cli/target_test.go b/internal/cmd/cli/target_test.go index d1db6b1acf..3c6e3c2825 100644 --- a/internal/cmd/cli/target_test.go +++ b/internal/cmd/cli/target_test.go @@ -92,7 +92,7 @@ func Test_stageAllTargets_overwritesExistingMaxNew(t *testing.T) { } func Test_stageAllTargets_preservesExistingRolloutStrategy(t *testing.T) { - ten := 10 + ten := 10 existing := &fleet.RolloutStrategy{ AutoPartitionThreshold: &ten, } diff --git a/internal/cmd/controller/reconciler/bundle_controller.go b/internal/cmd/controller/reconciler/bundle_controller.go index 92fc775862..bb546c9f96 100644 --- a/internal/cmd/controller/reconciler/bundle_controller.go +++ b/internal/cmd/controller/reconciler/bundle_controller.go @@ -292,7 +292,7 @@ func (r *BundleReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr } logger = logger.WithValues("manifestID", manifestID) - if err := resetStatus(&bundle.Status, matchedTargets, bundle.Spec.RolloutStrategy); err != nil { + if err := resetStatus(&bundle.Status, matchedTargets); err != nil { err = fmt.Errorf("failed to reset bundle status from targets: %w", err) return ctrl.Result{}, r.updateErrorStatus(ctx, bundleOrig, bundle, err) diff --git a/internal/cmd/controller/reconciler/bundle_status.go b/internal/cmd/controller/reconciler/bundle_status.go index 08ddd20aca..43b010b19f 100644 --- a/internal/cmd/controller/reconciler/bundle_status.go +++ b/internal/cmd/controller/reconciler/bundle_status.go @@ -8,15 +8,7 @@ import ( fleet "github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1" ) -// defaultMaxNew mirrors the default in the target package, kept in sync for -// the status field which reflects the configured value. -const defaultMaxNew = 50 - -func resetStatus(status *fleet.BundleStatus, allTargets []*target.Target, rollout *fleet.RolloutStrategy) (err error) { - status.MaxNew = defaultMaxNew - if rollout != nil && rollout.MaxNew != nil { - status.MaxNew = *rollout.MaxNew - } +func resetStatus(status *fleet.BundleStatus, allTargets []*target.Target) (err error) { status.Summary = fleet.BundleSummary{} status.PartitionStatus = nil status.Unavailable = 0 diff --git a/internal/cmd/controller/reconciler/bundle_status_test.go b/internal/cmd/controller/reconciler/bundle_status_test.go deleted file mode 100644 index f850665485..0000000000 --- a/internal/cmd/controller/reconciler/bundle_status_test.go +++ /dev/null @@ -1,63 +0,0 @@ -package reconciler - -import ( - "testing" - - "github.com/rancher/fleet/internal/cmd/controller/target" - fleet "github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1" -) - -func intPtr(i int) *int { - return &i -} - -func Test_resetStatus_MaxNew(t *testing.T) { - tests := []struct { - name string - rollout *fleet.RolloutStrategy - wantMaxNew int - }{ - { - name: "nil rollout strategy uses default maxNew", - rollout: nil, - wantMaxNew: defaultMaxNew, - }, - { - name: "rollout strategy without MaxNew uses default", - rollout: &fleet.RolloutStrategy{}, - wantMaxNew: defaultMaxNew, - }, - { - name: "rollout strategy with MaxNew configured uses it", - rollout: &fleet.RolloutStrategy{ - MaxNew: intPtr(100), - }, - wantMaxNew: 100, - }, - { - name: "rollout strategy with MaxNew of 0 prevents new deployments", - rollout: &fleet.RolloutStrategy{ - MaxNew: intPtr(0), - }, - wantMaxNew: 0, - }, - { - name: "rollout strategy with MaxNew larger than default is accepted", - rollout: &fleet.RolloutStrategy{ - MaxNew: intPtr(200), - }, - wantMaxNew: 200, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - status := &fleet.BundleStatus{} - if err := resetStatus(status, []*target.Target{}, tt.rollout); err != nil { - t.Fatalf("resetStatus() failed: %v", err) - } - if status.MaxNew != tt.wantMaxNew { - t.Errorf("MaxNew = %d, want %d", status.MaxNew, tt.wantMaxNew) - } - }) - } -} diff --git a/internal/cmd/controller/target/partition.go b/internal/cmd/controller/target/partition.go index d0b3aaa0c3..88532c8dcd 100644 --- a/internal/cmd/controller/target/partition.go +++ b/internal/cmd/controller/target/partition.go @@ -8,8 +8,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -const defaultMaxNew = 50 - type partition struct { Status fleet.PartitionStatus Targets []*Target @@ -20,7 +18,7 @@ type partition struct { // It updates Deployments in allTargets if they are out of sync (DeploymentID != StagedDeploymentID). func UpdatePartitions(status *fleet.BundleStatus, allTargets []*Target) (err error) { rollout := getRollout(allTargets) - maxNew := defaultMaxNew + maxNew := DefaultMaxNew if rollout.MaxNew != nil { maxNew = *rollout.MaxNew } diff --git a/internal/cmd/controller/target/rollout_test.go b/internal/cmd/controller/target/rollout_test.go index 1058867785..6feac06acb 100644 --- a/internal/cmd/controller/target/rollout_test.go +++ b/internal/cmd/controller/target/rollout_test.go @@ -529,7 +529,7 @@ func Test_UpdatePartitions_MaxNew(t *testing.T) { name: "nil maxNew uses default of 50", maxNew: nil, targetCount: 100, - wantNewlyCreated: defaultMaxNew, + wantNewlyCreated: DefaultMaxNew, }, } for _, tt := range tests { diff --git a/internal/cmd/controller/target/target.go b/internal/cmd/controller/target/target.go index 7dc252c742..9b0a17de56 100644 --- a/internal/cmd/controller/target/target.go +++ b/internal/cmd/controller/target/target.go @@ -25,6 +25,11 @@ var ( defMaxUnavailablePartitions = intstr.FromInt(0) ) +const ( + // DefaultMaxNew is the default value for RolloutStrategy.MaxNew. + DefaultMaxNew = 50 +) + const ( maxTemplateRecursionDepth = 50 clusterLabelPrefix = "global.fleet.clusterLabels." diff --git a/pkg/apis/fleet.cattle.io/v1alpha1/bundle_types.go b/pkg/apis/fleet.cattle.io/v1alpha1/bundle_types.go index 1528f52d8e..905f2e2e3f 100644 --- a/pkg/apis/fleet.cattle.io/v1alpha1/bundle_types.go +++ b/pkg/apis/fleet.cattle.io/v1alpha1/bundle_types.go @@ -389,10 +389,6 @@ type BundleStatus struct { // percentage of unavailable partitions. // +optional MaxUnavailablePartitions int `json:"maxUnavailablePartitions"` - // MaxNew is the maximum number of BundleDeployments that can be created - // in a single reconciliation. Defaults to 50. Can be configured via - // rolloutStrategy.maxNew in the Bundle spec. - MaxNew int `json:"maxNew,omitempty"` // PartitionStatus lists the status of each partition. PartitionStatus []PartitionStatus `json:"partitions,omitempty"` // Display contains the number of ready, desiredready clusters and a