diff --git a/config/v1/tests/clusterversions.config.openshift.io/ClusterUpdatePreflight.yaml b/config/v1/tests/clusterversions.config.openshift.io/ClusterUpdatePreflight.yaml
new file mode 100644
index 00000000000..b6c4a383121
--- /dev/null
+++ b/config/v1/tests/clusterversions.config.openshift.io/ClusterUpdatePreflight.yaml
@@ -0,0 +1,235 @@
+apiVersion: apiextensions.k8s.io/v1 # Hack because controller-gen complains if we don't have this
+name: "ClusterVersion"
+crdName: clusterversions.config.openshift.io
+featureGates:
+ - ClusterUpdatePreflight
+tests:
+ onCreate:
+ - name: Should be able to create with mode Preflight
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: ClusterVersion
+ spec:
+ clusterID: foo
+ desiredUpdate:
+ version: 4.22.0
+ mode: Preflight
+ expected: |
+ apiVersion: config.openshift.io/v1
+ kind: ClusterVersion
+ spec:
+ clusterID: foo
+ desiredUpdate:
+ version: 4.22.0
+ mode: Preflight
+ - name: Should be able to omit mode field (default behavior)
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: ClusterVersion
+ spec:
+ clusterID: foo
+ desiredUpdate:
+ version: 4.22.0
+ expected: |
+ apiVersion: config.openshift.io/v1
+ kind: ClusterVersion
+ spec:
+ clusterID: foo
+ desiredUpdate:
+ version: 4.22.0
+ - name: Should be able to use Preflight mode with acceptRisks
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: ClusterVersion
+ spec:
+ clusterID: foo
+ desiredUpdate:
+ version: 4.22.0
+ mode: Preflight
+ acceptRisks:
+ - name: RiskA
+ - name: RiskB
+ expected: |
+ apiVersion: config.openshift.io/v1
+ kind: ClusterVersion
+ spec:
+ clusterID: foo
+ desiredUpdate:
+ version: 4.22.0
+ mode: Preflight
+ acceptRisks:
+ - name: RiskA
+ - name: RiskB
+ - name: Should be able to use Preflight mode with image
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: ClusterVersion
+ spec:
+ clusterID: foo
+ desiredUpdate:
+ image: quay.io/openshift-release-dev/ocp-release@sha256:example
+ mode: Preflight
+ expected: |
+ apiVersion: config.openshift.io/v1
+ kind: ClusterVersion
+ spec:
+ clusterID: foo
+ desiredUpdate:
+ image: quay.io/openshift-release-dev/ocp-release@sha256:example
+ mode: Preflight
+ - name: Invalid mode value should be rejected
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: ClusterVersion
+ spec:
+ clusterID: foo
+ desiredUpdate:
+ version: 4.22.0
+ mode: InvalidMode
+ expectedError: "Unsupported value: \"InvalidMode\""
+ - name: Empty mode value should be rejected
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: ClusterVersion
+ spec:
+ clusterID: foo
+ desiredUpdate:
+ version: 4.22.0
+ mode: ""
+ expectedError: "Unsupported value: \"\""
+ - name: Should allow both force and mode to be set together
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: ClusterVersion
+ spec:
+ clusterID: foo
+ desiredUpdate:
+ version: 4.22.0
+ mode: Preflight
+ force: true
+ expected: |
+ apiVersion: config.openshift.io/v1
+ kind: ClusterVersion
+ spec:
+ clusterID: foo
+ desiredUpdate:
+ version: 4.22.0
+ mode: Preflight
+ force: true
+ - name: Should allow Preflight mode when force is explicitly false
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: ClusterVersion
+ spec:
+ clusterID: foo
+ desiredUpdate:
+ version: 4.22.0
+ mode: Preflight
+ force: false
+ expected: |
+ apiVersion: config.openshift.io/v1
+ kind: ClusterVersion
+ spec:
+ clusterID: foo
+ desiredUpdate:
+ version: 4.22.0
+ mode: Preflight
+ force: false
+ onUpdate:
+ - name: Should be able to transition from normal to Preflight mode
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: ClusterVersion
+ spec:
+ clusterID: foo
+ desiredUpdate:
+ version: 4.22.0
+ updated: |
+ apiVersion: config.openshift.io/v1
+ kind: ClusterVersion
+ spec:
+ clusterID: foo
+ desiredUpdate:
+ version: 4.22.0
+ mode: Preflight
+ expected: |
+ apiVersion: config.openshift.io/v1
+ kind: ClusterVersion
+ spec:
+ clusterID: foo
+ desiredUpdate:
+ version: 4.22.0
+ mode: Preflight
+ - name: Should allow clearing Preflight mode back to normal
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: ClusterVersion
+ spec:
+ clusterID: foo
+ desiredUpdate:
+ version: 4.22.0
+ mode: Preflight
+ updated: |
+ apiVersion: config.openshift.io/v1
+ kind: ClusterVersion
+ spec:
+ clusterID: foo
+ desiredUpdate:
+ version: 4.22.0
+ expected: |
+ apiVersion: config.openshift.io/v1
+ kind: ClusterVersion
+ spec:
+ clusterID: foo
+ desiredUpdate:
+ version: 4.22.0
+ - name: Should allow changing target version while in Preflight mode
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: ClusterVersion
+ spec:
+ clusterID: foo
+ desiredUpdate:
+ version: 4.22.0
+ mode: Preflight
+ updated: |
+ apiVersion: config.openshift.io/v1
+ kind: ClusterVersion
+ spec:
+ clusterID: foo
+ desiredUpdate:
+ version: 4.23.0
+ mode: Preflight
+ expected: |
+ apiVersion: config.openshift.io/v1
+ kind: ClusterVersion
+ spec:
+ clusterID: foo
+ desiredUpdate:
+ version: 4.23.0
+ mode: Preflight
+ - name: Should allow changing from image to version in Preflight mode
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: ClusterVersion
+ spec:
+ clusterID: foo
+ desiredUpdate:
+ image: quay.io/openshift-release-dev/ocp-release@sha256:example
+ mode: Preflight
+ updated: |
+ apiVersion: config.openshift.io/v1
+ kind: ClusterVersion
+ spec:
+ clusterID: foo
+ desiredUpdate:
+ version: 4.23.0
+ mode: Preflight
+ expected: |
+ apiVersion: config.openshift.io/v1
+ kind: ClusterVersion
+ spec:
+ clusterID: foo
+ desiredUpdate:
+ version: 4.23.0
+ mode: Preflight
diff --git a/config/v1/types_cluster_version.go b/config/v1/types_cluster_version.go
index 5f36f693de1..f8d45114a83 100644
--- a/config/v1/types_cluster_version.go
+++ b/config/v1/types_cluster_version.go
@@ -283,6 +283,16 @@ type UpdateHistory struct {
// ClusterID is string RFC4122 uuid.
type ClusterID string
+// UpdateMode defines how an update should be processed.
+// +enum
+// +kubebuilder:validation:Enum=Preflight
+type UpdateMode string
+
+const (
+ // UpdateModePreflight allows an update to be checked for compatibility without committing to updating the cluster.
+ UpdateModePreflight UpdateMode = "Preflight"
+)
+
// ClusterVersionArchitecture enumerates valid cluster architectures.
// +kubebuilder:validation:Enum="Multi";""
type ClusterVersionArchitecture string
@@ -760,6 +770,22 @@ type Update struct {
// +listMapKey=name
// +optional
AcceptRisks []AcceptRisk `json:"acceptRisks,omitempty"`
+
+ // mode determines how an update should be processed.
+ // The only valid value is "Preflight".
+ // When omitted, the cluster performs a normal update by applying the specified version or image to the cluster.
+ // This is the standard update behavior.
+ // When set to "Preflight", the cluster runs compatibility checks against the target release without
+ // performing an actual update. Compatibility results, including any detected risks, are reported
+ // in status.conditionalUpdates and status.conditionalUpdateRisks alongside risks from the update
+ // recommendation service.
+ // This allows administrators to assess update readiness and address issues before committing to the update.
+ // Preflight mode is particularly useful for skip-level updates where upgrade compatibility needs to be
+ // verified across multiple minor versions.
+ // When mode is set to "Preflight", the same rules for version, image, and architecture apply as for normal updates.
+ // +openshift:enable:FeatureGate=ClusterUpdatePreflight
+ // +optional
+ Mode UpdateMode `json:"mode,omitempty"`
}
// AcceptRisk represents a risk that is considered acceptable.
diff --git a/config/v1/zz_generated.crd-manifests/0000_00_cluster-version-operator_01_clusterversions-CustomNoUpgrade.crd.yaml b/config/v1/zz_generated.crd-manifests/0000_00_cluster-version-operator_01_clusterversions-CustomNoUpgrade.crd.yaml
index c89d45ddcd1..0deb9ba0861 100644
--- a/config/v1/zz_generated.crd-manifests/0000_00_cluster-version-operator_01_clusterversions-CustomNoUpgrade.crd.yaml
+++ b/config/v1/zz_generated.crd-manifests/0000_00_cluster-version-operator_01_clusterversions-CustomNoUpgrade.crd.yaml
@@ -218,6 +218,23 @@ spec:
When image is set, architecture cannot be specified.
If both version and image are set, the version extracted from the referenced image must match the specified version.
type: string
+ mode:
+ description: |-
+ mode determines how an update should be processed.
+ The only valid value is "Preflight".
+ When omitted, the cluster performs a normal update by applying the specified version or image to the cluster.
+ This is the standard update behavior.
+ When set to "Preflight", the cluster runs compatibility checks against the target release without
+ performing an actual update. Compatibility results, including any detected risks, are reported
+ in status.conditionalUpdates and status.conditionalUpdateRisks alongside risks from the update
+ recommendation service.
+ This allows administrators to assess update readiness and address issues before committing to the update.
+ Preflight mode is particularly useful for skip-level updates where upgrade compatibility needs to be
+ verified across multiple minor versions.
+ When mode is set to "Preflight", the same rules for version, image, and architecture apply as for normal updates.
+ enum:
+ - Preflight
+ type: string
version:
description: |-
version is a semantic version identifying the update version.
diff --git a/config/v1/zz_generated.crd-manifests/0000_00_cluster-version-operator_01_clusterversions-DevPreviewNoUpgrade.crd.yaml b/config/v1/zz_generated.crd-manifests/0000_00_cluster-version-operator_01_clusterversions-DevPreviewNoUpgrade.crd.yaml
index f24b2a16a15..70a09d3ff0a 100644
--- a/config/v1/zz_generated.crd-manifests/0000_00_cluster-version-operator_01_clusterversions-DevPreviewNoUpgrade.crd.yaml
+++ b/config/v1/zz_generated.crd-manifests/0000_00_cluster-version-operator_01_clusterversions-DevPreviewNoUpgrade.crd.yaml
@@ -218,6 +218,23 @@ spec:
When image is set, architecture cannot be specified.
If both version and image are set, the version extracted from the referenced image must match the specified version.
type: string
+ mode:
+ description: |-
+ mode determines how an update should be processed.
+ The only valid value is "Preflight".
+ When omitted, the cluster performs a normal update by applying the specified version or image to the cluster.
+ This is the standard update behavior.
+ When set to "Preflight", the cluster runs compatibility checks against the target release without
+ performing an actual update. Compatibility results, including any detected risks, are reported
+ in status.conditionalUpdates and status.conditionalUpdateRisks alongside risks from the update
+ recommendation service.
+ This allows administrators to assess update readiness and address issues before committing to the update.
+ Preflight mode is particularly useful for skip-level updates where upgrade compatibility needs to be
+ verified across multiple minor versions.
+ When mode is set to "Preflight", the same rules for version, image, and architecture apply as for normal updates.
+ enum:
+ - Preflight
+ type: string
version:
description: |-
version is a semantic version identifying the update version.
diff --git a/config/v1/zz_generated.crd-manifests/0000_00_cluster-version-operator_01_clusterversions-TechPreviewNoUpgrade.crd.yaml b/config/v1/zz_generated.crd-manifests/0000_00_cluster-version-operator_01_clusterversions-TechPreviewNoUpgrade.crd.yaml
index ea97687cfc1..8f9157d58ee 100644
--- a/config/v1/zz_generated.crd-manifests/0000_00_cluster-version-operator_01_clusterversions-TechPreviewNoUpgrade.crd.yaml
+++ b/config/v1/zz_generated.crd-manifests/0000_00_cluster-version-operator_01_clusterversions-TechPreviewNoUpgrade.crd.yaml
@@ -218,6 +218,23 @@ spec:
When image is set, architecture cannot be specified.
If both version and image are set, the version extracted from the referenced image must match the specified version.
type: string
+ mode:
+ description: |-
+ mode determines how an update should be processed.
+ The only valid value is "Preflight".
+ When omitted, the cluster performs a normal update by applying the specified version or image to the cluster.
+ This is the standard update behavior.
+ When set to "Preflight", the cluster runs compatibility checks against the target release without
+ performing an actual update. Compatibility results, including any detected risks, are reported
+ in status.conditionalUpdates and status.conditionalUpdateRisks alongside risks from the update
+ recommendation service.
+ This allows administrators to assess update readiness and address issues before committing to the update.
+ Preflight mode is particularly useful for skip-level updates where upgrade compatibility needs to be
+ verified across multiple minor versions.
+ When mode is set to "Preflight", the same rules for version, image, and architecture apply as for normal updates.
+ enum:
+ - Preflight
+ type: string
version:
description: |-
version is a semantic version identifying the update version.
diff --git a/config/v1/zz_generated.featuregated-crd-manifests.yaml b/config/v1/zz_generated.featuregated-crd-manifests.yaml
index eb7c485e03f..ebf1713a162 100644
--- a/config/v1/zz_generated.featuregated-crd-manifests.yaml
+++ b/config/v1/zz_generated.featuregated-crd-manifests.yaml
@@ -144,6 +144,7 @@ clusterversions.config.openshift.io:
Category: ""
FeatureGates:
- ClusterUpdateAcceptRisks
+ - ClusterUpdatePreflight
- ImageStreamImportMode
- SignatureStores
FilenameOperatorName: cluster-version-operator
diff --git a/config/v1/zz_generated.featuregated-crd-manifests/clusterversions.config.openshift.io/ClusterUpdatePreflight.yaml b/config/v1/zz_generated.featuregated-crd-manifests/clusterversions.config.openshift.io/ClusterUpdatePreflight.yaml
new file mode 100644
index 00000000000..005036bbe72
--- /dev/null
+++ b/config/v1/zz_generated.featuregated-crd-manifests/clusterversions.config.openshift.io/ClusterUpdatePreflight.yaml
@@ -0,0 +1,782 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ api-approved.openshift.io: https://github.com/openshift/api/pull/495
+ api.openshift.io/filename-cvo-runlevel: "0000_00"
+ api.openshift.io/filename-operator: cluster-version-operator
+ api.openshift.io/filename-ordering: "01"
+ feature-gate.release.openshift.io/ClusterUpdatePreflight: "true"
+ include.release.openshift.io/self-managed-high-availability: "true"
+ name: clusterversions.config.openshift.io
+spec:
+ group: config.openshift.io
+ names:
+ kind: ClusterVersion
+ listKind: ClusterVersionList
+ plural: clusterversions
+ singular: clusterversion
+ scope: Cluster
+ versions:
+ - additionalPrinterColumns:
+ - jsonPath: .status.history[?(@.state=="Completed")].version
+ name: Version
+ type: string
+ - jsonPath: .status.conditions[?(@.type=="Available")].status
+ name: Available
+ type: string
+ - jsonPath: .status.conditions[?(@.type=="Progressing")].status
+ name: Progressing
+ type: string
+ - jsonPath: .status.conditions[?(@.type=="Progressing")].lastTransitionTime
+ name: Since
+ type: date
+ - jsonPath: .status.conditions[?(@.type=="Progressing")].message
+ name: Status
+ type: string
+ name: v1
+ schema:
+ openAPIV3Schema:
+ description: |-
+ ClusterVersion is the configuration for the ClusterVersionOperator. This is where
+ parameters related to automatic updates can be set.
+
+ Compatibility level 1: Stable within a major release for a minimum of 12 months or 3 minor releases (whichever is longer).
+ properties:
+ apiVersion:
+ description: |-
+ APIVersion defines the versioned schema of this representation of an object.
+ Servers should convert recognized schemas to the latest internal value, and
+ may reject unrecognized values.
+ More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
+ type: string
+ kind:
+ description: |-
+ Kind is a string value representing the REST resource this object represents.
+ Servers may infer this from the endpoint the client submits requests to.
+ Cannot be updated.
+ In CamelCase.
+ More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
+ type: string
+ metadata:
+ type: object
+ spec:
+ description: |-
+ spec is the desired state of the cluster version - the operator will work
+ to ensure that the desired version is applied to the cluster.
+ properties:
+ capabilities:
+ description: |-
+ capabilities configures the installation of optional, core
+ cluster components. A null value here is identical to an
+ empty object; see the child properties for default semantics.
+ properties:
+ additionalEnabledCapabilities:
+ description: |-
+ additionalEnabledCapabilities extends the set of managed
+ capabilities beyond the baseline defined in
+ baselineCapabilitySet. The default is an empty set.
+ items:
+ description: ClusterVersionCapability enumerates optional, core
+ cluster components.
+ enum:
+ - openshift-samples
+ - baremetal
+ - marketplace
+ - Console
+ - Insights
+ - Storage
+ - CSISnapshot
+ - NodeTuning
+ - MachineAPI
+ - Build
+ - DeploymentConfig
+ - ImageRegistry
+ - OperatorLifecycleManager
+ - CloudCredential
+ - Ingress
+ - CloudControllerManager
+ - OperatorLifecycleManagerV1
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ baselineCapabilitySet:
+ description: |-
+ baselineCapabilitySet selects an initial set of
+ optional capabilities to enable, which can be extended via
+ additionalEnabledCapabilities. If unset, the cluster will
+ choose a default, and the default may change over time.
+ The current default is vCurrent.
+ enum:
+ - None
+ - v4.11
+ - v4.12
+ - v4.13
+ - v4.14
+ - v4.15
+ - v4.16
+ - v4.17
+ - v4.18
+ - vCurrent
+ type: string
+ type: object
+ channel:
+ description: |-
+ channel is an identifier for explicitly requesting a non-default set
+ of updates to be applied to this cluster. The default channel will
+ contain stable updates that are appropriate for production clusters.
+ type: string
+ clusterID:
+ description: |-
+ clusterID uniquely identifies this cluster. This is expected to be
+ an RFC4122 UUID value (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx in
+ hexadecimal values). This is a required field.
+ type: string
+ desiredUpdate:
+ description: |-
+ desiredUpdate is an optional field that indicates the desired value of
+ the cluster version. Setting this value will trigger an upgrade (if
+ the current version does not match the desired version). The set of
+ recommended update values is listed as part of available updates in
+ status, and setting values outside that range may cause the upgrade
+ to fail.
+
+ Some of the fields are inter-related with restrictions and meanings described here.
+ 1. image is specified, version is specified, architecture is specified. API validation error.
+ 2. image is specified, version is specified, architecture is not specified. The version extracted from the referenced image must match the specified version.
+ 3. image is specified, version is not specified, architecture is specified. API validation error.
+ 4. image is specified, version is not specified, architecture is not specified. image is used.
+ 5. image is not specified, version is specified, architecture is specified. version and desired architecture are used to select an image.
+ 6. image is not specified, version is specified, architecture is not specified. version and current architecture are used to select an image.
+ 7. image is not specified, version is not specified, architecture is specified. API validation error.
+ 8. image is not specified, version is not specified, architecture is not specified. API validation error.
+
+ If an upgrade fails the operator will halt and report status
+ about the failing component. Setting the desired update value back to
+ the previous version will cause a rollback to be attempted if the
+ previous version is within the current minor version. Not all
+ rollbacks will succeed, and some may unrecoverably break the
+ cluster.
+ properties:
+ architecture:
+ description: |-
+ architecture is an optional field that indicates the desired
+ value of the cluster architecture. In this context cluster
+ architecture means either a single architecture or a multi
+ architecture. architecture can only be set to Multi thereby
+ only allowing updates from single to multi architecture. If
+ architecture is set, image cannot be set and version must be
+ set.
+ Valid values are 'Multi' and empty.
+ enum:
+ - Multi
+ - ""
+ type: string
+ force:
+ description: |-
+ force allows an administrator to update to an image that has failed
+ verification or upgradeable checks that are designed to keep your
+ cluster safe. Only use this if:
+ * you are testing unsigned release images in short-lived test clusters or
+ * you are working around a known bug in the cluster-version
+ operator and you have verified the authenticity of the provided
+ image yourself.
+ The provided image will run with full administrative access
+ to the cluster. Do not use this flag with images that come from unknown
+ or potentially malicious sources.
+ type: boolean
+ image:
+ description: |-
+ image is a container image location that contains the update.
+ image should be used when the desired version does not exist in availableUpdates or history.
+ When image is set, architecture cannot be specified.
+ If both version and image are set, the version extracted from the referenced image must match the specified version.
+ type: string
+ mode:
+ description: |-
+ mode determines how an update should be processed.
+ The only valid value is "Preflight".
+ When omitted, the cluster performs a normal update by applying the specified version or image to the cluster.
+ This is the standard update behavior.
+ When set to "Preflight", the cluster runs compatibility checks against the target release without
+ performing an actual update. Compatibility results, including any detected risks, are reported
+ in status.conditionalUpdates and status.conditionalUpdateRisks alongside risks from the update
+ recommendation service.
+ This allows administrators to assess update readiness and address issues before committing to the update.
+ Preflight mode is particularly useful for skip-level updates where upgrade compatibility needs to be
+ verified across multiple minor versions.
+ When mode is set to "Preflight", the same rules for version, image, and architecture apply as for normal updates.
+ enum:
+ - Preflight
+ type: string
+ version:
+ description: |-
+ version is a semantic version identifying the update version.
+ version is required if architecture is specified.
+ If both version and image are set, the version extracted from the referenced image must match the specified version.
+ type: string
+ type: object
+ x-kubernetes-validations:
+ - message: cannot set both Architecture and Image
+ rule: 'has(self.architecture) && has(self.image) ? (self.architecture
+ == "" || self.image == "") : true'
+ - message: Version must be set if Architecture is set
+ rule: 'has(self.architecture) && self.architecture != "" ? self.version
+ != "" : true'
+ overrides:
+ description: |-
+ overrides is list of overides for components that are managed by
+ cluster version operator. Marking a component unmanaged will prevent
+ the operator from creating or updating the object.
+ items:
+ description: |-
+ ComponentOverride allows overriding cluster version operator's behavior
+ for a component.
+ properties:
+ group:
+ description: group identifies the API group that the kind is
+ in.
+ type: string
+ kind:
+ description: kind indentifies which object to override.
+ type: string
+ name:
+ description: name is the component's name.
+ type: string
+ namespace:
+ description: |-
+ namespace is the component's namespace. If the resource is cluster
+ scoped, the namespace should be empty.
+ type: string
+ unmanaged:
+ description: |-
+ unmanaged controls if cluster version operator should stop managing the
+ resources in this cluster.
+ Default: false
+ type: boolean
+ required:
+ - group
+ - kind
+ - name
+ - namespace
+ - unmanaged
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - kind
+ - group
+ - namespace
+ - name
+ x-kubernetes-list-type: map
+ upstream:
+ description: |-
+ upstream may be used to specify the preferred update server. By default
+ it will use the appropriate update server for the cluster and region.
+ type: string
+ required:
+ - clusterID
+ type: object
+ status:
+ description: |-
+ status contains information about the available updates and any in-progress
+ updates.
+ properties:
+ availableUpdates:
+ description: |-
+ availableUpdates contains updates recommended for this
+ cluster. Updates which appear in conditionalUpdates but not in
+ availableUpdates may expose this cluster to known issues. This list
+ may be empty if no updates are recommended, if the update service
+ is unavailable, or if an invalid channel has been specified.
+ items:
+ description: Release represents an OpenShift release image and associated
+ metadata.
+ properties:
+ channels:
+ description: |-
+ channels is the set of Cincinnati channels to which the release
+ currently belongs.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ image:
+ description: |-
+ image is a container image location that contains the update. When this
+ field is part of spec, image is optional if version is specified and the
+ availableUpdates field contains a matching version.
+ type: string
+ url:
+ description: |-
+ url contains information about this release. This URL is set by
+ the 'url' metadata property on a release or the metadata returned by
+ the update API and should be displayed as a link in user
+ interfaces. The URL field may not be set for test or nightly
+ releases.
+ type: string
+ version:
+ description: |-
+ version is a semantic version identifying the update version. When this
+ field is part of spec, version is optional if image is specified.
+ type: string
+ required:
+ - image
+ - version
+ type: object
+ nullable: true
+ type: array
+ x-kubernetes-list-type: atomic
+ capabilities:
+ description: capabilities describes the state of optional, core cluster
+ components.
+ properties:
+ enabledCapabilities:
+ description: enabledCapabilities lists all the capabilities that
+ are currently managed.
+ items:
+ description: ClusterVersionCapability enumerates optional, core
+ cluster components.
+ enum:
+ - openshift-samples
+ - baremetal
+ - marketplace
+ - Console
+ - Insights
+ - Storage
+ - CSISnapshot
+ - NodeTuning
+ - MachineAPI
+ - Build
+ - DeploymentConfig
+ - ImageRegistry
+ - OperatorLifecycleManager
+ - CloudCredential
+ - Ingress
+ - CloudControllerManager
+ - OperatorLifecycleManagerV1
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ knownCapabilities:
+ description: knownCapabilities lists all the capabilities known
+ to the current cluster.
+ items:
+ description: ClusterVersionCapability enumerates optional, core
+ cluster components.
+ enum:
+ - openshift-samples
+ - baremetal
+ - marketplace
+ - Console
+ - Insights
+ - Storage
+ - CSISnapshot
+ - NodeTuning
+ - MachineAPI
+ - Build
+ - DeploymentConfig
+ - ImageRegistry
+ - OperatorLifecycleManager
+ - CloudCredential
+ - Ingress
+ - CloudControllerManager
+ - OperatorLifecycleManagerV1
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ type: object
+ conditionalUpdates:
+ description: |-
+ conditionalUpdates contains the list of updates that may be
+ recommended for this cluster if it meets specific required
+ conditions. Consumers interested in the set of updates that are
+ actually recommended for this cluster should use
+ availableUpdates. This list may be empty if no updates are
+ recommended, if the update service is unavailable, or if an empty
+ or invalid channel has been specified.
+ items:
+ description: |-
+ ConditionalUpdate represents an update which is recommended to some
+ clusters on the version the current cluster is reconciling, but which
+ may not be recommended for the current cluster.
+ properties:
+ conditions:
+ description: |-
+ conditions represents the observations of the conditional update's
+ current status. Known types are:
+ * Recommended, for whether the update is recommended for the current cluster.
+ items:
+ description: Condition contains details for one aspect of
+ the current state of this API Resource.
+ properties:
+ lastTransitionTime:
+ description: |-
+ lastTransitionTime is the last time the condition transitioned from one status to another.
+ This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
+ format: date-time
+ type: string
+ message:
+ description: |-
+ message is a human readable message indicating details about the transition.
+ This may be an empty string.
+ maxLength: 32768
+ type: string
+ observedGeneration:
+ description: |-
+ observedGeneration represents the .metadata.generation that the condition was set based upon.
+ For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
+ with respect to the current state of the instance.
+ format: int64
+ minimum: 0
+ type: integer
+ reason:
+ description: |-
+ reason contains a programmatic identifier indicating the reason for the condition's last transition.
+ Producers of specific condition types may define expected values and meanings for this field,
+ and whether the values are considered a guaranteed API.
+ The value should be a CamelCase string.
+ This field may not be empty.
+ maxLength: 1024
+ minLength: 1
+ pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+ type: string
+ status:
+ description: status of the condition, one of True, False,
+ Unknown.
+ enum:
+ - "True"
+ - "False"
+ - Unknown
+ type: string
+ type:
+ description: type of condition in CamelCase or in foo.example.com/CamelCase.
+ maxLength: 316
+ pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+ type: string
+ required:
+ - lastTransitionTime
+ - message
+ - reason
+ - status
+ - type
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - type
+ x-kubernetes-list-type: map
+ release:
+ description: release is the target of the update.
+ properties:
+ channels:
+ description: |-
+ channels is the set of Cincinnati channels to which the release
+ currently belongs.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ image:
+ description: |-
+ image is a container image location that contains the update. When this
+ field is part of spec, image is optional if version is specified and the
+ availableUpdates field contains a matching version.
+ type: string
+ url:
+ description: |-
+ url contains information about this release. This URL is set by
+ the 'url' metadata property on a release or the metadata returned by
+ the update API and should be displayed as a link in user
+ interfaces. The URL field may not be set for test or nightly
+ releases.
+ type: string
+ version:
+ description: |-
+ version is a semantic version identifying the update version. When this
+ field is part of spec, version is optional if image is specified.
+ type: string
+ required:
+ - image
+ - version
+ type: object
+ risks:
+ description: |-
+ risks represents the range of issues associated with
+ updating to the target release. The cluster-version
+ operator will evaluate all entries, and only recommend the
+ update if there is at least one entry and all entries
+ recommend the update.
+ items:
+ description: |-
+ ConditionalUpdateRisk represents a reason and cluster-state
+ for not recommending a conditional update.
+ properties:
+ matchingRules:
+ description: |-
+ matchingRules is a slice of conditions for deciding which
+ clusters match the risk and which do not. The slice is
+ ordered by decreasing precedence. The cluster-version
+ operator will walk the slice in order, and stop after the
+ first it can successfully evaluate. If no condition can be
+ successfully evaluated, the update will not be recommended.
+ items:
+ description: |-
+ ClusterCondition is a union of typed cluster conditions. The 'type'
+ property determines which of the type-specific properties are relevant.
+ When evaluated on a cluster, the condition may match, not match, or
+ fail to evaluate.
+ properties:
+ promql:
+ description: promql represents a cluster condition
+ based on PromQL.
+ properties:
+ promql:
+ description: |-
+ promql is a PromQL query classifying clusters. This query
+ query should return a 1 in the match case and a 0 in the
+ does-not-match case. Queries which return no time
+ series, or which return values besides 0 or 1, are
+ evaluation failures.
+ type: string
+ required:
+ - promql
+ type: object
+ type:
+ description: |-
+ type represents the cluster-condition type. This defines
+ the members and semantics of any additional properties.
+ enum:
+ - Always
+ - PromQL
+ type: string
+ required:
+ - type
+ type: object
+ minItems: 1
+ type: array
+ x-kubernetes-list-type: atomic
+ message:
+ description: |-
+ message provides additional information about the risk of
+ updating, in the event that matchingRules match the cluster
+ state. This is only to be consumed by humans. It may
+ contain Line Feed characters (U+000A), which should be
+ rendered as new lines.
+ minLength: 1
+ type: string
+ name:
+ description: |-
+ name is the CamelCase reason for not recommending a
+ conditional update, in the event that matchingRules match the
+ cluster state.
+ minLength: 1
+ type: string
+ url:
+ description: url contains information about this risk.
+ format: uri
+ minLength: 1
+ type: string
+ required:
+ - matchingRules
+ - message
+ - name
+ - url
+ type: object
+ maxItems: 200
+ minItems: 1
+ type: array
+ x-kubernetes-list-map-keys:
+ - name
+ x-kubernetes-list-type: map
+ required:
+ - release
+ - risks
+ type: object
+ maxItems: 500
+ type: array
+ x-kubernetes-list-type: atomic
+ conditions:
+ description: |-
+ conditions provides information about the cluster version. The condition
+ "Available" is set to true if the desiredUpdate has been reached. The
+ condition "Progressing" is set to true if an update is being applied.
+ The condition "Degraded" is set to true if an update is currently blocked
+ by a temporary or permanent error. Conditions are only valid for the
+ current desiredUpdate when metadata.generation is equal to
+ status.generation.
+ items:
+ description: |-
+ ClusterOperatorStatusCondition represents the state of the operator's
+ managed and monitored components.
+ properties:
+ lastTransitionTime:
+ description: lastTransitionTime is the time of the last update
+ to the current status property.
+ format: date-time
+ type: string
+ message:
+ description: |-
+ message provides additional information about the current condition.
+ This is only to be consumed by humans. It may contain Line Feed
+ characters (U+000A), which should be rendered as new lines.
+ type: string
+ reason:
+ description: reason is the CamelCase reason for the condition's
+ current status.
+ type: string
+ status:
+ description: status of the condition, one of True, False, Unknown.
+ type: string
+ type:
+ description: type specifies the aspect reported by this condition.
+ type: string
+ required:
+ - lastTransitionTime
+ - status
+ - type
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - type
+ x-kubernetes-list-type: map
+ desired:
+ description: |-
+ desired is the version that the cluster is reconciling towards.
+ If the cluster is not yet fully initialized desired will be set
+ with the information available, which may be an image or a tag.
+ properties:
+ channels:
+ description: |-
+ channels is the set of Cincinnati channels to which the release
+ currently belongs.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ image:
+ description: |-
+ image is a container image location that contains the update. When this
+ field is part of spec, image is optional if version is specified and the
+ availableUpdates field contains a matching version.
+ type: string
+ url:
+ description: |-
+ url contains information about this release. This URL is set by
+ the 'url' metadata property on a release or the metadata returned by
+ the update API and should be displayed as a link in user
+ interfaces. The URL field may not be set for test or nightly
+ releases.
+ type: string
+ version:
+ description: |-
+ version is a semantic version identifying the update version. When this
+ field is part of spec, version is optional if image is specified.
+ type: string
+ required:
+ - image
+ - version
+ type: object
+ history:
+ description: |-
+ history contains a list of the most recent versions applied to the cluster.
+ This value may be empty during cluster startup, and then will be updated
+ when a new update is being applied. The newest update is first in the
+ list and it is ordered by recency. Updates in the history have state
+ Completed if the rollout completed - if an update was failing or halfway
+ applied the state will be Partial. Only a limited amount of update history
+ is preserved.
+ items:
+ description: UpdateHistory is a single attempted update to the cluster.
+ properties:
+ acceptedRisks:
+ description: |-
+ acceptedRisks records risks which were accepted to initiate the update.
+ For example, it may mention an Upgradeable=False or missing signature
+ that was overridden via desiredUpdate.force, or an update that was
+ initiated despite not being in the availableUpdates set of recommended
+ update targets.
+ type: string
+ completionTime:
+ description: |-
+ completionTime, if set, is when the update was fully applied. The update
+ that is currently being applied will have a null completion time.
+ Completion time will always be set for entries that are not the current
+ update (usually to the started time of the next update).
+ format: date-time
+ nullable: true
+ type: string
+ image:
+ description: |-
+ image is a container image location that contains the update. This value
+ is always populated.
+ type: string
+ startedTime:
+ description: startedTime is the time at which the update was
+ started.
+ format: date-time
+ type: string
+ state:
+ description: |-
+ state reflects whether the update was fully applied. The Partial state
+ indicates the update is not fully applied, while the Completed state
+ indicates the update was successfully rolled out at least once (all
+ parts of the update successfully applied).
+ type: string
+ verified:
+ description: |-
+ verified indicates whether the provided update was properly verified
+ before it was installed. If this is false the cluster may not be trusted.
+ Verified does not cover upgradeable checks that depend on the cluster
+ state at the time when the update target was accepted.
+ type: boolean
+ version:
+ description: |-
+ version is a semantic version identifying the update version. If the
+ requested image does not define a version, or if a failure occurs
+ retrieving the image, this value may be empty.
+ type: string
+ required:
+ - completionTime
+ - image
+ - startedTime
+ - state
+ - verified
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ observedGeneration:
+ description: |-
+ observedGeneration reports which version of the spec is being synced.
+ If this value is not equal to metadata.generation, then the desired
+ and conditions fields may represent a previous version.
+ format: int64
+ type: integer
+ versionHash:
+ description: |-
+ versionHash is a fingerprint of the content that the cluster will be
+ updated with. It is used by the operator to avoid unnecessary work
+ and is for internal use only.
+ type: string
+ required:
+ - availableUpdates
+ - desired
+ - observedGeneration
+ - versionHash
+ type: object
+ required:
+ - spec
+ type: object
+ x-kubernetes-validations:
+ - message: the `marketplace` capability requires the `OperatorLifecycleManager`
+ capability, which is neither explicitly or implicitly enabled in this
+ cluster, please enable the `OperatorLifecycleManager` capability
+ rule: 'has(self.spec.capabilities) && has(self.spec.capabilities.additionalEnabledCapabilities)
+ && self.spec.capabilities.baselineCapabilitySet == ''None'' && ''marketplace''
+ in self.spec.capabilities.additionalEnabledCapabilities ? ''OperatorLifecycleManager''
+ in self.spec.capabilities.additionalEnabledCapabilities || (has(self.status)
+ && has(self.status.capabilities) && has(self.status.capabilities.enabledCapabilities)
+ && ''OperatorLifecycleManager'' in self.status.capabilities.enabledCapabilities)
+ : true'
+ served: true
+ storage: true
+ subresources:
+ status: {}
diff --git a/config/v1/zz_generated.swagger_doc_generated.go b/config/v1/zz_generated.swagger_doc_generated.go
index 69fb37c5233..e3e3be21186 100644
--- a/config/v1/zz_generated.swagger_doc_generated.go
+++ b/config/v1/zz_generated.swagger_doc_generated.go
@@ -915,6 +915,7 @@ var map_Update = map[string]string{
"image": "image is a container image location that contains the update. image should be used when the desired version does not exist in availableUpdates or history. When image is set, architecture cannot be specified. If both version and image are set, the version extracted from the referenced image must match the specified version.",
"force": "force allows an administrator to update to an image that has failed verification or upgradeable checks that are designed to keep your cluster safe. Only use this if: * you are testing unsigned release images in short-lived test clusters or * you are working around a known bug in the cluster-version\n operator and you have verified the authenticity of the provided\n image yourself.\nThe provided image will run with full administrative access to the cluster. Do not use this flag with images that come from unknown or potentially malicious sources.",
"acceptRisks": "acceptRisks is an optional set of names of conditional update risks that are considered acceptable. A conditional update is performed only if all of its risks are acceptable. This list may contain entries that apply to current, previous or future updates. The entries therefore may not map directly to a risk in .status.conditionalUpdateRisks. acceptRisks must not contain more than 1000 entries. Entries in this list must be unique.",
+ "mode": "mode determines how an update should be processed. The only valid value is \"Preflight\". When omitted, the cluster performs a normal update by applying the specified version or image to the cluster. This is the standard update behavior. When set to \"Preflight\", the cluster runs compatibility checks against the target release without performing an actual update. Compatibility results, including any detected risks, are reported in status.conditionalUpdates and status.conditionalUpdateRisks alongside risks from the update recommendation service. This allows administrators to assess update readiness and address issues before committing to the update. Preflight mode is particularly useful for skip-level updates where upgrade compatibility needs to be verified across multiple minor versions. When mode is set to \"Preflight\", the same rules for version, image, and architecture apply as for normal updates.",
}
func (Update) SwaggerDoc() map[string]string {
diff --git a/features.md b/features.md
index 5259884ec63..a9f94d0a88b 100644
--- a/features.md
+++ b/features.md
@@ -44,6 +44,7 @@
| ClusterAPIMachineManagementVSphere| | | Enabled | Enabled | | | Enabled | Enabled |
| ClusterMonitoringConfig| | | Enabled | Enabled | | | Enabled | Enabled |
| ClusterUpdateAcceptRisks| | | Enabled | Enabled | | | Enabled | Enabled |
+| ClusterUpdatePreflight| | | Enabled | Enabled | | | Enabled | Enabled |
| ClusterVersionOperatorConfiguration| | | Enabled | Enabled | | | Enabled | Enabled |
| ConfigurablePKI| | | Enabled | Enabled | | | Enabled | Enabled |
| DNSNameResolver| | | Enabled | Enabled | | | Enabled | Enabled |
diff --git a/features/features.go b/features/features.go
index 3ba5f3113e9..70a4d220e29 100644
--- a/features/features.go
+++ b/features/features.go
@@ -738,6 +738,14 @@ var (
enable(inDevPreviewNoUpgrade(), inTechPreviewNoUpgrade()).
mustRegister()
+ FeatureGateClusterUpdatePreflight = newFeatureGate("ClusterUpdatePreflight").
+ reportProblemsToJiraComponent("Cluster Version Operator").
+ contactPerson("fao89").
+ productScope(ocpSpecific).
+ enhancementPR("https://github.com/openshift/enhancements/pull/1930").
+ enable(inDevPreviewNoUpgrade(), inTechPreviewNoUpgrade()).
+ mustRegister()
+
FeatureGateGCPCustomAPIEndpoints = newFeatureGate("GCPCustomAPIEndpoints").
reportProblemsToJiraComponent("Installer").
contactPerson("barbacbd").
diff --git a/features/util.go b/features/util.go
index e2b35d93a92..8c95cc430a6 100644
--- a/features/util.go
+++ b/features/util.go
@@ -124,7 +124,8 @@ type featureGateBuilder struct {
owningProduct OwningProduct
enhancementPRURL string
- status []featureGateStatus
+ status []featureGateStatus
+ statusByClusterProfileByFeatureSet map[ClusterProfileName]map[configv1.FeatureSet]bool `json:"-"`
}
type featureGateStatus struct {
version sets.Set[uint64]
diff --git a/openapi/generated_openapi/zz_generated.openapi.go b/openapi/generated_openapi/zz_generated.openapi.go
index c2746f05d0b..db3fbc8cdbf 100644
--- a/openapi/generated_openapi/zz_generated.openapi.go
+++ b/openapi/generated_openapi/zz_generated.openapi.go
@@ -21500,6 +21500,14 @@ func schema_openshift_api_config_v1_Update(ref common.ReferenceCallback) common.
},
},
},
+ "mode": {
+ SchemaProps: spec.SchemaProps{
+ Description: "mode determines how an update should be processed. The only valid value is \"Preflight\". When omitted, the cluster performs a normal update by applying the specified version or image to the cluster. This is the standard update behavior. When set to \"Preflight\", the cluster runs compatibility checks against the target release without performing an actual update. Compatibility results, including any detected risks, are reported in status.conditionalUpdates and status.conditionalUpdateRisks alongside risks from the update recommendation service. This allows administrators to assess update readiness and address issues before committing to the update. Preflight mode is particularly useful for skip-level updates where upgrade compatibility needs to be verified across multiple minor versions. When mode is set to \"Preflight\", the same rules for version, image, and architecture apply as for normal updates.\n\nPossible enum values:\n - `\"Preflight\"` allows an update to be checked for compatibility without committing to updating the cluster.",
+ Type: []string{"string"},
+ Format: "",
+ Enum: []interface{}{"Preflight"},
+ },
+ },
},
},
},
diff --git a/openapi/openapi.json b/openapi/openapi.json
index fff430807d8..a3c453bbc36 100644
--- a/openapi/openapi.json
+++ b/openapi/openapi.json
@@ -6339,7 +6339,7 @@
],
"properties": {
"ciphers": {
- "description": "ciphers is used to specify the cipher algorithms that are negotiated during the TLS handshake. Operators may remove entries their operands do not support. For example, to use DES-CBC3-SHA (yaml):\n\n ciphers:\n - DES-CBC3-SHA",
+ "description": "ciphers is used to specify the cipher algorithms that are negotiated during the TLS handshake. Operators may remove entries that their operands do not support. For example, to use only ECDHE-RSA-AES128-GCM-SHA256 (yaml):\n\n ciphers:\n - ECDHE-RSA-AES128-GCM-SHA256\n\nTLS 1.3 cipher suites (e.g. TLS_AES_128_GCM_SHA256) are not configurable and are always enabled when TLS 1.3 is negotiated.",
"type": "array",
"items": {
"type": "string",
@@ -11311,7 +11311,7 @@
],
"properties": {
"ciphers": {
- "description": "ciphers is used to specify the cipher algorithms that are negotiated during the TLS handshake. Operators may remove entries their operands do not support. For example, to use DES-CBC3-SHA (yaml):\n\n ciphers:\n - DES-CBC3-SHA",
+ "description": "ciphers is used to specify the cipher algorithms that are negotiated during the TLS handshake. Operators may remove entries that their operands do not support. For example, to use only ECDHE-RSA-AES128-GCM-SHA256 (yaml):\n\n ciphers:\n - ECDHE-RSA-AES128-GCM-SHA256\n\nTLS 1.3 cipher suites (e.g. TLS_AES_128_GCM_SHA256) are not configurable and are always enabled when TLS 1.3 is negotiated.",
"type": "array",
"items": {
"type": "string",
@@ -11335,7 +11335,7 @@
"$ref": "#/definitions/com.github.openshift.api.config.v1.CustomTLSProfile"
},
"intermediate": {
- "description": "intermediate is a TLS profile for use when you do not need compatibility with legacy clients and want to remain highly secure while being compatible with most clients currently in use.\n\nThe cipher list includes TLS 1.3 ciphers for forward compatibility, followed by the \"intermediate\" profile ciphers.\n\nThis profile is equivalent to a Custom profile specified as:\n minTLSVersion: VersionTLS12\n ciphers:\n - TLS_AES_128_GCM_SHA256\n - TLS_AES_256_GCM_SHA384\n - TLS_CHACHA20_POLY1305_SHA256\n - ECDHE-ECDSA-AES128-GCM-SHA256\n - ECDHE-RSA-AES128-GCM-SHA256\n - ECDHE-ECDSA-AES256-GCM-SHA384\n - ECDHE-RSA-AES256-GCM-SHA384\n - ECDHE-ECDSA-CHACHA20-POLY1305\n - ECDHE-RSA-CHACHA20-POLY1305\n - DHE-RSA-AES128-GCM-SHA256\n - DHE-RSA-AES256-GCM-SHA384",
+ "description": "intermediate is a TLS profile for use when you do not need compatibility with legacy clients and want to remain highly secure while being compatible with most clients currently in use.\n\nThis profile is equivalent to a Custom profile specified as:\n minTLSVersion: VersionTLS12\n ciphers:\n - TLS_AES_128_GCM_SHA256\n - TLS_AES_256_GCM_SHA384\n - TLS_CHACHA20_POLY1305_SHA256\n - ECDHE-ECDSA-AES128-GCM-SHA256\n - ECDHE-RSA-AES128-GCM-SHA256\n - ECDHE-ECDSA-AES256-GCM-SHA384\n - ECDHE-RSA-AES256-GCM-SHA384\n - ECDHE-ECDSA-CHACHA20-POLY1305\n - ECDHE-RSA-CHACHA20-POLY1305",
"$ref": "#/definitions/com.github.openshift.api.config.v1.IntermediateTLSProfile"
},
"modern": {
@@ -11343,11 +11343,11 @@
"$ref": "#/definitions/com.github.openshift.api.config.v1.ModernTLSProfile"
},
"old": {
- "description": "old is a TLS profile for use when services need to be accessed by very old clients or libraries and should be used only as a last resort.\n\nThe cipher list includes TLS 1.3 ciphers for forward compatibility, followed by the \"old\" profile ciphers.\n\nThis profile is equivalent to a Custom profile specified as:\n minTLSVersion: VersionTLS10\n ciphers:\n - TLS_AES_128_GCM_SHA256\n - TLS_AES_256_GCM_SHA384\n - TLS_CHACHA20_POLY1305_SHA256\n - ECDHE-ECDSA-AES128-GCM-SHA256\n - ECDHE-RSA-AES128-GCM-SHA256\n - ECDHE-ECDSA-AES256-GCM-SHA384\n - ECDHE-RSA-AES256-GCM-SHA384\n - ECDHE-ECDSA-CHACHA20-POLY1305\n - ECDHE-RSA-CHACHA20-POLY1305\n - DHE-RSA-AES128-GCM-SHA256\n - DHE-RSA-AES256-GCM-SHA384\n - DHE-RSA-CHACHA20-POLY1305\n - ECDHE-ECDSA-AES128-SHA256\n - ECDHE-RSA-AES128-SHA256\n - ECDHE-ECDSA-AES128-SHA\n - ECDHE-RSA-AES128-SHA\n - ECDHE-ECDSA-AES256-SHA384\n - ECDHE-RSA-AES256-SHA384\n - ECDHE-ECDSA-AES256-SHA\n - ECDHE-RSA-AES256-SHA\n - DHE-RSA-AES128-SHA256\n - DHE-RSA-AES256-SHA256\n - AES128-GCM-SHA256\n - AES256-GCM-SHA384\n - AES128-SHA256\n - AES256-SHA256\n - AES128-SHA\n - AES256-SHA\n - DES-CBC3-SHA",
+ "description": "old is a TLS profile for use when services need to be accessed by very old clients or libraries and should be used only as a last resort.\n\nThis profile is equivalent to a Custom profile specified as:\n minTLSVersion: VersionTLS10\n ciphers:\n - TLS_AES_128_GCM_SHA256\n - TLS_AES_256_GCM_SHA384\n - TLS_CHACHA20_POLY1305_SHA256\n - ECDHE-ECDSA-AES128-GCM-SHA256\n - ECDHE-RSA-AES128-GCM-SHA256\n - ECDHE-ECDSA-AES256-GCM-SHA384\n - ECDHE-RSA-AES256-GCM-SHA384\n - ECDHE-ECDSA-CHACHA20-POLY1305\n - ECDHE-RSA-CHACHA20-POLY1305\n - ECDHE-ECDSA-AES128-SHA256\n - ECDHE-RSA-AES128-SHA256\n - ECDHE-ECDSA-AES128-SHA\n - ECDHE-RSA-AES128-SHA\n - ECDHE-ECDSA-AES256-SHA\n - ECDHE-RSA-AES256-SHA\n - AES128-GCM-SHA256\n - AES256-GCM-SHA384\n - AES128-SHA256\n - AES128-SHA\n - AES256-SHA\n - DES-CBC3-SHA",
"$ref": "#/definitions/com.github.openshift.api.config.v1.OldTLSProfile"
},
"type": {
- "description": "type is one of Old, Intermediate, Modern or Custom. Custom provides the ability to specify individual TLS security profile parameters.\n\nThe profiles are currently based on version 5.0 of the Mozilla Server Side TLS configuration guidelines (released 2019-06-28) with TLS 1.3 ciphers added for forward compatibility. See: https://ssl-config.mozilla.org/guidelines/5.0.json\n\nThe profiles are intent based, so they may change over time as new ciphers are developed and existing ciphers are found to be insecure. Depending on precisely which ciphers are available to a process, the list may be reduced.",
+ "description": "type is one of Old, Intermediate, Modern or Custom. Custom provides the ability to specify individual TLS security profile parameters.\n\nThe profiles are based on version 5.7 of the Mozilla Server Side TLS configuration guidelines. The cipher lists consist of the configuration's \"ciphersuites\" followed by the Go-specific \"ciphers\" from the guidelines. See: https://ssl-config.mozilla.org/guidelines/5.7.json\n\nThe profiles are intent based, so they may change over time as new ciphers are developed and existing ciphers are found to be insecure. Depending on precisely which ciphers are available to a process, the list may be reduced.",
"type": "string",
"default": ""
}
@@ -11663,6 +11663,13 @@
"type": "string",
"default": ""
},
+ "mode": {
+ "description": "mode determines how an update should be processed. The only valid value is \"Preflight\". When omitted, the cluster performs a normal update by applying the specified version or image to the cluster. This is the standard update behavior. When set to \"Preflight\", the cluster runs compatibility checks against the target release without performing an actual update. Compatibility results, including any detected risks, are reported in status.conditionalUpdates and status.conditionalUpdateRisks alongside risks from the update recommendation service. This allows administrators to assess update readiness and address issues before committing to the update. Preflight mode is particularly useful for skip-level updates where upgrade compatibility needs to be verified across multiple minor versions. When mode is set to \"Preflight\", the same rules for version, image, and architecture apply as for normal updates.\n\nPossible enum values:\n - `\"Preflight\"` allows an update to be checked for compatibility without committing to updating the cluster.",
+ "type": "string",
+ "enum": [
+ "Preflight"
+ ]
+ },
"version": {
"description": "version is a semantic version identifying the update version. version is required if architecture is specified. If both version and image are set, the version extracted from the referenced image must match the specified version.",
"type": "string",
@@ -26310,7 +26317,13 @@
},
"com.github.openshift.api.machineconfiguration.v1alpha1.OSImageStreamSpec": {
"description": "OSImageStreamSpec defines the desired state of a OSImageStream.",
- "type": "object"
+ "type": "object",
+ "properties": {
+ "defaultStream": {
+ "description": "defaultStream is the desired name of the stream that should be used as the default when no specific stream is requested by a MachineConfigPool.\n\nThis field is set by the installer during installation. Users may need to update it if the currently selected stream is no longer available, for example when the stream has reached its End of Life. The MachineConfigOperator uses this value to determine which stream from status.availableStreams to apply as the default for MachineConfigPools that do not specify a stream override.\n\nIt must be a valid RFC 1123 subdomain between 1 and 253 characters in length, consisting of lowercase alphanumeric characters, hyphens ('-'), and periods ('.').",
+ "type": "string"
+ }
+ }
},
"com.github.openshift.api.machineconfiguration.v1alpha1.OSImageStreamStatus": {
"description": "OSImageStreamStatus describes the current state of a OSImageStream",
@@ -35897,7 +35910,6 @@
},
"spec": {
"description": "spec is the specification of the desired behavior of the capi-operator.",
- "default": {},
"$ref": "#/definitions/com.github.openshift.api.operator.v1alpha1.ClusterAPISpec"
},
"status": {
@@ -35907,6 +35919,96 @@
}
}
},
+ "com.github.openshift.api.operator.v1alpha1.ClusterAPIInstallerComponent": {
+ "description": "ClusterAPIInstallerComponent defines a component which will be installed by this revision.",
+ "type": "object",
+ "required": [
+ "type"
+ ],
+ "properties": {
+ "image": {
+ "description": "image defines an image source for a component. The image must contain a /capi-operator-installer directory containing the component manifests.",
+ "default": {},
+ "$ref": "#/definitions/com.github.openshift.api.operator.v1alpha1.ClusterAPIInstallerComponentImage"
+ },
+ "type": {
+ "description": "type is the source type of the component. The only valid value is Image. When set to Image, the image field must be set and will define an image source for the component.\n\nPossible enum values:\n - `\"Image\"` is an image source for a component.",
+ "type": "string",
+ "enum": [
+ "Image"
+ ]
+ }
+ },
+ "x-kubernetes-unions": [
+ {
+ "discriminator": "type",
+ "fields-to-discriminateBy": {
+ "image": "Image"
+ }
+ }
+ ]
+ },
+ "com.github.openshift.api.operator.v1alpha1.ClusterAPIInstallerComponentImage": {
+ "description": "ClusterAPIInstallerComponentImage defines an image source for a component.",
+ "type": "object",
+ "required": [
+ "ref",
+ "profile"
+ ],
+ "properties": {
+ "profile": {
+ "description": "profile is the name of a profile to use from the image.\n\nA profile name may be up to 255 characters long. It must consist of alphanumeric characters, '-', or '_'.",
+ "type": "string"
+ },
+ "ref": {
+ "description": "ref is an image reference to the image containing the component manifests. The reference must be a valid image digest reference in the format host[:port][/namespace]/name@sha256:. The digest must be 64 characters long, and consist only of lowercase hexadecimal characters, a-f and 0-9. The length of the field must be between 1 to 447 characters.",
+ "type": "string"
+ }
+ }
+ },
+ "com.github.openshift.api.operator.v1alpha1.ClusterAPIInstallerRevision": {
+ "type": "object",
+ "required": [
+ "name",
+ "revision",
+ "contentID",
+ "components"
+ ],
+ "properties": {
+ "components": {
+ "description": "components is list of components which will be installed by this revision. Components will be installed in the order they are listed.\n\nThe maximum number of components is 32.",
+ "type": "array",
+ "items": {
+ "default": {},
+ "$ref": "#/definitions/com.github.openshift.api.operator.v1alpha1.ClusterAPIInstallerComponent"
+ },
+ "x-kubernetes-list-type": "atomic"
+ },
+ "contentID": {
+ "description": "contentID uniquely identifies the content of this revision. The contentID must be between 1 and 255 characters long.",
+ "type": "string"
+ },
+ "name": {
+ "description": "name is the name of a revision.",
+ "type": "string"
+ },
+ "revision": {
+ "description": "revision is a monotonically increasing number that is assigned to a revision.",
+ "type": "integer",
+ "format": "int64"
+ },
+ "unmanagedCustomResourceDefinitions": {
+ "description": "unmanagedCustomResourceDefinitions is a list of the names of ClusterResourceDefinition (CRD) objects which are included in this revision, but which should not be installed or updated. If not set, all CRDs in the revision will be managed by the CAPI operator.",
+ "type": "array",
+ "items": {
+ "type": "string",
+ "default": ""
+ },
+ "x-kubernetes-list-type": "atomic"
+ }
+ },
+ "x-kubernetes-map-type": "atomic"
+ },
"com.github.openshift.api.operator.v1alpha1.ClusterAPIList": {
"description": "ClusterAPIList contains a list of ClusterAPI configurations\n\nCompatibility level 4: No compatibility is provided, the API can change at any point for any reason. These capabilities should not be used by applications needing long term support.",
"type": "object",
@@ -35939,11 +36041,11 @@
}
},
"com.github.openshift.api.operator.v1alpha1.ClusterAPISpec": {
- "description": "ClusterAPISpec defines the desired configuration of the capi-operator.",
+ "description": "ClusterAPISpec defines the desired configuration of the capi-operator. The spec is required but we deliberately allow it to be empty.",
"type": "object",
"properties": {
"unmanagedCustomResourceDefinitions": {
- "description": "unmanagedCustomResourceDefinitions is a list of ClusterResourceDefinition (CRD) names that should not be managed by the capi-operator installer controller. This allows external actors to own specific CRDs while capi-operator manages others.\n\nEach CRD name must be a valid DNS-1123 subdomain consisting of lowercase alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character, with a maximum length of 253 characters. Example: \"clusters.cluster.x-k8s.io\"\n\nItems cannot be removed from this list once added.\n\nThe maximum number of unmanagedCustomResourceDefinitions is 128.",
+ "description": "unmanagedCustomResourceDefinitions is a list of ClusterResourceDefinition (CRD) names that should not be managed by the capi-operator installer controller. This allows external actors to own specific CRDs while capi-operator manages others.\n\nEach CRD name must be a valid DNS-1123 subdomain consisting of lowercase alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character, with a maximum length of 253 characters. CRD names must contain at least two '.' characters. Example: \"clusters.cluster.x-k8s.io\"\n\nItems cannot be removed from this list once added.\n\nThe maximum number of unmanagedCustomResourceDefinitions is 128.",
"type": "array",
"items": {
"type": "string",
@@ -35956,22 +36058,25 @@
"com.github.openshift.api.operator.v1alpha1.ClusterAPIStatus": {
"description": "ClusterAPIStatus describes the current state of the capi-operator.",
"type": "object",
+ "required": [
+ "desiredRevision",
+ "revisions"
+ ],
"properties": {
- "activeConfigMaps": {
- "description": "activeConfigMaps is a list of ConfigMap names that the installer controller has successfully reconciled. This represents the currently deployed CAPI provider components.\n\nEach ConfigMap name must be a valid DNS-1123 label consisting of lowercase alphanumeric characters or hyphens, starting and ending with an alphanumeric character, with a maximum length of 63 characters.\n\nThis field is owned by the installer controller and is updated atomically after a successful reconciliation.\n\nThe maximum number of activeConfigMaps is 128.",
- "type": "array",
- "items": {
- "type": "string",
- "default": ""
- },
- "x-kubernetes-list-type": "atomic"
+ "currentRevision": {
+ "description": "currentRevision is the name of the most recently fully applied revision. It is written by the installer controller. If it is absent, it indicates that no revision has been fully applied yet. If set, currentRevision must correspond to an entry in the revisions list.",
+ "type": "string"
},
- "targetConfigMaps": {
- "description": "targetConfigMaps is a list of ConfigMap names that the staging controller has validated and approved for reconciliation. The installer controller will reconcile these ConfigMaps.\n\nEach ConfigMap name must be a valid DNS-1123 label consisting of lowercase alphanumeric characters or hyphens, starting and ending with an alphanumeric character, with a maximum length of 63 characters.\n\nThis field is owned by the staging controller and is updated atomically to a consistent set of transport ConfigMaps that have passed validation checks.\n\nThe maximum number of targetConfigMaps is 128.",
+ "desiredRevision": {
+ "description": "desiredRevision is the name of the desired revision. It is written by the revision controller. It must be set to the name of the entry in the revisions list with the highest revision number.",
+ "type": "string"
+ },
+ "revisions": {
+ "description": "revisions is a list of all currently active revisions. A revision is active until the installer controller updates currentRevision to a later revision. It is written by the revision controller.\n\nThe maximum number of revisions is 16. All revisions must have a unique name. All revisions must have a unique revision number. When adding a revision, the revision number must be greater than the highest revision number in the list. Revisions are immutable, although they can be deleted.",
"type": "array",
"items": {
- "type": "string",
- "default": ""
+ "default": {},
+ "$ref": "#/definitions/com.github.openshift.api.operator.v1alpha1.ClusterAPIInstallerRevision"
},
"x-kubernetes-list-type": "atomic"
}
@@ -37023,7 +37128,8 @@
"items": {
"default": {},
"$ref": "#/definitions/com.github.openshift.api.operatoringress.v1.DNSRecord"
- }
+ },
+ "x-kubernetes-list-type": "atomic"
},
"kind": {
"description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
@@ -37074,7 +37180,8 @@
"items": {
"type": "string",
"default": ""
- }
+ },
+ "x-kubernetes-list-type": "atomic"
}
}
},
@@ -37093,7 +37200,8 @@
"items": {
"default": {},
"$ref": "#/definitions/com.github.openshift.api.operatoringress.v1.DNSZoneStatus"
- }
+ },
+ "x-kubernetes-list-type": "atomic"
}
}
},
@@ -37137,7 +37245,8 @@
"items": {
"default": {},
"$ref": "#/definitions/com.github.openshift.api.operatoringress.v1.DNSZoneCondition"
- }
+ },
+ "x-kubernetes-list-type": "atomic"
},
"dnsZone": {
"description": "dnsZone is the zone where the record is published.",
@@ -52174,77 +52283,6 @@
"description": "IntOrString is a type that can hold an int32 or a string. When used in JSON or YAML marshalling and unmarshalling, it produces or consumes the inner type. This allows you to have, for example, a JSON field that can accept a name or number.",
"type": "string",
"format": "int-or-string"
- },
- "io.k8s.apimachinery.pkg.version.Info": {
- "description": "Info contains versioning information. how we'll want to distribute that information.",
- "type": "object",
- "required": [
- "major",
- "minor",
- "gitVersion",
- "gitCommit",
- "gitTreeState",
- "buildDate",
- "goVersion",
- "compiler",
- "platform"
- ],
- "properties": {
- "buildDate": {
- "type": "string",
- "default": ""
- },
- "compiler": {
- "type": "string",
- "default": ""
- },
- "emulationMajor": {
- "description": "EmulationMajor is the major version of the emulation version",
- "type": "string"
- },
- "emulationMinor": {
- "description": "EmulationMinor is the minor version of the emulation version",
- "type": "string"
- },
- "gitCommit": {
- "type": "string",
- "default": ""
- },
- "gitTreeState": {
- "type": "string",
- "default": ""
- },
- "gitVersion": {
- "type": "string",
- "default": ""
- },
- "goVersion": {
- "type": "string",
- "default": ""
- },
- "major": {
- "description": "Major is the major version of the binary version",
- "type": "string",
- "default": ""
- },
- "minCompatibilityMajor": {
- "description": "MinCompatibilityMajor is the major version of the minimum compatibility version",
- "type": "string"
- },
- "minCompatibilityMinor": {
- "description": "MinCompatibilityMinor is the minor version of the minimum compatibility version",
- "type": "string"
- },
- "minor": {
- "description": "Minor is the minor version of the binary version",
- "type": "string",
- "default": ""
- },
- "platform": {
- "type": "string",
- "default": ""
- }
- }
}
}
}
diff --git a/payload-manifests/featuregates/featureGate-4-10-Hypershift-Default.yaml b/payload-manifests/featuregates/featureGate-4-10-Hypershift-Default.yaml
index db59d186a29..59d3133e550 100644
--- a/payload-manifests/featuregates/featureGate-4-10-Hypershift-Default.yaml
+++ b/payload-manifests/featuregates/featureGate-4-10-Hypershift-Default.yaml
@@ -107,6 +107,9 @@
{
"name": "ClusterUpdateAcceptRisks"
},
+ {
+ "name": "ClusterUpdatePreflight"
+ },
{
"name": "ClusterVersionOperatorConfiguration"
},
diff --git a/payload-manifests/featuregates/featureGate-4-10-Hypershift-DevPreviewNoUpgrade.yaml b/payload-manifests/featuregates/featureGate-4-10-Hypershift-DevPreviewNoUpgrade.yaml
index bcb089a53bf..47b885b97c9 100644
--- a/payload-manifests/featuregates/featureGate-4-10-Hypershift-DevPreviewNoUpgrade.yaml
+++ b/payload-manifests/featuregates/featureGate-4-10-Hypershift-DevPreviewNoUpgrade.yaml
@@ -150,6 +150,9 @@
{
"name": "ClusterUpdateAcceptRisks"
},
+ {
+ "name": "ClusterUpdatePreflight"
+ },
{
"name": "ClusterVersionOperatorConfiguration"
},
diff --git a/payload-manifests/featuregates/featureGate-4-10-Hypershift-OKD.yaml b/payload-manifests/featuregates/featureGate-4-10-Hypershift-OKD.yaml
index 332c549cafa..f29239e2c2b 100644
--- a/payload-manifests/featuregates/featureGate-4-10-Hypershift-OKD.yaml
+++ b/payload-manifests/featuregates/featureGate-4-10-Hypershift-OKD.yaml
@@ -109,6 +109,9 @@
{
"name": "ClusterUpdateAcceptRisks"
},
+ {
+ "name": "ClusterUpdatePreflight"
+ },
{
"name": "ClusterVersionOperatorConfiguration"
},
diff --git a/payload-manifests/featuregates/featureGate-4-10-Hypershift-TechPreviewNoUpgrade.yaml b/payload-manifests/featuregates/featureGate-4-10-Hypershift-TechPreviewNoUpgrade.yaml
index dcf160c5417..79f02493fa8 100644
--- a/payload-manifests/featuregates/featureGate-4-10-Hypershift-TechPreviewNoUpgrade.yaml
+++ b/payload-manifests/featuregates/featureGate-4-10-Hypershift-TechPreviewNoUpgrade.yaml
@@ -165,6 +165,9 @@
{
"name": "ClusterUpdateAcceptRisks"
},
+ {
+ "name": "ClusterUpdatePreflight"
+ },
{
"name": "ClusterVersionOperatorConfiguration"
},
diff --git a/payload-manifests/featuregates/featureGate-4-10-SelfManagedHA-Default.yaml b/payload-manifests/featuregates/featureGate-4-10-SelfManagedHA-Default.yaml
index 72e73eb4233..e8e6ec5fd06 100644
--- a/payload-manifests/featuregates/featureGate-4-10-SelfManagedHA-Default.yaml
+++ b/payload-manifests/featuregates/featureGate-4-10-SelfManagedHA-Default.yaml
@@ -107,6 +107,9 @@
{
"name": "ClusterUpdateAcceptRisks"
},
+ {
+ "name": "ClusterUpdatePreflight"
+ },
{
"name": "ClusterVersionOperatorConfiguration"
},
diff --git a/payload-manifests/featuregates/featureGate-4-10-SelfManagedHA-DevPreviewNoUpgrade.yaml b/payload-manifests/featuregates/featureGate-4-10-SelfManagedHA-DevPreviewNoUpgrade.yaml
index f29f4947246..b754d66f5d7 100644
--- a/payload-manifests/featuregates/featureGate-4-10-SelfManagedHA-DevPreviewNoUpgrade.yaml
+++ b/payload-manifests/featuregates/featureGate-4-10-SelfManagedHA-DevPreviewNoUpgrade.yaml
@@ -132,6 +132,9 @@
{
"name": "ClusterUpdateAcceptRisks"
},
+ {
+ "name": "ClusterUpdatePreflight"
+ },
{
"name": "ClusterVersionOperatorConfiguration"
},
diff --git a/payload-manifests/featuregates/featureGate-4-10-SelfManagedHA-OKD.yaml b/payload-manifests/featuregates/featureGate-4-10-SelfManagedHA-OKD.yaml
index 7f29f0d1a1a..e5adb1189a1 100644
--- a/payload-manifests/featuregates/featureGate-4-10-SelfManagedHA-OKD.yaml
+++ b/payload-manifests/featuregates/featureGate-4-10-SelfManagedHA-OKD.yaml
@@ -109,6 +109,9 @@
{
"name": "ClusterUpdateAcceptRisks"
},
+ {
+ "name": "ClusterUpdatePreflight"
+ },
{
"name": "ClusterVersionOperatorConfiguration"
},
diff --git a/payload-manifests/featuregates/featureGate-4-10-SelfManagedHA-TechPreviewNoUpgrade.yaml b/payload-manifests/featuregates/featureGate-4-10-SelfManagedHA-TechPreviewNoUpgrade.yaml
index be6d15233f7..c582571ebee 100644
--- a/payload-manifests/featuregates/featureGate-4-10-SelfManagedHA-TechPreviewNoUpgrade.yaml
+++ b/payload-manifests/featuregates/featureGate-4-10-SelfManagedHA-TechPreviewNoUpgrade.yaml
@@ -147,6 +147,9 @@
{
"name": "ClusterUpdateAcceptRisks"
},
+ {
+ "name": "ClusterUpdatePreflight"
+ },
{
"name": "ClusterVersionOperatorConfiguration"
},