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..60ee24bfc3e --- /dev/null +++ b/config/v1/tests/clusterversions.config.openshift.io/ClusterUpdatePreflight.yaml @@ -0,0 +1,208 @@ +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 reject when both force and mode are set + initial: | + apiVersion: config.openshift.io/v1 + kind: ClusterVersion + spec: + clusterID: foo + desiredUpdate: + version: 4.22.0 + mode: Preflight + force: true + expectedError: "force and mode are mutually exclusive" + 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..25507f7d4a1 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 +// UpdateModePolicy defines how an update should be processed. +// +enum +// +kubebuilder:validation:Enum=Preflight +type UpdateModePolicy string + +const ( + // UpdateModePolicyPreflight allows an update to be checked for compatibility without committing to updating the cluster. + UpdateModePolicyPreflight UpdateModePolicy = "Preflight" +) + // ClusterVersionArchitecture enumerates valid cluster architectures. // +kubebuilder:validation:Enum="Multi";"" type ClusterVersionArchitecture string @@ -704,6 +714,7 @@ type URL string // Update represents an administrator update request. // +kubebuilder:validation:XValidation:rule="has(self.architecture) && has(self.image) ? (self.architecture == \"\" || self.image == \"\") : true",message="cannot set both Architecture and Image" // +kubebuilder:validation:XValidation:rule="has(self.architecture) && self.architecture != \"\" ? self.version != \"\" : true",message="Version must be set if Architecture is set" +// +kubebuilder:validation:XValidation:rule="has(self.force) && has(self.mode) && self.force && self.mode != \"\" ? false : true",message="force and mode are mutually exclusive" // +k8s:deepcopy-gen=true type Update struct { // architecture is an optional field that indicates the desired @@ -760,6 +771,23 @@ 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. The target release's CVO will execute pre-checks and report any detected + // risks in status.conditionalUpdateRisks, alongside risks from the update recommendation service. + // status.conditionalUpdates contains references/entries that point to the detailed risk objects + // stored in status.conditionalUpdateRisks from both the update graph and preflight checks executed by the target release's CVO. + // 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. + // The mode and force fields are mutually exclusive - mode cannot be set when force is true. + // +optional + Mode UpdateModePolicy `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..1baf1b3fffc 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,25 @@ 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. The target release's CVO will execute pre-checks and report any detected + risks in status.conditionalUpdateRisks, alongside risks from the update recommendation service. + status.conditionalUpdates contains references/entries that point to the detailed risk objects + stored in status.conditionalUpdateRisks from both the update graph and preflight checks executed by the target release's CVO. + 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. + The mode and force fields are mutually exclusive - mode cannot be set when force is true. + enum: + - Preflight + type: string version: description: |- version is a semantic version identifying the update version. @@ -232,6 +251,9 @@ spec: - message: Version must be set if Architecture is set rule: 'has(self.architecture) && self.architecture != "" ? self.version != "" : true' + - message: force and mode are mutually exclusive + rule: 'has(self.force) && has(self.mode) && self.force && self.mode + != "" ? false : true' overrides: description: |- overrides is list of overides for components that are managed by diff --git a/config/v1/zz_generated.crd-manifests/0000_00_cluster-version-operator_01_clusterversions-Default.crd.yaml b/config/v1/zz_generated.crd-manifests/0000_00_cluster-version-operator_01_clusterversions-Default.crd.yaml index 430a39025ff..20a1946b4b6 100644 --- a/config/v1/zz_generated.crd-manifests/0000_00_cluster-version-operator_01_clusterversions-Default.crd.yaml +++ b/config/v1/zz_generated.crd-manifests/0000_00_cluster-version-operator_01_clusterversions-Default.crd.yaml @@ -190,6 +190,25 @@ 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. The target release's CVO will execute pre-checks and report any detected + risks in status.conditionalUpdateRisks, alongside risks from the update recommendation service. + status.conditionalUpdates contains references/entries that point to the detailed risk objects + stored in status.conditionalUpdateRisks from both the update graph and preflight checks executed by the target release's CVO. + 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. + The mode and force fields are mutually exclusive - mode cannot be set when force is true. + enum: + - Preflight + type: string version: description: |- version is a semantic version identifying the update version. @@ -204,6 +223,9 @@ spec: - message: Version must be set if Architecture is set rule: 'has(self.architecture) && self.architecture != "" ? self.version != "" : true' + - message: force and mode are mutually exclusive + rule: 'has(self.force) && has(self.mode) && self.force && self.mode + != "" ? false : true' overrides: description: |- overrides is list of overides for components that are managed by 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..399d7ba3c04 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,25 @@ 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. The target release's CVO will execute pre-checks and report any detected + risks in status.conditionalUpdateRisks, alongside risks from the update recommendation service. + status.conditionalUpdates contains references/entries that point to the detailed risk objects + stored in status.conditionalUpdateRisks from both the update graph and preflight checks executed by the target release's CVO. + 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. + The mode and force fields are mutually exclusive - mode cannot be set when force is true. + enum: + - Preflight + type: string version: description: |- version is a semantic version identifying the update version. @@ -232,6 +251,9 @@ spec: - message: Version must be set if Architecture is set rule: 'has(self.architecture) && self.architecture != "" ? self.version != "" : true' + - message: force and mode are mutually exclusive + rule: 'has(self.force) && has(self.mode) && self.force && self.mode + != "" ? false : true' overrides: description: |- overrides is list of overides for components that are managed by diff --git a/config/v1/zz_generated.crd-manifests/0000_00_cluster-version-operator_01_clusterversions-OKD.crd.yaml b/config/v1/zz_generated.crd-manifests/0000_00_cluster-version-operator_01_clusterversions-OKD.crd.yaml index 1ae333ddc69..970579a3f50 100644 --- a/config/v1/zz_generated.crd-manifests/0000_00_cluster-version-operator_01_clusterversions-OKD.crd.yaml +++ b/config/v1/zz_generated.crd-manifests/0000_00_cluster-version-operator_01_clusterversions-OKD.crd.yaml @@ -190,6 +190,25 @@ 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. The target release's CVO will execute pre-checks and report any detected + risks in status.conditionalUpdateRisks, alongside risks from the update recommendation service. + status.conditionalUpdates contains references/entries that point to the detailed risk objects + stored in status.conditionalUpdateRisks from both the update graph and preflight checks executed by the target release's CVO. + 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. + The mode and force fields are mutually exclusive - mode cannot be set when force is true. + enum: + - Preflight + type: string version: description: |- version is a semantic version identifying the update version. @@ -204,6 +223,9 @@ spec: - message: Version must be set if Architecture is set rule: 'has(self.architecture) && self.architecture != "" ? self.version != "" : true' + - message: force and mode are mutually exclusive + rule: 'has(self.force) && has(self.mode) && self.force && self.mode + != "" ? false : true' overrides: description: |- overrides is list of overides for components that are managed by 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..79189efbabb 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,25 @@ 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. The target release's CVO will execute pre-checks and report any detected + risks in status.conditionalUpdateRisks, alongside risks from the update recommendation service. + status.conditionalUpdates contains references/entries that point to the detailed risk objects + stored in status.conditionalUpdateRisks from both the update graph and preflight checks executed by the target release's CVO. + 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. + The mode and force fields are mutually exclusive - mode cannot be set when force is true. + enum: + - Preflight + type: string version: description: |- version is a semantic version identifying the update version. @@ -232,6 +251,9 @@ spec: - message: Version must be set if Architecture is set rule: 'has(self.architecture) && self.architecture != "" ? self.version != "" : true' + - message: force and mode are mutually exclusive + rule: 'has(self.force) && has(self.mode) && self.force && self.mode + != "" ? false : true' overrides: description: |- overrides is list of overides for components that are managed by diff --git a/config/v1/zz_generated.featuregated-crd-manifests/clusterversions.config.openshift.io/AAA_ungated.yaml b/config/v1/zz_generated.featuregated-crd-manifests/clusterversions.config.openshift.io/AAA_ungated.yaml index c7edb6835a1..1bb7a8481e7 100644 --- a/config/v1/zz_generated.featuregated-crd-manifests/clusterversions.config.openshift.io/AAA_ungated.yaml +++ b/config/v1/zz_generated.featuregated-crd-manifests/clusterversions.config.openshift.io/AAA_ungated.yaml @@ -192,6 +192,25 @@ 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. The target release's CVO will execute pre-checks and report any detected + risks in status.conditionalUpdateRisks, alongside risks from the update recommendation service. + status.conditionalUpdates contains references/entries that point to the detailed risk objects + stored in status.conditionalUpdateRisks from both the update graph and preflight checks executed by the target release's CVO. + 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. + The mode and force fields are mutually exclusive - mode cannot be set when force is true. + enum: + - Preflight + type: string version: description: |- version is a semantic version identifying the update version. @@ -206,6 +225,9 @@ spec: - message: Version must be set if Architecture is set rule: 'has(self.architecture) && self.architecture != "" ? self.version != "" : true' + - message: force and mode are mutually exclusive + rule: 'has(self.force) && has(self.mode) && self.force && self.mode + != "" ? false : true' overrides: description: |- overrides is list of overides for components that are managed by diff --git a/config/v1/zz_generated.featuregated-crd-manifests/clusterversions.config.openshift.io/ClusterUpdateAcceptRisks.yaml b/config/v1/zz_generated.featuregated-crd-manifests/clusterversions.config.openshift.io/ClusterUpdateAcceptRisks.yaml index e5ac1631330..117cae719d9 100644 --- a/config/v1/zz_generated.featuregated-crd-manifests/clusterversions.config.openshift.io/ClusterUpdateAcceptRisks.yaml +++ b/config/v1/zz_generated.featuregated-crd-manifests/clusterversions.config.openshift.io/ClusterUpdateAcceptRisks.yaml @@ -220,6 +220,25 @@ 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. The target release's CVO will execute pre-checks and report any detected + risks in status.conditionalUpdateRisks, alongside risks from the update recommendation service. + status.conditionalUpdates contains references/entries that point to the detailed risk objects + stored in status.conditionalUpdateRisks from both the update graph and preflight checks executed by the target release's CVO. + 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. + The mode and force fields are mutually exclusive - mode cannot be set when force is true. + enum: + - Preflight + type: string version: description: |- version is a semantic version identifying the update version. @@ -234,6 +253,9 @@ spec: - message: Version must be set if Architecture is set rule: 'has(self.architecture) && self.architecture != "" ? self.version != "" : true' + - message: force and mode are mutually exclusive + rule: 'has(self.force) && has(self.mode) && self.force && self.mode + != "" ? false : true' overrides: description: |- overrides is list of overides for components that are managed by diff --git a/config/v1/zz_generated.featuregated-crd-manifests/clusterversions.config.openshift.io/ImageStreamImportMode.yaml b/config/v1/zz_generated.featuregated-crd-manifests/clusterversions.config.openshift.io/ImageStreamImportMode.yaml index 5682079136d..c890d989434 100644 --- a/config/v1/zz_generated.featuregated-crd-manifests/clusterversions.config.openshift.io/ImageStreamImportMode.yaml +++ b/config/v1/zz_generated.featuregated-crd-manifests/clusterversions.config.openshift.io/ImageStreamImportMode.yaml @@ -192,6 +192,25 @@ 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. The target release's CVO will execute pre-checks and report any detected + risks in status.conditionalUpdateRisks, alongside risks from the update recommendation service. + status.conditionalUpdates contains references/entries that point to the detailed risk objects + stored in status.conditionalUpdateRisks from both the update graph and preflight checks executed by the target release's CVO. + 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. + The mode and force fields are mutually exclusive - mode cannot be set when force is true. + enum: + - Preflight + type: string version: description: |- version is a semantic version identifying the update version. @@ -206,6 +225,9 @@ spec: - message: Version must be set if Architecture is set rule: 'has(self.architecture) && self.architecture != "" ? self.version != "" : true' + - message: force and mode are mutually exclusive + rule: 'has(self.force) && has(self.mode) && self.force && self.mode + != "" ? false : true' overrides: description: |- overrides is list of overides for components that are managed by diff --git a/config/v1/zz_generated.featuregated-crd-manifests/clusterversions.config.openshift.io/SignatureStores.yaml b/config/v1/zz_generated.featuregated-crd-manifests/clusterversions.config.openshift.io/SignatureStores.yaml index 17ca96c1c8f..934ddcc19ce 100644 --- a/config/v1/zz_generated.featuregated-crd-manifests/clusterversions.config.openshift.io/SignatureStores.yaml +++ b/config/v1/zz_generated.featuregated-crd-manifests/clusterversions.config.openshift.io/SignatureStores.yaml @@ -192,6 +192,25 @@ 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. The target release's CVO will execute pre-checks and report any detected + risks in status.conditionalUpdateRisks, alongside risks from the update recommendation service. + status.conditionalUpdates contains references/entries that point to the detailed risk objects + stored in status.conditionalUpdateRisks from both the update graph and preflight checks executed by the target release's CVO. + 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. + The mode and force fields are mutually exclusive - mode cannot be set when force is true. + enum: + - Preflight + type: string version: description: |- version is a semantic version identifying the update version. @@ -206,6 +225,9 @@ spec: - message: Version must be set if Architecture is set rule: 'has(self.architecture) && self.architecture != "" ? self.version != "" : true' + - message: force and mode are mutually exclusive + rule: 'has(self.force) && has(self.mode) && self.force && self.mode + != "" ? false : true' overrides: description: |- overrides is list of overides for components that are managed by diff --git a/config/v1/zz_generated.swagger_doc_generated.go b/config/v1/zz_generated.swagger_doc_generated.go index 7f0018950a9..cb8eb797b93 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. The target release's CVO will execute pre-checks and report any detected risks in status.conditionalUpdateRisks, alongside risks from the update recommendation service. status.conditionalUpdates contains references/entries that point to the detailed risk objects stored in status.conditionalUpdateRisks from both the update graph and preflight checks executed by the target release's CVO. 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. The mode and force fields are mutually exclusive - mode cannot be set when force is true.", } func (Update) SwaggerDoc() map[string]string { diff --git a/features.md b/features.md index afa64782571..c265ffde169 100644 --- a/features.md +++ b/features.md @@ -9,6 +9,7 @@ | ClusterAPIComputeInstall| | | Enabled | Enabled | | | | | | ClusterAPIControlPlaneInstall| | | Enabled | Enabled | | | | | | ClusterAPIMachineManagementVSphere| | | Enabled | Enabled | | | | | +| ClusterUpdatePreflight| | | | | | | Enabled | Enabled | | Example2| | | Enabled | Enabled | | | | | | ExternalSnapshotMetadata| | | Enabled | Enabled | | | | | | IngressControllerDynamicConfigurationManager| | | Enabled | Enabled | | | | | diff --git a/features/features.go b/features/features.go index 187edb0e164..0861199882f 100644 --- a/features/features.go +++ b/features/features.go @@ -699,6 +699,14 @@ var ( enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() + FeatureGateClusterUpdatePreflight = newFeatureGate("ClusterUpdatePreflight"). + reportProblemsToJiraComponent("Cluster Version Operator"). + contactPerson("fao89"). + productScope(ocpSpecific). + enhancementPR("https://github.com/openshift/enhancements/pull/1930"). + enableIn(configv1.TechPreviewNoUpgrade). + mustRegister() + FeatureGateGCPCustomAPIEndpoints = newFeatureGate("GCPCustomAPIEndpoints"). reportProblemsToJiraComponent("Installer"). contactPerson("barbacbd"). diff --git a/openapi/generated_openapi/zz_generated.openapi.go b/openapi/generated_openapi/zz_generated.openapi.go index 83a9e5b0375..f431a8fc07c 100644 --- a/openapi/generated_openapi/zz_generated.openapi.go +++ b/openapi/generated_openapi/zz_generated.openapi.go @@ -21481,6 +21481,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. The target release's CVO will execute pre-checks and report any detected risks in status.conditionalUpdateRisks, alongside risks from the update recommendation service. status.conditionalUpdates contains references/entries that point to the detailed risk objects stored in status.conditionalUpdateRisks from both the update graph and preflight checks executed by the target release's CVO. 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. The mode and force fields are mutually exclusive - mode cannot be set when force is true.\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 ba45ba36dee..08f552671a1 100644 --- a/openapi/openapi.json +++ b/openapi/openapi.json @@ -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. The target release's CVO will execute pre-checks and report any detected risks in status.conditionalUpdateRisks, alongside risks from the update recommendation service. status.conditionalUpdates contains references/entries that point to the detailed risk objects stored in status.conditionalUpdateRisks from both the update graph and preflight checks executed by the target release's CVO. 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. The mode and force fields are mutually exclusive - mode cannot be set when force is true.\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", diff --git a/payload-manifests/featuregates/featureGate-Hypershift-Default.yaml b/payload-manifests/featuregates/featureGate-Hypershift-Default.yaml index 326d875acd8..cfc852b2c1a 100644 --- a/payload-manifests/featuregates/featureGate-Hypershift-Default.yaml +++ b/payload-manifests/featuregates/featureGate-Hypershift-Default.yaml @@ -84,6 +84,9 @@ { "name": "ClusterUpdateAcceptRisks" }, + { + "name": "ClusterUpdatePreflight" + }, { "name": "ClusterVersionOperatorConfiguration" }, diff --git a/payload-manifests/featuregates/featureGate-Hypershift-DevPreviewNoUpgrade.yaml b/payload-manifests/featuregates/featureGate-Hypershift-DevPreviewNoUpgrade.yaml index 1897be7b3c5..f7ade7a8d43 100644 --- a/payload-manifests/featuregates/featureGate-Hypershift-DevPreviewNoUpgrade.yaml +++ b/payload-manifests/featuregates/featureGate-Hypershift-DevPreviewNoUpgrade.yaml @@ -20,6 +20,9 @@ { "name": "ClusterAPIInstall" }, + { + "name": "ClusterUpdatePreflight" + }, { "name": "EventedPLEG" }, diff --git a/payload-manifests/featuregates/featureGate-Hypershift-OKD.yaml b/payload-manifests/featuregates/featureGate-Hypershift-OKD.yaml index 91f2cd1e720..62b28136dd8 100644 --- a/payload-manifests/featuregates/featureGate-Hypershift-OKD.yaml +++ b/payload-manifests/featuregates/featureGate-Hypershift-OKD.yaml @@ -86,6 +86,9 @@ { "name": "ClusterUpdateAcceptRisks" }, + { + "name": "ClusterUpdatePreflight" + }, { "name": "ClusterVersionOperatorConfiguration" }, diff --git a/payload-manifests/featuregates/featureGate-Hypershift-TechPreviewNoUpgrade.yaml b/payload-manifests/featuregates/featureGate-Hypershift-TechPreviewNoUpgrade.yaml index 5853607c02b..c6c5d5dda02 100644 --- a/payload-manifests/featuregates/featureGate-Hypershift-TechPreviewNoUpgrade.yaml +++ b/payload-manifests/featuregates/featureGate-Hypershift-TechPreviewNoUpgrade.yaml @@ -154,6 +154,9 @@ { "name": "ClusterUpdateAcceptRisks" }, + { + "name": "ClusterUpdatePreflight" + }, { "name": "ClusterVersionOperatorConfiguration" }, diff --git a/payload-manifests/featuregates/featureGate-SelfManagedHA-Default.yaml b/payload-manifests/featuregates/featureGate-SelfManagedHA-Default.yaml index 43c5affe7e2..a41ad731444 100644 --- a/payload-manifests/featuregates/featureGate-SelfManagedHA-Default.yaml +++ b/payload-manifests/featuregates/featureGate-SelfManagedHA-Default.yaml @@ -84,6 +84,9 @@ { "name": "ClusterUpdateAcceptRisks" }, + { + "name": "ClusterUpdatePreflight" + }, { "name": "ClusterVersionOperatorConfiguration" }, diff --git a/payload-manifests/featuregates/featureGate-SelfManagedHA-DevPreviewNoUpgrade.yaml b/payload-manifests/featuregates/featureGate-SelfManagedHA-DevPreviewNoUpgrade.yaml index e9d704c6a35..d640e3d8289 100644 --- a/payload-manifests/featuregates/featureGate-SelfManagedHA-DevPreviewNoUpgrade.yaml +++ b/payload-manifests/featuregates/featureGate-SelfManagedHA-DevPreviewNoUpgrade.yaml @@ -20,6 +20,9 @@ { "name": "ClusterAPIInstall" }, + { + "name": "ClusterUpdatePreflight" + }, { "name": "EventedPLEG" }, diff --git a/payload-manifests/featuregates/featureGate-SelfManagedHA-OKD.yaml b/payload-manifests/featuregates/featureGate-SelfManagedHA-OKD.yaml index 9c72a8df94f..18c37518793 100644 --- a/payload-manifests/featuregates/featureGate-SelfManagedHA-OKD.yaml +++ b/payload-manifests/featuregates/featureGate-SelfManagedHA-OKD.yaml @@ -86,6 +86,9 @@ { "name": "ClusterUpdateAcceptRisks" }, + { + "name": "ClusterUpdatePreflight" + }, { "name": "ClusterVersionOperatorConfiguration" }, diff --git a/payload-manifests/featuregates/featureGate-SelfManagedHA-TechPreviewNoUpgrade.yaml b/payload-manifests/featuregates/featureGate-SelfManagedHA-TechPreviewNoUpgrade.yaml index f3a7e2c225a..c6e080ed7f7 100644 --- a/payload-manifests/featuregates/featureGate-SelfManagedHA-TechPreviewNoUpgrade.yaml +++ b/payload-manifests/featuregates/featureGate-SelfManagedHA-TechPreviewNoUpgrade.yaml @@ -136,6 +136,9 @@ { "name": "ClusterUpdateAcceptRisks" }, + { + "name": "ClusterUpdatePreflight" + }, { "name": "ClusterVersionOperatorConfiguration" },