Skip to content

Commit 1b24c73

Browse files
authored
Merge branch 'main' into feat/memory-optimization-hub-2
2 parents 4db6bee + ffc7479 commit 1b24c73

File tree

55 files changed

+3902
-379
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+3902
-379
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ on:
1313
paths-ignore: [docs/**, "**.md", "**.mdx", "**.png", "**.jpg"]
1414

1515
env:
16-
GO_VERSION: '1.24.6'
16+
GO_VERSION: '1.24.9'
1717

1818
jobs:
1919
detect-noop:

.github/workflows/code-lint.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ on:
1414

1515
env:
1616
# Common versions
17-
GO_VERSION: '1.24.6'
17+
GO_VERSION: '1.24.9'
1818

1919
jobs:
2020

.github/workflows/codespell.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ jobs:
1212
runs-on: ubuntu-latest
1313
steps:
1414
- name: Harden Runner
15-
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
15+
uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
1616
with:
1717
egress-policy: audit
1818

1919
- uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v4.1.7
20-
- uses: codespell-project/actions-codespell@406322ec52dd7b488e48c1c4b82e2a8b3a1bf630 # master
20+
- uses: codespell-project/actions-codespell@8f01853be192eb0f849a5c7d721450e7a467c579 # master
2121
with:
2222
check_filenames: true
2323
skip: ./.git,./.github/workflows/codespell.yml,.git,*.png,*.jpg,*.svg,*.sum,./vendor,go.sum,testdata

.github/workflows/trivy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ env:
1818
MEMBER_AGENT_IMAGE_NAME: member-agent
1919
REFRESH_TOKEN_IMAGE_NAME: refresh-token
2020

21-
GO_VERSION: '1.24.6'
21+
GO_VERSION: '1.24.9'
2222

2323
jobs:
2424
export-registry:

.github/workflows/upgrade.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ on:
1717
paths-ignore: [docs/**, "**.md", "**.mdx", "**.png", "**.jpg"]
1818

1919
env:
20-
GO_VERSION: '1.24.6'
20+
GO_VERSION: '1.24.9'
2121

2222
jobs:
2323
detect-noop:

.golangci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
run:
22
timeout: 15m
3-
go: '1.24.6'
3+
go: '1.24.9'
44

55
linters-settings:
66
stylecheck:

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ CONTROLLER_GEN_VER := v0.16.0
5454
CONTROLLER_GEN_BIN := controller-gen
5555
CONTROLLER_GEN := $(abspath $(TOOLS_BIN_DIR)/$(CONTROLLER_GEN_BIN)-$(CONTROLLER_GEN_VER))
5656

57-
STATICCHECK_VER := 2025.1
57+
STATICCHECK_VER := master
5858
STATICCHECK_BIN := staticcheck
5959
STATICCHECK := $(abspath $(TOOLS_BIN_DIR)/$(STATICCHECK_BIN)-$(STATICCHECK_VER))
6060

apis/placement/v1beta1/clusterresourceplacement_types.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ type ClusterResourcePlacement struct {
113113

114114
// The desired state of ClusterResourcePlacement.
115115
// +kubebuilder:validation:Required
116-
// +kubebuilder:validation:XValidation:rule="!((has(oldSelf.policy) && !has(self.policy)) || (has(oldSelf.policy) && has(self.policy) && has(self.policy.placementType) && has(oldSelf.policy.placementType) && self.policy.placementType != oldSelf.policy.placementType))",message="placement type is immutable"
116+
// +kubebuilder:validation:XValidation:rule="!(has(oldSelf.policy) && !has(self.policy))",message="policy cannot be removed once set"
117117
// +kubebuilder:validation:XValidation:rule="!(self.statusReportingScope == 'NamespaceAccessible' && size(self.resourceSelectors.filter(x, x.kind == 'Namespace')) != 1)",message="when statusReportingScope is NamespaceAccessible, exactly one resourceSelector with kind 'Namespace' is required"
118118
// +kubebuilder:validation:XValidation:rule="!has(oldSelf.statusReportingScope) || self.statusReportingScope == oldSelf.statusReportingScope",message="statusReportingScope is immutable"
119119
Spec PlacementSpec `json:"spec"`
@@ -135,6 +135,7 @@ type PlacementSpec struct {
135135
// Policy defines how to select member clusters to place the selected resources.
136136
// If unspecified, all the joined member clusters are selected.
137137
// +kubebuilder:validation:Optional
138+
// +kubebuilder:validation:XValidation:rule="!(self.placementType != oldSelf.placementType)",message="placement type is immutable"
138139
Policy *PlacementPolicy `json:"policy,omitempty"`
139140

140141
// The rollout strategy to use to replace existing placement with new ones.
@@ -1628,6 +1629,7 @@ type ResourcePlacement struct {
16281629

16291630
// The desired state of ResourcePlacement.
16301631
// +kubebuilder:validation:Required
1632+
// +kubebuilder:validation:XValidation:rule="!(has(oldSelf.policy) && !has(self.policy))",message="policy cannot be removed once set"
16311633
Spec PlacementSpec `json:"spec"`
16321634

16331635
// The observed status of ResourcePlacement.

apis/placement/v1beta1/stageupdate_types.go

Lines changed: 93 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package v1beta1
1919
import (
2020
"k8s.io/apimachinery/pkg/api/meta"
2121
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
22+
"k8s.io/apimachinery/pkg/util/intstr"
2223
"sigs.k8s.io/controller-runtime/pkg/client"
2324

2425
"github.com/kubefleet-dev/kubefleet/apis"
@@ -91,6 +92,7 @@ type UpdateRunObjList interface {
9192
// +kubebuilder:printcolumn:JSONPath=`.spec.resourceSnapshotIndex`,name="Resource-Snapshot-Index",type=string
9293
// +kubebuilder:printcolumn:JSONPath=`.status.policySnapshotIndexUsed`,name="Policy-Snapshot-Index",type=string
9394
// +kubebuilder:printcolumn:JSONPath=`.status.conditions[?(@.type=="Initialized")].status`,name="Initialized",type=string
95+
// +kubebuilder:printcolumn:JSONPath=`.status.conditions[?(@.type=="Progressing")].status`,name="Progressing",type=string
9496
// +kubebuilder:printcolumn:JSONPath=`.status.conditions[?(@.type=="Succeeded")].status`,name="Succeeded",type=string
9597
// +kubebuilder:printcolumn:JSONPath=`.metadata.creationTimestamp`,name="Age",type=date
9698
// +kubebuilder:printcolumn:JSONPath=`.spec.stagedRolloutStrategyName`,name="Strategy",priority=1,type=string
@@ -106,9 +108,8 @@ type ClusterStagedUpdateRun struct {
106108
metav1.TypeMeta `json:",inline"`
107109
metav1.ObjectMeta `json:"metadata,omitempty"`
108110

109-
// The desired state of ClusterStagedUpdateRun. The spec is immutable.
111+
// The desired state of ClusterStagedUpdateRun.
110112
// +kubebuilder:validation:Required
111-
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="The spec field is immutable"
112113
Spec UpdateRunSpec `json:"spec"`
113114

114115
// The observed status of ClusterStagedUpdateRun.
@@ -146,27 +147,66 @@ func (c *ClusterStagedUpdateRun) SetUpdateRunStatus(status UpdateRunStatus) {
146147
c.Status = status
147148
}
148149

150+
// State represents the desired state of an update run.
151+
// +enum
152+
type State string
153+
154+
const (
155+
// StateNotStarted describes user intent to initialize but not execute the update run.
156+
// This is the default state when an update run is created.
157+
StateNotStarted State = "NotStarted"
158+
159+
// StateStarted describes user intent to execute (or resume execution if paused).
160+
// Users can subsequently set the state to Stopped or Abandoned.
161+
StateStarted State = "Started"
162+
163+
// StateStopped describes user intent to pause the update run.
164+
// Users can subsequently set the state to Started or Abandoned.
165+
StateStopped State = "Stopped"
166+
167+
// StateAbandoned describes user intent to abandon the update run.
168+
// This is a terminal state; once set, it cannot be changed.
169+
StateAbandoned State = "Abandoned"
170+
)
171+
149172
// UpdateRunSpec defines the desired rollout strategy and the snapshot indices of the resources to be updated.
150173
// It specifies a stage-by-stage update process across selected clusters for the given ResourcePlacement object.
174+
// +kubebuilder:validation:XValidation:rule="!has(oldSelf.state) || oldSelf.state != 'NotStarted' || self.state != 'Stopped'",message="invalid state transition: cannot transition from NotStarted to Stopped"
175+
// +kubebuilder:validation:XValidation:rule="!has(oldSelf.state) || oldSelf.state != 'Started' || self.state != 'NotStarted'",message="invalid state transition: cannot transition from Started to NotStarted"
176+
// +kubebuilder:validation:XValidation:rule="!has(oldSelf.state) || oldSelf.state != 'Stopped' || self.state != 'NotStarted'",message="invalid state transition: cannot transition from Stopped to NotStarted"
177+
// +kubebuilder:validation:XValidation:rule="!has(oldSelf.state) || oldSelf.state != 'Abandoned' || self.state == 'Abandoned'",message="invalid state transition: Abandoned is a terminal state and cannot transition to any other state"
151178
type UpdateRunSpec struct {
152179
// PlacementName is the name of placement that this update run is applied to.
153180
// There can be multiple active update runs for each placement, but
154181
// it's up to the DevOps team to ensure they don't conflict with each other.
155182
// +kubebuilder:validation:Required
156183
// +kubebuilder:validation:MaxLength=255
184+
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="placementName is immutable"
157185
PlacementName string `json:"placementName"`
158186

159187
// The resource snapshot index of the selected resources to be updated across clusters.
160188
// The index represents a group of resource snapshots that includes all the resources a ResourcePlacement selected.
161189
// +kubebuilder:validation:Required
190+
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="resourceSnapshotIndex is immutable"
162191
ResourceSnapshotIndex string `json:"resourceSnapshotIndex"`
163192

164193
// The name of the update strategy that specifies the stages and the sequence
165194
// in which the selected resources will be updated on the member clusters. The stages
166195
// are computed according to the referenced strategy when the update run starts
167196
// and recorded in the status field.
168197
// +kubebuilder:validation:Required
198+
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="stagedRolloutStrategyName is immutable"
169199
StagedUpdateStrategyName string `json:"stagedRolloutStrategyName"`
200+
201+
// State indicates the desired state of the update run.
202+
// NotStarted: The update run is initialized but execution has not started (default).
203+
// Started: The update run should execute or resume execution.
204+
// Stopped: The update run should pause execution.
205+
// Abandoned: The update run should be abandoned and terminated.
206+
// +kubebuilder:validation:Optional
207+
// +kubebuilder:default=NotStarted
208+
// +kubebuilder:validation:Enum=NotStarted;Started;Stopped;Abandoned
209+
State State `json:"state,omitempty"`
170210
}
171211

172212
// UpdateStrategySpecGetterSetter offers the functionality to work with UpdateStrategySpec.
@@ -275,21 +315,40 @@ type StageConfig struct {
275315
// +kubebuilder:validation:Optional
276316
SortingLabelKey *string `json:"sortingLabelKey,omitempty"`
277317

318+
// MaxConcurrency specifies the maximum number of clusters that can be updated concurrently within this stage.
319+
// Value can be an absolute number (ex: 5) or a percentage of the total clusters in the stage (ex: 50%).
320+
// Fractional results are rounded down. A minimum of 1 update is enforced.
321+
// If not specified, all clusters in the stage are updated sequentially (effectively maxConcurrency = 1).
322+
// Defaults to 1.
323+
// +kubebuilder:default=1
324+
// +kubebuilder:validation:XIntOrString
325+
// +kubebuilder:validation:Pattern="^((100|[0-9]{1,2})%|[0-9]+)$"
326+
// +kubebuilder:validation:Optional
327+
MaxConcurrency *intstr.IntOrString `json:"maxConcurrency,omitempty"`
328+
278329
// The collection of tasks that each stage needs to complete successfully before moving to the next stage.
279330
// Each task is executed in parallel and there cannot be more than one task of the same type.
280331
// +kubebuilder:validation:MaxItems=2
281332
// +kubebuilder:validation:Optional
282333
// +kubebuilder:validation:XValidation:rule="!self.exists(e, e.type == 'Approval' && has(e.waitTime))",message="AfterStageTaskType is Approval, waitTime is not allowed"
283334
// +kubebuilder:validation:XValidation:rule="!self.exists(e, e.type == 'TimedWait' && !has(e.waitTime))",message="AfterStageTaskType is TimedWait, waitTime is required"
284-
AfterStageTasks []AfterStageTask `json:"afterStageTasks,omitempty"`
335+
AfterStageTasks []StageTask `json:"afterStageTasks,omitempty"`
336+
337+
// The collection of tasks that needs to completed successfully by each stage before starting the stage.
338+
// Each task is executed in parallel and there cannot be more than one task of the same type.
339+
// +kubebuilder:validation:Optional
340+
// +kubebuilder:validation:MaxItems=1
341+
// +kubebuilder:validation:XValidation:rule="!self.exists(e, e.type == 'Approval' && has(e.waitTime))",message="AfterStageTaskType is Approval, waitTime is not allowed"
342+
// +kubebuilder:validation:XValidation:rule="!self.exists(e, e.type == 'TimedWait')",message="BeforeStageTaskType cannot be TimedWait"
343+
BeforeStageTasks []StageTask `json:"beforeStageTasks,omitempty"`
285344
}
286345

287-
// AfterStageTask is the collection of post-stage tasks that ALL need to be completed before moving to the next stage.
288-
type AfterStageTask struct {
289-
// The type of the after-stage task.
346+
// StageTask is the pre or post stage task that needs to be completed before starting or moving to the next stage.
347+
type StageTask struct {
348+
// The type of the before or after stage task.
290349
// +kubebuilder:validation:Enum=TimedWait;Approval
291350
// +kubebuilder:validation:Required
292-
Type AfterStageTaskType `json:"type"`
351+
Type StageTaskType `json:"type"`
293352

294353
// The time to wait after all the clusters in the current stage complete the update before moving to the next stage.
295354
// +kubebuilder:validation:Pattern="^0|([0-9]+(\\.[0-9]+)?(s|m|h))+$"
@@ -367,7 +426,7 @@ const (
367426
// StagedUpdateRunConditionProgressing indicates whether the staged update run is making progress.
368427
// Its condition status can be one of the following:
369428
// - "True": The staged update run is making progress.
370-
// - "False": The staged update run is waiting/paused.
429+
// - "False": The staged update run is waiting/paused/abandoned.
371430
// - "Unknown" means it is unknown.
372431
StagedUpdateRunConditionProgressing StagedUpdateRunConditionType = "Progressing"
373432

@@ -392,7 +451,12 @@ type StageUpdatingStatus struct {
392451
// Empty if the stage has not finished updating all the clusters.
393452
// +kubebuilder:validation:MaxItems=2
394453
// +kubebuilder:validation:Optional
395-
AfterStageTaskStatus []AfterStageTaskStatus `json:"afterStageTaskStatus,omitempty"`
454+
AfterStageTaskStatus []StageTaskStatus `json:"afterStageTaskStatus,omitempty"`
455+
456+
// The status of the pre-update tasks associated with the current stage.
457+
// +kubebuilder:validation:MaxItems=1
458+
// +kubebuilder:validation:Optional
459+
BeforeStageTaskStatus []StageTaskStatus `json:"beforeStageTaskStatus,omitempty"`
396460

397461
// The time when the update started on the stage. Empty if the stage has not started updating.
398462
// +kubebuilder:validation:Optional
@@ -482,11 +546,11 @@ const (
482546
ClusterUpdatingConditionSucceeded ClusterUpdatingStatusConditionType = "Succeeded"
483547
)
484548

485-
type AfterStageTaskStatus struct {
486-
// The type of the post-update task.
549+
type StageTaskStatus struct {
550+
// The type of the pre or post update task.
487551
// +kubebuilder:validation:Enum=TimedWait;Approval
488552
// +kubebuilder:validation:Required
489-
Type AfterStageTaskType `json:"type"`
553+
Type StageTaskType `json:"type"`
490554

491555
// The name of the approval request object that is created for this stage.
492556
// Only valid if the AfterStageTaskType is Approval.
@@ -498,45 +562,45 @@ type AfterStageTaskStatus struct {
498562
// +listType=map
499563
// +listMapKey=type
500564
//
501-
// Conditions is an array of current observed conditions for the specific type of post-update task.
565+
// Conditions is an array of current observed conditions for the specific type of pre or post update task.
502566
// Known conditions are "ApprovalRequestCreated", "WaitTimeElapsed", and "ApprovalRequestApproved".
503567
// +kubebuilder:validation:Optional
504568
Conditions []metav1.Condition `json:"conditions,omitempty"`
505569
}
506570

507-
// AfterStageTaskType identifies a specific type of the AfterStageTask.
571+
// StageTaskType identifies a specific type of the AfterStageTask or BeforeStageTask.
508572
// +enum
509-
type AfterStageTaskType string
573+
type StageTaskType string
510574

511575
const (
512-
// AfterStageTaskTypeTimedWait indicates the post-stage task is a timed wait.
513-
AfterStageTaskTypeTimedWait AfterStageTaskType = "TimedWait"
576+
// StageTaskTypeTimedWait indicates the stage task is a timed wait.
577+
StageTaskTypeTimedWait StageTaskType = "TimedWait"
514578

515-
// AfterStageTaskTypeApproval indicates the post-stage task is an approval.
516-
AfterStageTaskTypeApproval AfterStageTaskType = "Approval"
579+
// StageTaskTypeApproval indicates the stage task is an approval.
580+
StageTaskTypeApproval StageTaskType = "Approval"
517581
)
518582

519-
// AfterStageTaskConditionType identifies a specific condition of the AfterStageTask.
583+
// StageTaskConditionType identifies a specific condition of the AfterStageTask or BeforeStageTask.
520584
// +enum
521-
type AfterStageTaskConditionType string
585+
type StageTaskConditionType string
522586

523587
const (
524-
// AfterStageTaskConditionApprovalRequestCreated indicates if the approval request has been created.
588+
// StageTaskConditionApprovalRequestCreated indicates if the approval request has been created.
525589
// Its condition status can be:
526590
// - "True": The approval request has been created.
527-
AfterStageTaskConditionApprovalRequestCreated AfterStageTaskConditionType = "ApprovalRequestCreated"
591+
StageTaskConditionApprovalRequestCreated StageTaskConditionType = "ApprovalRequestCreated"
528592

529-
// AfterStageTaskConditionApprovalRequestApproved indicates if the approval request has been approved.
593+
// StageTaskConditionApprovalRequestApproved indicates if the approval request has been approved.
530594
// Its condition status can be:
531595
// - "True": The approval request has been approved.
532-
AfterStageTaskConditionApprovalRequestApproved AfterStageTaskConditionType = "ApprovalRequestApproved"
596+
StageTaskConditionApprovalRequestApproved StageTaskConditionType = "ApprovalRequestApproved"
533597

534-
// AfterStageTaskConditionWaitTimeElapsed indicates if the wait time after each stage has elapsed.
598+
// StageTaskConditionWaitTimeElapsed indicates if the wait time after each stage has elapsed.
535599
// If the status is "False", the condition message will include the remaining wait time.
536600
// Its condition status can be:
537601
// - "True": The wait time has elapsed.
538602
// - "False": The wait time has not elapsed.
539-
AfterStageTaskConditionWaitTimeElapsed AfterStageTaskConditionType = "WaitTimeElapsed"
603+
StageTaskConditionWaitTimeElapsed StageTaskConditionType = "WaitTimeElapsed"
540604
)
541605

542606
// ClusterStagedUpdateRunList contains a list of ClusterStagedUpdateRun.
@@ -721,6 +785,7 @@ func (c *ClusterApprovalRequestList) GetApprovalRequestObjs() []ApprovalRequestO
721785
// +kubebuilder:printcolumn:JSONPath=`.spec.resourceSnapshotIndex`,name="Resource-Snapshot-Index",type=string
722786
// +kubebuilder:printcolumn:JSONPath=`.status.policySnapshotIndexUsed`,name="Policy-Snapshot-Index",type=string
723787
// +kubebuilder:printcolumn:JSONPath=`.status.conditions[?(@.type=="Initialized")].status`,name="Initialized",type=string
788+
// +kubebuilder:printcolumn:JSONPath=`.status.conditions[?(@.type=="Progressing")].status`,name="Progressing",type=string
724789
// +kubebuilder:printcolumn:JSONPath=`.status.conditions[?(@.type=="Succeeded")].status`,name="Succeeded",type=string
725790
// +kubebuilder:printcolumn:JSONPath=`.metadata.creationTimestamp`,name="Age",type=date
726791
// +kubebuilder:printcolumn:JSONPath=`.spec.stagedRolloutStrategyName`,name="Strategy",priority=1,type=string
@@ -736,9 +801,8 @@ type StagedUpdateRun struct {
736801
metav1.TypeMeta `json:",inline"`
737802
metav1.ObjectMeta `json:"metadata,omitempty"`
738803

739-
// The desired state of StagedUpdateRun. The spec is immutable.
804+
// The desired state of StagedUpdateRun.
740805
// +kubebuilder:validation:Required
741-
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="The spec field is immutable"
742806
Spec UpdateRunSpec `json:"spec"`
743807

744808
// The observed status of StagedUpdateRun.

0 commit comments

Comments
 (0)