Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
220 changes: 187 additions & 33 deletions api/v1/clusterextensionrevision_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,42 +24,121 @@ import (
const (
ClusterExtensionRevisionKind = "ClusterExtensionRevision"

// Condition Types
// ClusterExtensionRevisionTypeAvailable is the condition type that represents whether the
// ClusterExtensionRevision is available and has been successfully rolled out.
ClusterExtensionRevisionTypeAvailable = "Available"

// ClusterExtensionRevisionTypeSucceeded is the condition type that represents whether the
// ClusterExtensionRevision rollout has succeeded at least once.
ClusterExtensionRevisionTypeSucceeded = "Succeeded"

// Condition Reasons
ClusterExtensionRevisionReasonAvailable = "Available"
ClusterExtensionRevisionReasonReconcileFailure = "ReconcileFailure"
// ClusterExtensionRevisionReasonAvailable is set when the revision is available
// and passes all probes after a successful rollout.
// Condition: Available, Status: True
ClusterExtensionRevisionReasonAvailable = "Available"

// ClusterExtensionRevisionReasonReconcileFailure is set when the ClusterExtensionRevision
// encounters a general reconciliation failure, such as errors ensuring finalizers or
// establishing watches.
// Condition: Available, Status: False
ClusterExtensionRevisionReasonReconcileFailure = "ReconcileFailure"

// ClusterExtensionRevisionReasonRevisionValidationFailure is set when the revision
// fails preflight validation checks at the revision level.
// Condition: Available, Status: False
ClusterExtensionRevisionReasonRevisionValidationFailure = "RevisionValidationFailure"
ClusterExtensionRevisionReasonPhaseValidationError = "PhaseValidationError"
ClusterExtensionRevisionReasonObjectCollisions = "ObjectCollisions"
ClusterExtensionRevisionReasonRolloutSuccess = "RolloutSuccess"
ClusterExtensionRevisionReasonProbeFailure = "ProbeFailure"
ClusterExtensionRevisionReasonIncomplete = "Incomplete"
ClusterExtensionRevisionReasonProgressing = "Progressing"
ClusterExtensionRevisionReasonArchived = "Archived"
ClusterExtensionRevisionReasonMigrated = "Migrated"

// ClusterExtensionRevisionReasonPhaseValidationError is set when a phase within
// the revision fails preflight validation checks.
// Condition: Available, Status: False
ClusterExtensionRevisionReasonPhaseValidationError = "PhaseValidationError"

// ClusterExtensionRevisionReasonObjectCollisions is set when objects in the revision
// collide with existing objects on the cluster that cannot be adopted based on
// the configured collision protection policy.
// Condition: Available, Status: False
ClusterExtensionRevisionReasonObjectCollisions = "ObjectCollisions"

// ClusterExtensionRevisionReasonRolloutSuccess is set when the revision has
// successfully completed its rollout for the first time.
// Condition: Succeeded, Status: True
ClusterExtensionRevisionReasonRolloutSuccess = "RolloutSuccess"

// ClusterExtensionRevisionReasonProbeFailure is set when one or more objects
// in the revision fail their readiness probes during rollout.
// Condition: Available, Status: False
ClusterExtensionRevisionReasonProbeFailure = "ProbeFailure"

// ClusterExtensionRevisionReasonIncomplete is set when the revision rollout
// has not completed but no specific probe failures have been detected.
// Condition: Available, Status: False
ClusterExtensionRevisionReasonIncomplete = "Incomplete"

// ClusterExtensionRevisionReasonProgressing is set when the revision rollout
// is actively making progress and is in transition.
// Condition: Progressing, Status: True
ClusterExtensionRevisionReasonProgressing = "Progressing"

// ClusterExtensionRevisionReasonArchived is set when the revision has been
// archived and its objects have been torn down.
// Condition: Available, Status: Unknown
ClusterExtensionRevisionReasonArchived = "Archived"

// ClusterExtensionRevisionReasonMigrated is set when the revision was
// migrated from an existing Helm release to a ClusterExtensionRevision.
// Condition: Available, Status: Unknown
ClusterExtensionRevisionReasonMigrated = "Migrated"
)

// ClusterExtensionRevisionSpec defines the desired state of ClusterExtensionRevision.
//
// A ClusterExtensionRevision represents a specific immutable snapshot of the objects
// to be installed for a ClusterExtension. Each revision is rolled out in phases,
// with objects organized by their Group-Kind into well-known phases such as namespaces,
// rbac, crds, and deploy.
type ClusterExtensionRevisionSpec struct {
// Specifies the lifecycle state of the ClusterExtensionRevision.
// The lifecycleState field specifies the lifecycle state of the ClusterExtensionRevision.
//
// When set to "Active" (the default), the revision is actively managed and reconciled.
// When set to "Paused", reconciliation is disabled but status updates continue.
// When set to "Archived", the revision is torn down and scaled to zero.
// The revision is removed from the owner list of all objects previously under management.
// All objects that did not transition to a succeeding revision are deleted.
//
// Once a revision is set to "Archived", it cannot be un-archived.
//
// +kubebuilder:default="Active"
// +kubebuilder:validation:Enum=Active;Paused;Archived
// +kubebuilder:validation:XValidation:rule="oldSelf == 'Active' || oldSelf == 'Paused' || oldSelf == 'Archived' && oldSelf == self", message="can not un-archive"
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The validation error message should use "cannot" instead of "can not". "Cannot" is the standard single-word form preferred in error messages.

Suggested change
// +kubebuilder:validation:XValidation:rule="oldSelf == 'Active' || oldSelf == 'Paused' || oldSelf == 'Archived' && oldSelf == self", message="can not un-archive"
// +kubebuilder:validation:XValidation:rule="oldSelf == 'Active' || oldSelf == 'Paused' || oldSelf == 'Archived' && oldSelf == self", message="cannot un-archive"

Copilot uses AI. Check for mistakes.
LifecycleState ClusterExtensionRevisionLifecycleState `json:"lifecycleState,omitempty"`
// Revision is a sequence number representing a specific revision of the ClusterExtension instance.
// Must be positive. Each ClusterExtensionRevision of the same parent ClusterExtension needs to have
// a unique value assigned. It is immutable after creation. The new revision number must always be previous revision +1.

// The revision field is a required, immutable sequence number representing a specific revision
// of the parent ClusterExtension.
//
// The revision field must be a positive integer.
// Each ClusterExtensionRevision belonging to the same parent ClusterExtension must have a unique revision number.
// The revision number must always be the previous revision number plus one, or 1 for the first revision.
//
// +kubebuilder:validation:Required
// +kubebuilder:validation:Minimum:=1
// +kubebuilder:validation:XValidation:rule="self == oldSelf", message="revision is immutable"
Revision int64 `json:"revision"`
// Phases are groups of objects that will be applied at the same time.
// All objects in the phase will have to pass their probes in order to progress to the next phase.

// The phases field is an optional, immutable list of phases that group objects to be applied together.
//
// Objects are organized into phases based on their Group-Kind. Common phases include:
// - namespaces: Namespace objects
// - policies: ResourceQuota, LimitRange, NetworkPolicy objects
// - rbac: ServiceAccount, Role, RoleBinding, ClusterRole, ClusterRoleBinding objects
// - crds: CustomResourceDefinition objects
// - storage: PersistentVolume, PersistentVolumeClaim, StorageClass objects
// - deploy: Deployment, StatefulSet, DaemonSet, Service, ConfigMap, Secret objects
// - publish: Ingress, APIService, Route, Webhook objects
//
// All objects in a phase are applied simultaneously.
// The revision progresses to the next phase only after all objects in the current phase pass their readiness probes.
//
// Once set (even if empty), the phases field is immutable.
//
// +kubebuilder:validation:XValidation:rule="self == oldSelf || oldSelf.size() == 0", message="phases is immutable"
// +listType=map
Expand All @@ -75,33 +154,68 @@ const (
// ClusterExtensionRevisionLifecycleStateActive / "Active" is the default lifecycle state.
ClusterExtensionRevisionLifecycleStateActive ClusterExtensionRevisionLifecycleState = "Active"
// ClusterExtensionRevisionLifecycleStatePaused / "Paused" disables reconciliation of the ClusterExtensionRevision.
// Only Status updates will still propagated, but object changes will not be reconciled.
// Object changes will not be reconciled. However, status updates will be propagated.
ClusterExtensionRevisionLifecycleStatePaused ClusterExtensionRevisionLifecycleState = "Paused"
// ClusterExtensionRevisionLifecycleStateArchived / "Archived" disables reconciliation while also "scaling to zero",
// which deletes all objects that are not excluded via the pausedFor property and
// removes itself from the owner list of all other objects previously under management.
// ClusterExtensionRevisionLifecycleStateArchived / "Archived" archives the revision for historical or auditing purposes.
// The revision is removed from the owner list of all other objects previously under management and all objects
// that did not transition to a succeeding revision are deleted.
ClusterExtensionRevisionLifecycleStateArchived ClusterExtensionRevisionLifecycleState = "Archived"
)

// ClusterExtensionRevisionPhase are groups of objects that will be applied at the same time.
// All objects in the a phase will have to pass their probes in order to progress to the next phase.
// ClusterExtensionRevisionPhase represents a group of objects that are applied together.
//
// Objects in a phase are applied simultaneously.
// All objects must pass their readiness probes before the revision progresses to the next phase.
// Phases are applied in a defined order based on the types of objects they contain.
type ClusterExtensionRevisionPhase struct {
// Name identifies this phase.
// The name field is a required identifier for this phase.
//
// Phase names must follow the DNS label standard as defined in [RFC 1123].
// They must contain only lowercase alphanumeric characters or hyphens (-),
// start and end with an alphanumeric character, and be no longer than 63 characters.
//
// Common phase names include: namespaces, policies, rbac, crds, storage, deploy, publish.
//
// [RFC 1123]: https://tools.ietf.org/html/rfc1123
//
// +kubebuilder:validation:MaxLength=63
// +kubebuilder:validation:Pattern=`^[a-z]([-a-z0-9]*[a-z0-9])?$`
Name string `json:"name"`
// Objects are a list of all the objects within this phase.

// The objects field is a required list of all Kubernetes objects in this phase.
//
// All objects in this list are applied to the cluster simultaneously.
// The phase is considered complete only after all objects pass their readiness probes.
Objects []ClusterExtensionRevisionObject `json:"objects"`
}

// ClusterExtensionRevisionObject contains an object and settings for it.
// ClusterExtensionRevisionObject represents a Kubernetes object to be applied as part
// of a ClusterExtensionRevision, along with its collision protection settings.
type ClusterExtensionRevisionObject struct {
// The object field is a required embedded Kubernetes object to be applied.
//
// This object must be a valid Kubernetes resource with apiVersion, kind, and metadata fields.
// Status fields are not permitted and are removed if present.
// Only specific metadata fields are preserved: name, namespace, labels, and annotations.
//
// +kubebuilder:validation:EmbeddedResource
// +kubebuilder:pruning:PreserveUnknownFields
Object unstructured.Unstructured `json:"object"`
// CollisionProtection controls whether OLM can adopt and modify objects
// already existing on the cluster or even owned by another controller.

// The collisionProtection field controls whether the operator can adopt and modify objects
// that already exist on the cluster.
//
// When set to "Prevent" (the default), the operator only manages objects it created itself.
// This prevents ownership collisions.
//
// When set to "IfNoController", the operator can adopt and modify pre-existing objects
// that are not owned by another controller.
// This is useful for taking over management of manually-created resources.
//
// When set to "None", the operator can adopt and modify any pre-existing object, even if
// owned by another controller.
// Use this setting with extreme caution as it may cause multiple controllers to fight over
// the same resource, resulting in increased load on the API server and etcd.
//
// +kubebuilder:default="Prevent"
// +kubebuilder:validation:Enum=Prevent;IfNoController;None
Expand All @@ -128,6 +242,27 @@ const (

// ClusterExtensionRevisionStatus defines the observed state of a ClusterExtensionRevision.
type ClusterExtensionRevisionStatus struct {
// conditions is an optional list of status conditions describing the state of the
// ClusterExtensionRevision.
//
// The Progressing condition represents whether the revision is actively rolling out:
// - When status is True and reason is Progressing, the revision rollout is actively making progress and is in transition.
// - When Progressing is not present, the revision is not currently in transition.
//
// The Available condition represents whether the revision has been successfully rolled out and is available:
// - When status is True and reason is Available, the revision has been successfully rolled out and all objects pass their readiness probes.
// - When status is False and reason is Incomplete, the revision rollout has not yet completed but no specific failures have been detected.
// - When status is False and reason is ProbeFailure, one or more objects are failing their readiness probes during rollout.
// - When status is False and reason is ReconcileFailure, the revision has encountered a general reconciliation failure.
// - When status is False and reason is RevisionValidationFailure, the revision failed preflight validation checks.
// - When status is False and reason is PhaseValidationError, a phase within the revision failed preflight validation checks.
// - When status is False and reason is ObjectCollisions, objects in the revision collide with existing cluster objects that cannot be adopted.
// - When status is Unknown and reason is Archived, the revision has been archived and its objects have been torn down.
// - When status is Unknown and reason is Migrated, the revision was migrated from an existing release and object status probe results have not yet been observed.
//
// The Succeeded condition represents whether the revision has successfully completed its rollout at least once:
// - When status is True and reason is RolloutSuccess, the revision has successfully completed its rollout. This condition is set once and persists even if the revision later becomes unavailable.
//
// +listType=map
// +listMapKey=type
// +optional
Expand All @@ -137,19 +272,38 @@ type ClusterExtensionRevisionStatus struct {
// +kubebuilder:object:root=true
// +kubebuilder:resource:scope=Cluster
// +kubebuilder:subresource:status

// ClusterExtensionRevision is the Schema for the clusterextensionrevisions API
// +kubebuilder:printcolumn:name="Available",type=string,JSONPath=`.status.conditions[?(@.type=='Available')].status`
// +kubebuilder:printcolumn:name=Age,type=date,JSONPath=`.metadata.creationTimestamp`

// ClusterExtensionRevision is the schema for the ClusterExtensionRevisions API.
//
// A ClusterExtensionRevision represents an immutable snapshot of Kubernetes objects
// for a specific version of a ClusterExtension. Each revision contains objects
// organized into phases that roll out sequentially.
//
// The ClusterExtension controller creates and manages ClusterExtensionRevisions automatically.
// Do not create them directly. Each ClusterExtension can have multiple revisions as it
// upgrades or reconfigures.
//
// The revision rollout uses a phased approach where objects apply in a defined order based
// on type (for example: namespaces, then RBAC, then CRDs, then deployments). All objects
// in a phase apply simultaneously and must pass readiness probes before rollout continues
// to the next phase.
//
// Revisions have three lifecycle states:
// - Active: The revision is actively managed and reconciled (default)
// - Paused: Reconciliation is disabled but status updates continue
// - Archived: The revision is torn down, objects are deleted, and the revision removes
// itself from the owner list of managed objects
type ClusterExtensionRevision struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

// spec is an optional field that defines the desired state of the ClusterExtension.
// The spec field is optional and defines the desired state of the ClusterExtensionRevision.
// +optional
Spec ClusterExtensionRevisionSpec `json:"spec,omitempty"`

// status is an optional field that defines the observed state of the ClusterExtension.
// The status field is optional and defines the observed state of the ClusterExtensionRevision.
// +optional
Status ClusterExtensionRevisionStatus `json:"status,omitempty"`
}
Expand Down
Loading
Loading