From de957683c4a6ae8a428efc8e4d20bd1a827ca28e Mon Sep 17 00:00:00 2001 From: David Date: Fri, 15 Aug 2025 12:06:36 -0400 Subject: [PATCH 1/3] machine_config: add BootImageSkewEnforcement API --- .../generated_openapi/zz_generated.openapi.go | 140 +- openapi/openapi.json | 82 ++ .../BootImageSkewEnforcement.yaml | 239 ++++ operator/v1/types_machineconfiguration.go | 142 +- ...ineconfigurations-CustomNoUpgrade.crd.yaml | 184 +++ ...onfigurations-DevPreviewNoUpgrade.crd.yaml | 184 +++ operator/v1/zz_generated.deepcopy.go | 53 + ..._generated.featuregated-crd-manifests.yaml | 1 + .../BootImageSkewEnforcement.yaml | 1180 +++++++++++++++++ .../v1/zz_generated.swagger_doc_generated.go | 41 +- ...ineconfigurations-CustomNoUpgrade.crd.yaml | 184 +++ ...onfigurations-DevPreviewNoUpgrade.crd.yaml | 184 +++ 12 files changed, 2606 insertions(+), 8 deletions(-) create mode 100644 operator/v1/tests/machineconfigurations.operator.openshift.io/BootImageSkewEnforcement.yaml create mode 100644 operator/v1/zz_generated.featuregated-crd-manifests/machineconfigurations.operator.openshift.io/BootImageSkewEnforcement.yaml diff --git a/openapi/generated_openapi/zz_generated.openapi.go b/openapi/generated_openapi/zz_generated.openapi.go index ca03cb5450f..1938bcdf604 100644 --- a/openapi/generated_openapi/zz_generated.openapi.go +++ b/openapi/generated_openapi/zz_generated.openapi.go @@ -922,6 +922,8 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/openshift/api/operator/v1.AuthenticationStatus": schema_openshift_api_operator_v1_AuthenticationStatus(ref), "github.com/openshift/api/operator/v1.AzureCSIDriverConfigSpec": schema_openshift_api_operator_v1_AzureCSIDriverConfigSpec(ref), "github.com/openshift/api/operator/v1.AzureDiskEncryptionSet": schema_openshift_api_operator_v1_AzureDiskEncryptionSet(ref), + "github.com/openshift/api/operator/v1.BootImageSkewEnforcementConfig": schema_openshift_api_operator_v1_BootImageSkewEnforcementConfig(ref), + "github.com/openshift/api/operator/v1.BootImageSkewEnforcementStatus": schema_openshift_api_operator_v1_BootImageSkewEnforcementStatus(ref), "github.com/openshift/api/operator/v1.CSIDriverConfigSpec": schema_openshift_api_operator_v1_CSIDriverConfigSpec(ref), "github.com/openshift/api/operator/v1.CSISnapshotController": schema_openshift_api_operator_v1_CSISnapshotController(ref), "github.com/openshift/api/operator/v1.CSISnapshotControllerList": schema_openshift_api_operator_v1_CSISnapshotControllerList(ref), @@ -934,6 +936,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/openshift/api/operator/v1.CloudCredentialList": schema_openshift_api_operator_v1_CloudCredentialList(ref), "github.com/openshift/api/operator/v1.CloudCredentialSpec": schema_openshift_api_operator_v1_CloudCredentialSpec(ref), "github.com/openshift/api/operator/v1.CloudCredentialStatus": schema_openshift_api_operator_v1_CloudCredentialStatus(ref), + "github.com/openshift/api/operator/v1.ClusterBootImage": schema_openshift_api_operator_v1_ClusterBootImage(ref), "github.com/openshift/api/operator/v1.ClusterCSIDriver": schema_openshift_api_operator_v1_ClusterCSIDriver(ref), "github.com/openshift/api/operator/v1.ClusterCSIDriverList": schema_openshift_api_operator_v1_ClusterCSIDriverList(ref), "github.com/openshift/api/operator/v1.ClusterCSIDriverSpec": schema_openshift_api_operator_v1_ClusterCSIDriverSpec(ref), @@ -46927,6 +46930,98 @@ func schema_openshift_api_operator_v1_AzureDiskEncryptionSet(ref common.Referenc } } +func schema_openshift_api_operator_v1_BootImageSkewEnforcementConfig(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "BootImageSkewEnforcementConfig is used to configure how boot image version skew is enforced on the cluster.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "mode": { + SchemaProps: spec.SchemaProps{ + Description: "mode determines the underlying behavior of skew enforcement mechanism. Valid values are Manual and None. Manual means that the cluster admin is expected to perform manual boot image updates and store the OCP & RHCOS version associated with the last boot image update in the manual field. In Manual mode, the MCO will prevent upgrades when the boot image skew exceeds the skew limit described by the release image. None means that the MCO will no longer monitor the boot image skew. This may affect the cluster's ability to scale. This field is required.", + Type: []string{"string"}, + Format: "", + }, + }, + "manual": { + SchemaProps: spec.SchemaProps{ + Description: "manual describes the current boot image of the cluster. This should be set to the oldest boot image used amongst all machine resources in the cluster. This includes the RHCOS version of the boot image and the OCP release version which shipped with that RHCOS boot image. If ocpVersion and rhcosVersion are defined, both values will be used for checking skew compliance. If only ocpVersion is defined, only that value will be used for checking skew compliance. If only rhcosVersion is defined, only that value will be used for checking skew compliance. Required when mode is set to \"Manual\" and forbidden otherwise.", + Default: map[string]interface{}{}, + Ref: ref("github.com/openshift/api/operator/v1.ClusterBootImage"), + }, + }, + }, + Required: []string{"mode"}, + }, + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-unions": []interface{}{ + map[string]interface{}{ + "discriminator": "mode", + "fields-to-discriminateBy": map[string]interface{}{ + "manual": "Manual", + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/openshift/api/operator/v1.ClusterBootImage"}, + } +} + +func schema_openshift_api_operator_v1_BootImageSkewEnforcementStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "BootImageSkewEnforcementStatus is the type for the status object. It represents the cluster defaults when the boot image skew enforcement configuration is undefined and reflects the actual configuration when it is defined.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "mode": { + SchemaProps: spec.SchemaProps{ + Description: "mode determines the underlying behavior of skew enforcement mechanism. Valid values are Automatic, Manual and None. Automatic means that the MCO will perform boot image updates and store the OCP & RHCOS version associated with the last boot image update in the automatic field. Manual means that the cluster admin is expected to perform manual boot image updates and store the OCP & RHCOS version associated with the last boot image update in the manual field. In Automatic and Manual mode, the MCO will prevent upgrades when the boot image skew exceeds the skew limit described by the release image. None means that the MCO will no longer monitor the boot image skew. This may affect the cluster's ability to scale. This field is required.", + Type: []string{"string"}, + Format: "", + }, + }, + "automatic": { + SchemaProps: spec.SchemaProps{ + Description: "automatic describes the current boot image of the cluster. This will be populated by the MCO when performing boot image updates. This value will be compared against the cluster's skew limit to determine skew compliance. Required when mode is set to \"Automatic\" and forbidden otherwise.", + Default: map[string]interface{}{}, + Ref: ref("github.com/openshift/api/operator/v1.ClusterBootImage"), + }, + }, + "manual": { + SchemaProps: spec.SchemaProps{ + Description: "manual describes the current boot image of the cluster. This will be populated by the MCO using the values provided in the spec.bootImageSkewEnforcement.manual field. This value will be compared against the cluster's skew limit to determine skew compliance. Required when mode is set to \"Manual\" and forbidden otherwise.", + Default: map[string]interface{}{}, + Ref: ref("github.com/openshift/api/operator/v1.ClusterBootImage"), + }, + }, + }, + Required: []string{"mode"}, + }, + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-unions": []interface{}{ + map[string]interface{}{ + "discriminator": "mode", + "fields-to-discriminateBy": map[string]interface{}{ + "automatic": "Automatic", + "manual": "Manual", + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/openshift/api/operator/v1.ClusterBootImage"}, + } +} + func schema_openshift_api_operator_v1_CSIDriverConfigSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -47600,6 +47695,33 @@ func schema_openshift_api_operator_v1_CloudCredentialStatus(ref common.Reference } } +func schema_openshift_api_operator_v1_ClusterBootImage(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ClusterBootImage describes the boot image of a cluster. It stores the RHCOS version of the boot image and the OCP release version which shipped with that RHCOS boot image. At least one of these values are required. If ocpVersion and rhcosVersion are defined, both values will be used for checking skew compliance. If only ocpVersion is defined, only that value will be used for checking skew compliance. If only rhcosVersion is defined, only that value will be used for checking skew compliance.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "ocpVersion": { + SchemaProps: spec.SchemaProps{ + Description: "ocpVersion provides a string which represents the OCP version of the boot image. This field must match the OCP semver compatible format of x.y.z. This field must be between 5 and 10 characters long.", + Type: []string{"string"}, + Format: "", + }, + }, + "rhcosVersion": { + SchemaProps: spec.SchemaProps{ + Description: "rhcosVersion provides a string which represents the RHCOS version of the boot image This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between 14 and 21 characters long.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + func schema_openshift_api_operator_v1_ClusterCSIDriver(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -53274,12 +53396,19 @@ func schema_openshift_api_operator_v1_MachineConfigurationSpec(ref common.Refere Ref: ref("github.com/openshift/api/operator/v1.IrreconcilableValidationOverrides"), }, }, + "bootImageSkewEnforcement": { + SchemaProps: spec.SchemaProps{ + Description: "bootImageSkewEnforcement allows an admin to configure how boot image version skew is enforced on the cluster. When omitted, this will default to Automatic for clusters that support automatic boot image updates. For clusters that do not support automatic boot image updates, cluster upgrades will be disabled until a skew enforcement mode has been specified. When version skew is being enforced, cluster upgrades will be disabled until the version skew is deemed acceptable for the current release payload.", + Default: map[string]interface{}{}, + Ref: ref("github.com/openshift/api/operator/v1.BootImageSkewEnforcementConfig"), + }, + }, }, Required: []string{"managementState", "forceRedeploymentReason"}, }, }, Dependencies: []string{ - "github.com/openshift/api/operator/v1.IrreconcilableValidationOverrides", "github.com/openshift/api/operator/v1.ManagedBootImages", "github.com/openshift/api/operator/v1.NodeDisruptionPolicyConfig", "k8s.io/apimachinery/pkg/runtime.RawExtension"}, + "github.com/openshift/api/operator/v1.BootImageSkewEnforcementConfig", "github.com/openshift/api/operator/v1.IrreconcilableValidationOverrides", "github.com/openshift/api/operator/v1.ManagedBootImages", "github.com/openshift/api/operator/v1.NodeDisruptionPolicyConfig", "k8s.io/apimachinery/pkg/runtime.RawExtension"}, } } @@ -53332,11 +53461,18 @@ func schema_openshift_api_operator_v1_MachineConfigurationStatus(ref common.Refe Ref: ref("github.com/openshift/api/operator/v1.ManagedBootImages"), }, }, + "bootImageSkewEnforcementStatus": { + SchemaProps: spec.SchemaProps{ + Description: "bootImageSkewEnforcementStatus reflects what the latest cluster-validated boot image skew enforcement configuration is and will be used by Machine Config Controller while performing boot image skew enforcement. When omitted, the MCO has no knowledge of how to enforce boot image skew. When the MCO does not know how boot image skew should be enforced, cluster upgrades will be blocked until it can either automatically determine skew enforcement or there is an explicit skew enforcement configuration provided in the spec.bootImageSkewEnforcement field.", + Default: map[string]interface{}{}, + Ref: ref("github.com/openshift/api/operator/v1.BootImageSkewEnforcementStatus"), + }, + }, }, }, }, Dependencies: []string{ - "github.com/openshift/api/operator/v1.ManagedBootImages", "github.com/openshift/api/operator/v1.NodeDisruptionPolicyStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition"}, + "github.com/openshift/api/operator/v1.BootImageSkewEnforcementStatus", "github.com/openshift/api/operator/v1.ManagedBootImages", "github.com/openshift/api/operator/v1.NodeDisruptionPolicyStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition"}, } } diff --git a/openapi/openapi.json b/openapi/openapi.json index 42ee6c97da5..10429079ade 100644 --- a/openapi/openapi.json +++ b/openapi/openapi.json @@ -27198,6 +27198,64 @@ } } }, + "com.github.openshift.api.operator.v1.BootImageSkewEnforcementConfig": { + "description": "BootImageSkewEnforcementConfig is used to configure how boot image version skew is enforced on the cluster.", + "type": "object", + "required": [ + "mode" + ], + "properties": { + "manual": { + "description": "manual describes the current boot image of the cluster. This should be set to the oldest boot image used amongst all machine resources in the cluster. This includes the RHCOS version of the boot image and the OCP release version which shipped with that RHCOS boot image. If ocpVersion and rhcosVersion are defined, both values will be used for checking skew compliance. If only ocpVersion is defined, only that value will be used for checking skew compliance. If only rhcosVersion is defined, only that value will be used for checking skew compliance. Required when mode is set to \"Manual\" and forbidden otherwise.", + "default": {}, + "$ref": "#/definitions/com.github.openshift.api.operator.v1.ClusterBootImage" + }, + "mode": { + "description": "mode determines the underlying behavior of skew enforcement mechanism. Valid values are Manual and None. Manual means that the cluster admin is expected to perform manual boot image updates and store the OCP & RHCOS version associated with the last boot image update in the manual field. In Manual mode, the MCO will prevent upgrades when the boot image skew exceeds the skew limit described by the release image. None means that the MCO will no longer monitor the boot image skew. This may affect the cluster's ability to scale. This field is required.", + "type": "string" + } + }, + "x-kubernetes-unions": [ + { + "discriminator": "mode", + "fields-to-discriminateBy": { + "manual": "Manual" + } + } + ] + }, + "com.github.openshift.api.operator.v1.BootImageSkewEnforcementStatus": { + "description": "BootImageSkewEnforcementStatus is the type for the status object. It represents the cluster defaults when the boot image skew enforcement configuration is undefined and reflects the actual configuration when it is defined.", + "type": "object", + "required": [ + "mode" + ], + "properties": { + "automatic": { + "description": "automatic describes the current boot image of the cluster. This will be populated by the MCO when performing boot image updates. This value will be compared against the cluster's skew limit to determine skew compliance. Required when mode is set to \"Automatic\" and forbidden otherwise.", + "default": {}, + "$ref": "#/definitions/com.github.openshift.api.operator.v1.ClusterBootImage" + }, + "manual": { + "description": "manual describes the current boot image of the cluster. This will be populated by the MCO using the values provided in the spec.bootImageSkewEnforcement.manual field. This value will be compared against the cluster's skew limit to determine skew compliance. Required when mode is set to \"Manual\" and forbidden otherwise.", + "default": {}, + "$ref": "#/definitions/com.github.openshift.api.operator.v1.ClusterBootImage" + }, + "mode": { + "description": "mode determines the underlying behavior of skew enforcement mechanism. Valid values are Automatic, Manual and None. Automatic means that the MCO will perform boot image updates and store the OCP & RHCOS version associated with the last boot image update in the automatic field. Manual means that the cluster admin is expected to perform manual boot image updates and store the OCP & RHCOS version associated with the last boot image update in the manual field. In Automatic and Manual mode, the MCO will prevent upgrades when the boot image skew exceeds the skew limit described by the release image. None means that the MCO will no longer monitor the boot image skew. This may affect the cluster's ability to scale. This field is required.", + "type": "string" + } + }, + "x-kubernetes-unions": [ + { + "discriminator": "mode", + "fields-to-discriminateBy": { + "automatic": "Automatic", + "manual": "Manual" + } + } + ] + }, "com.github.openshift.api.operator.v1.CSIDriverConfigSpec": { "description": "CSIDriverConfigSpec defines configuration spec that can be used to optionally configure a specific CSI Driver.", "type": "object", @@ -27604,6 +27662,20 @@ } } }, + "com.github.openshift.api.operator.v1.ClusterBootImage": { + "description": "ClusterBootImage describes the boot image of a cluster. It stores the RHCOS version of the boot image and the OCP release version which shipped with that RHCOS boot image. At least one of these values are required. If ocpVersion and rhcosVersion are defined, both values will be used for checking skew compliance. If only ocpVersion is defined, only that value will be used for checking skew compliance. If only rhcosVersion is defined, only that value will be used for checking skew compliance.", + "type": "object", + "properties": { + "ocpVersion": { + "description": "ocpVersion provides a string which represents the OCP version of the boot image. This field must match the OCP semver compatible format of x.y.z. This field must be between 5 and 10 characters long.", + "type": "string" + }, + "rhcosVersion": { + "description": "rhcosVersion provides a string which represents the RHCOS version of the boot image This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between 14 and 21 characters long.", + "type": "string" + } + } + }, "com.github.openshift.api.operator.v1.ClusterCSIDriver": { "description": "ClusterCSIDriver object allows management and configuration of a CSI driver operator installed by default in OpenShift. Name of the object must be name of the CSI driver it operates. See CSIDriverName type for list of allowed values.\n\nCompatibility level 1: Stable within a major release for a minimum of 12 months or 3 minor releases (whichever is longer).", "type": "object", @@ -30929,6 +31001,11 @@ "forceRedeploymentReason" ], "properties": { + "bootImageSkewEnforcement": { + "description": "bootImageSkewEnforcement allows an admin to configure how boot image version skew is enforced on the cluster. When omitted, this will default to Automatic for clusters that support automatic boot image updates. For clusters that do not support automatic boot image updates, cluster upgrades will be disabled until a skew enforcement mode has been specified. When version skew is being enforced, cluster upgrades will be disabled until the version skew is deemed acceptable for the current release payload.", + "default": {}, + "$ref": "#/definitions/com.github.openshift.api.operator.v1.BootImageSkewEnforcementConfig" + }, "failedRevisionLimit": { "description": "failedRevisionLimit is the number of failed static pod installer revisions to keep on disk and in the api -1 = unlimited, 0 or unset = 5 (default)", "type": "integer", @@ -30985,6 +31062,11 @@ "com.github.openshift.api.operator.v1.MachineConfigurationStatus": { "type": "object", "properties": { + "bootImageSkewEnforcementStatus": { + "description": "bootImageSkewEnforcementStatus reflects what the latest cluster-validated boot image skew enforcement configuration is and will be used by Machine Config Controller while performing boot image skew enforcement. When omitted, the MCO has no knowledge of how to enforce boot image skew. When the MCO does not know how boot image skew should be enforced, cluster upgrades will be blocked until it can either automatically determine skew enforcement or there is an explicit skew enforcement configuration provided in the spec.bootImageSkewEnforcement field.", + "default": {}, + "$ref": "#/definitions/com.github.openshift.api.operator.v1.BootImageSkewEnforcementStatus" + }, "conditions": { "description": "conditions is a list of conditions and their status", "type": "array", diff --git a/operator/v1/tests/machineconfigurations.operator.openshift.io/BootImageSkewEnforcement.yaml b/operator/v1/tests/machineconfigurations.operator.openshift.io/BootImageSkewEnforcement.yaml new file mode 100644 index 00000000000..b47641a93b3 --- /dev/null +++ b/operator/v1/tests/machineconfigurations.operator.openshift.io/BootImageSkewEnforcement.yaml @@ -0,0 +1,239 @@ +apiVersion: apiextensions.k8s.io/v1 # Hack because controller-gen complains if we don't have this +name: "MachineConfiguration" +crdName: machineconfigurations.operator.openshift.io +featureGates: +- BootImageSkewEnforcement +tests: + onCreate: + - name: Should be able to create a minimal MachineConfiguration + initial: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: {} # No spec is required for a MachineConfiguration + expected: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: + logLevel: Normal + operatorLogLevel: Normal + - name: Should be able to create a manual BootImageSkewEnforcement configuration knob + initial: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: + bootImageSkewEnforcement: + mode: Manual + manual: + ocpVersion: "4.18.2" + rhcosVersion: "9.6.20250523-1" + expected: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: + logLevel: Normal + operatorLogLevel: Normal + bootImageSkewEnforcement: + mode: Manual + manual: + ocpVersion: "4.18.2" + rhcosVersion: "9.6.20250523-1" + - name: Should not be able to create an automatic BootImageSkewEnforcement configuration knob + initial: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: + bootImageSkewEnforcement: + mode: Automatic + expectedError: "Unsupported value: \"Automatic\": supported values: \"Manual\", \"None\"" + - name: Should be able to create a manual BootImageSkewEnforcement configuration knob with a legacy cluster boot image + initial: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: + bootImageSkewEnforcement: + mode: Manual + manual: + ocpVersion: "4.18.2" + rhcosVersion: "416.94.202411201433-0" + expected: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: + logLevel: Normal + operatorLogLevel: Normal + bootImageSkewEnforcement: + mode: Manual + manual: + ocpVersion: "4.18.2" + rhcosVersion: "416.94.202411201433-0" + - name: Should be able to create a manual BootImageSkewEnforcement configuration knob with only ocpVersion defined + initial: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: + bootImageSkewEnforcement: + mode: Manual + manual: + ocpVersion: "4.18.2" + expected: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: + logLevel: Normal + operatorLogLevel: Normal + bootImageSkewEnforcement: + mode: Manual + manual: + ocpVersion: "4.18.2" + - name: Should be able to create a manual BootImageSkewEnforcement configuration knob with only rhcosVersion defined + initial: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: + bootImageSkewEnforcement: + mode: Manual + manual: + rhcosVersion: "416.94.202411201433-0" + expected: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: + logLevel: Normal + operatorLogLevel: Normal + bootImageSkewEnforcement: + mode: Manual + manual: + rhcosVersion: "416.94.202411201433-0" + - name: Should be able to create a None BootImageSkewEnforcement configuration knob + initial: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: + bootImageSkewEnforcement: + mode: None + expected: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: + logLevel: Normal + operatorLogLevel: Normal + bootImageSkewEnforcement: + mode: None + - name: Should not be able to add manual field if bootImageSkewEnforcement.mode is set to None + initial: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: + bootImageSkewEnforcement: + mode: None + manual: + ocpVersion: "4.18.2" + rhcosVersion: "9.6.20250523-1" + expectedError: "manual is required when mode is Manual, and forbidden otherwise" + - name: manual field should be set if bootImageSkewEnforcement.mode is set to Manual + initial: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: + bootImageSkewEnforcement: + mode: Manual + expectedError: "manual is required when mode is Manual, and forbidden otherwise" + onUpdate: + - name: Should not be able to add manual field in status if bootImageSkewEnforcementStatus.mode is set to None + initial: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: {} + status: + bootImageSkewEnforcementStatus: + mode: None + updated: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: {} + status: + bootImageSkewEnforcementStatus: + mode: None + manual: + ocpVersion: "4.18.2" + rhcosVersion: "9.6.20250523-1" + expectedStatusError: "manual is required when mode is Manual, and forbidden otherwise" + - name: Should not able to add automatic field in status if bootImageSkewEnforcementStatus.mode is set to None + initial: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: {} + status: + bootImageSkewEnforcementStatus: + mode: None + updated: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: {} + status: + bootImageSkewEnforcementStatus: + mode: None + automatic: + ocpVersion: "4.18.2" + rhcosVersion: "9.6.20250523-1" + expectedStatusError: "automatic is required when mode is Automatic, and forbidden otherwise" + - name: Should be able to add manual field in status if bootImageSkewEnforcementStatus.mode is set to manual + initial: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: {} + status: + bootImageSkewEnforcementStatus: + mode: None + updated: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: {} + status: + bootImageSkewEnforcementStatus: + mode: Manual + manual: + ocpVersion: "4.18.2" + rhcosVersion: "9.6.20250523-1" + expected: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: + logLevel: Normal + operatorLogLevel: Normal + status: + bootImageSkewEnforcementStatus: + mode: Manual + manual: + ocpVersion: "4.18.2" + rhcosVersion: "9.6.20250523-1" + - name: Should be able to add automatic field in status if bootImageSkewEnforcementStatus.mode is set to automatic + initial: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: {} + status: + bootImageSkewEnforcementStatus: + mode: None + updated: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: {} + status: + bootImageSkewEnforcementStatus: + mode: Automatic + automatic: + ocpVersion: "4.18.2" + rhcosVersion: "416.94.202411201433-0" + expected: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: + logLevel: Normal + operatorLogLevel: Normal + status: + bootImageSkewEnforcementStatus: + mode: Automatic + automatic: + ocpVersion: "4.18.2" + rhcosVersion: "416.94.202411201433-0" diff --git a/operator/v1/types_machineconfiguration.go b/operator/v1/types_machineconfiguration.go index 8f779db2a6e..7dd9727375d 100644 --- a/operator/v1/types_machineconfiguration.go +++ b/operator/v1/types_machineconfiguration.go @@ -36,8 +36,6 @@ type MachineConfiguration struct { type MachineConfigurationSpec struct { StaticPodOperatorSpec `json:",inline"` - // TODO(jkyros): This is where we put our knobs and dials - // managedBootImages allows configuration for the management of boot images for machine // resources within the cluster. This configuration allows users to select resources that should // be updated to the latest boot images during cluster upgrades, ensuring that new machines @@ -65,8 +63,138 @@ type MachineConfigurationSpec struct { // +openshift:enable:FeatureGate=IrreconcilableMachineConfig // +optional IrreconcilableValidationOverrides IrreconcilableValidationOverrides `json:"irreconcilableValidationOverrides,omitempty,omitzero"` + + // bootImageSkewEnforcement allows an admin to configure how boot image version skew is + // enforced on the cluster. + // When omitted, this will default to Automatic for clusters that support automatic boot image updates. + // For clusters that do not support automatic boot image updates, cluster upgrades will be disabled until + // a skew enforcement mode has been specified. + // When version skew is being enforced, cluster upgrades will be disabled until the version skew is deemed + // acceptable for the current release payload. + // +openshift:enable:FeatureGate=BootImageSkewEnforcement + // +optional + BootImageSkewEnforcement BootImageSkewEnforcementConfig `json:"bootImageSkewEnforcement,omitempty,omitzero"` +} + +// BootImageSkewEnforcementConfig is used to configure how boot image version skew is enforced on the cluster. +// +kubebuilder:validation:XValidation:rule="has(self.mode) && (self.mode =='Manual') ? has(self.manual) : !has(self.manual)",message="manual is required when mode is Manual, and forbidden otherwise" +// +union +type BootImageSkewEnforcementConfig struct { + // mode determines the underlying behavior of skew enforcement mechanism. + // Valid values are Manual and None. + // Manual means that the cluster admin is expected to perform manual boot image updates and store the OCP + // & RHCOS version associated with the last boot image update in the manual field. + // In Manual mode, the MCO will prevent upgrades when the boot image skew exceeds the + // skew limit described by the release image. + // None means that the MCO will no longer monitor the boot image skew. This may affect + // the cluster's ability to scale. + // This field is required. + // +unionDiscriminator + // +required + Mode BootImageSkewEnforcementConfigMode `json:"mode,omitempty"` + + // manual describes the current boot image of the cluster. + // This should be set to the oldest boot image used amongst all machine resources in the cluster. + // This includes the RHCOS version of the boot image and the OCP release version which shipped with that RHCOS boot image. + // If ocpVersion and rhcosVersion are defined, both values will be used for checking skew compliance. + // If only ocpVersion is defined, only that value will be used for checking skew compliance. + // If only rhcosVersion is defined, only that value will be used for checking skew compliance. + // Required when mode is set to "Manual" and forbidden otherwise. + // +optional + Manual ClusterBootImage `json:"manual,omitempty,omitzero"` +} + +// BootImageSkewEnforcementStatus is the type for the status object. It represents the cluster defaults when +// the boot image skew enforcement configuration is undefined and reflects the actual configuration when it is defined. +// +kubebuilder:validation:XValidation:rule="has(self.mode) && (self.mode == 'Automatic') ? has(self.automatic) : !has(self.automatic)",message="automatic is required when mode is Automatic, and forbidden otherwise" +// +kubebuilder:validation:XValidation:rule="has(self.mode) && (self.mode == 'Manual') ? has(self.manual) : !has(self.manual)",message="manual is required when mode is Manual, and forbidden otherwise" +// +union +type BootImageSkewEnforcementStatus struct { + // mode determines the underlying behavior of skew enforcement mechanism. + // Valid values are Automatic, Manual and None. + // Automatic means that the MCO will perform boot image updates and store the + // OCP & RHCOS version associated with the last boot image update in the automatic field. + // Manual means that the cluster admin is expected to perform manual boot image updates and store the OCP + // & RHCOS version associated with the last boot image update in the manual field. + // In Automatic and Manual mode, the MCO will prevent upgrades when the boot image skew exceeds the + // skew limit described by the release image. + // None means that the MCO will no longer monitor the boot image skew. This may affect + // the cluster's ability to scale. + // This field is required. + // +unionDiscriminator + // +required + Mode BootImageSkewEnforcementModeStatus `json:"mode,omitempty"` + + // automatic describes the current boot image of the cluster. + // This will be populated by the MCO when performing boot image updates. This value will be compared against + // the cluster's skew limit to determine skew compliance. + // Required when mode is set to "Automatic" and forbidden otherwise. + // +optional + Automatic ClusterBootImage `json:"automatic,omitempty,omitzero"` + + // manual describes the current boot image of the cluster. + // This will be populated by the MCO using the values provided in the spec.bootImageSkewEnforcement.manual field. + // This value will be compared against the cluster's skew limit to determine skew compliance. + // Required when mode is set to "Manual" and forbidden otherwise. + // +optional + Manual ClusterBootImage `json:"manual,omitempty,omitzero"` } +// ClusterBootImage describes the boot image of a cluster. It stores the RHCOS version of the boot image and +// the OCP release version which shipped with that RHCOS boot image. At least one of these values are required. +// If ocpVersion and rhcosVersion are defined, both values will be used for checking skew compliance. +// If only ocpVersion is defined, only that value will be used for checking skew compliance. +// If only rhcosVersion is defined, only that value will be used for checking skew compliance. +// +kubebuilder:validation:XValidation:rule="has(self.ocpVersion) || has(self.rhcosVersion)",message="at least one of ocpVersion or rhcosVersion is required" +// +kubebuilder:validation:MinProperties=1 +type ClusterBootImage struct { + // ocpVersion provides a string which represents the OCP version of the boot image. + // This field must match the OCP semver compatible format of x.y.z. This field must be between + // 5 and 10 characters long. + // +kubebuilder:validation:XValidation:rule="self.matches('^[0-9]+\\\\.[0-9]+\\\\.[0-9]+$')",message="bootImageOCPVersion must match the OCP semver compatible format of x.y.z" + // +kubebuilder:validation:MaxLength:=10 + // +kubebuilder:validation:MinLength:=5 + // +optional + OCPVersion string `json:"ocpVersion,omitempty"` + + // rhcosVersion provides a string which represents the RHCOS version of the boot image + // This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy + // format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between + // 14 and 21 characters long. + // +kubebuilder:validation:XValidation:rule="self.matches('^[0-9]+\\\\.[0-9]+\\\\.([0-9]{8}|[0-9]{12})-[0-9]+$')",message="rhcosVersion must match format [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or must match legacy format [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]" + // +kubebuilder:validation:MaxLength:=21 + // +kubebuilder:validation:MinLength:=14 + // +optional + RHCOSVersion string `json:"rhcosVersion,omitempty"` +} + +// BootImageSkewEnforcementConfigMode is a string enum used to configure the cluster's boot image skew enforcement mode. +// +kubebuilder:validation:Enum:="Manual";"None" +type BootImageSkewEnforcementConfigMode string + +const ( + // Manual represents a configuration mode that allows manual skew enforcement. + BootImageSkewEnforcementConfigModeManual BootImageSkewEnforcementConfigMode = "Manual" + + // None represents a configuration mode that disables boot image skew enforcement. + BootImageSkewEnforcementConfigModeNone BootImageSkewEnforcementConfigMode = "None" +) + +// BootImageSkewEnforcementModeStatus is a string enum used to indicate the cluster's boot image skew enforcement mode. +// +kubebuilder:validation:Enum:="Automatic";"Manual";"None" +type BootImageSkewEnforcementModeStatus string + +const ( + // Automatic represents a configuration mode that allows automatic skew enforcement. + BootImageSkewEnforcementModeStatusAutomatic BootImageSkewEnforcementModeStatus = "Automatic" + + // Manual represents a configuration mode that allows manual skew enforcement. + BootImageSkewEnforcementModeStatusManual BootImageSkewEnforcementModeStatus = "Manual" + + // None represents a configuration mode that disables boot image skew enforcement. + BootImageSkewEnforcementModeStatusNone BootImageSkewEnforcementModeStatus = "None" +) + type MachineConfigurationStatus struct { // observedGeneration is the last generation change you've dealt with // +optional @@ -111,6 +239,16 @@ type MachineConfigurationStatus struct { // +openshift:enable:FeatureGate=ManagedBootImages // +optional ManagedBootImagesStatus ManagedBootImages `json:"managedBootImagesStatus"` + + // bootImageSkewEnforcementStatus reflects what the latest cluster-validated boot image skew enforcement + // configuration is and will be used by Machine Config Controller while performing boot image skew enforcement. + // When omitted, the MCO has no knowledge of how to enforce boot image skew. When the MCO does not know how + // boot image skew should be enforced, cluster upgrades will be blocked until it can either automatically + // determine skew enforcement or there is an explicit skew enforcement configuration provided in the + // spec.bootImageSkewEnforcement field. + // +openshift:enable:FeatureGate=BootImageSkewEnforcement + // +optional + BootImageSkewEnforcementStatus BootImageSkewEnforcementStatus `json:"bootImageSkewEnforcementStatus,omitempty,omitzero"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/operator/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfigurations-CustomNoUpgrade.crd.yaml b/operator/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfigurations-CustomNoUpgrade.crd.yaml index da62cb7eec1..cb5697ddff8 100644 --- a/operator/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfigurations-CustomNoUpgrade.crd.yaml +++ b/operator/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfigurations-CustomNoUpgrade.crd.yaml @@ -46,6 +46,78 @@ spec: description: spec is the specification of the desired behavior of the Machine Config Operator properties: + bootImageSkewEnforcement: + description: |- + bootImageSkewEnforcement allows an admin to configure how boot image version skew is + enforced on the cluster. + When omitted, this will default to Automatic for clusters that support automatic boot image updates. + For clusters that do not support automatic boot image updates, cluster upgrades will be disabled until + a skew enforcement mode has been specified. + When version skew is being enforced, cluster upgrades will be disabled until the version skew is deemed + acceptable for the current release payload. + properties: + manual: + description: |- + manual describes the current boot image of the cluster. + This should be set to the oldest boot image used amongst all machine resources in the cluster. + This includes the RHCOS version of the boot image and the OCP release version which shipped with that RHCOS boot image. + If ocpVersion and rhcosVersion are defined, both values will be used for checking skew compliance. + If only ocpVersion is defined, only that value will be used for checking skew compliance. + If only rhcosVersion is defined, only that value will be used for checking skew compliance. + Required when mode is set to "Manual" and forbidden otherwise. + minProperties: 1 + properties: + ocpVersion: + description: |- + ocpVersion provides a string which represents the OCP version of the boot image. + This field must match the OCP semver compatible format of x.y.z. This field must be between + 5 and 10 characters long. + maxLength: 10 + minLength: 5 + type: string + x-kubernetes-validations: + - message: bootImageOCPVersion must match the OCP semver compatible + format of x.y.z + rule: self.matches('^[0-9]+\\.[0-9]+\\.[0-9]+$') + rhcosVersion: + description: |- + rhcosVersion provides a string which represents the RHCOS version of the boot image + This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy + format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between + 14 and 21 characters long. + maxLength: 21 + minLength: 14 + type: string + x-kubernetes-validations: + - message: rhcosVersion must match format [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] + or must match legacy format [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber] + rule: self.matches('^[0-9]+\\.[0-9]+\\.([0-9]{8}|[0-9]{12})-[0-9]+$') + type: object + x-kubernetes-validations: + - message: at least one of ocpVersion or rhcosVersion is required + rule: has(self.ocpVersion) || has(self.rhcosVersion) + mode: + description: |- + mode determines the underlying behavior of skew enforcement mechanism. + Valid values are Manual and None. + Manual means that the cluster admin is expected to perform manual boot image updates and store the OCP + & RHCOS version associated with the last boot image update in the manual field. + In Manual mode, the MCO will prevent upgrades when the boot image skew exceeds the + skew limit described by the release image. + None means that the MCO will no longer monitor the boot image skew. This may affect + the cluster's ability to scale. + This field is required. + enum: + - Manual + - None + type: string + required: + - mode + type: object + x-kubernetes-validations: + - message: manual is required when mode is Manual, and forbidden otherwise + rule: 'has(self.mode) && (self.mode ==''Manual'') ? has(self.manual) + : !has(self.manual)' failedRevisionLimit: description: |- failedRevisionLimit is the number of failed static pod installer revisions to keep on disk and in the api @@ -682,6 +754,118 @@ spec: description: status is the most recently observed status of the Machine Config Operator properties: + bootImageSkewEnforcementStatus: + description: |- + bootImageSkewEnforcementStatus reflects what the latest cluster-validated boot image skew enforcement + configuration is and will be used by Machine Config Controller while performing boot image skew enforcement. + When omitted, the MCO has no knowledge of how to enforce boot image skew. When the MCO does not know how + boot image skew should be enforced, cluster upgrades will be blocked until it can either automatically + determine skew enforcement or there is an explicit skew enforcement configuration provided in the + spec.bootImageSkewEnforcement field. + properties: + automatic: + description: |- + automatic describes the current boot image of the cluster. + This will be populated by the MCO when performing boot image updates. This value will be compared against + the cluster's skew limit to determine skew compliance. + Required when mode is set to "Automatic" and forbidden otherwise. + minProperties: 1 + properties: + ocpVersion: + description: |- + ocpVersion provides a string which represents the OCP version of the boot image. + This field must match the OCP semver compatible format of x.y.z. This field must be between + 5 and 10 characters long. + maxLength: 10 + minLength: 5 + type: string + x-kubernetes-validations: + - message: bootImageOCPVersion must match the OCP semver compatible + format of x.y.z + rule: self.matches('^[0-9]+\\.[0-9]+\\.[0-9]+$') + rhcosVersion: + description: |- + rhcosVersion provides a string which represents the RHCOS version of the boot image + This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy + format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between + 14 and 21 characters long. + maxLength: 21 + minLength: 14 + type: string + x-kubernetes-validations: + - message: rhcosVersion must match format [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] + or must match legacy format [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber] + rule: self.matches('^[0-9]+\\.[0-9]+\\.([0-9]{8}|[0-9]{12})-[0-9]+$') + type: object + x-kubernetes-validations: + - message: at least one of ocpVersion or rhcosVersion is required + rule: has(self.ocpVersion) || has(self.rhcosVersion) + manual: + description: |- + manual describes the current boot image of the cluster. + This will be populated by the MCO using the values provided in the spec.bootImageSkewEnforcement.manual field. + This value will be compared against the cluster's skew limit to determine skew compliance. + Required when mode is set to "Manual" and forbidden otherwise. + minProperties: 1 + properties: + ocpVersion: + description: |- + ocpVersion provides a string which represents the OCP version of the boot image. + This field must match the OCP semver compatible format of x.y.z. This field must be between + 5 and 10 characters long. + maxLength: 10 + minLength: 5 + type: string + x-kubernetes-validations: + - message: bootImageOCPVersion must match the OCP semver compatible + format of x.y.z + rule: self.matches('^[0-9]+\\.[0-9]+\\.[0-9]+$') + rhcosVersion: + description: |- + rhcosVersion provides a string which represents the RHCOS version of the boot image + This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy + format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between + 14 and 21 characters long. + maxLength: 21 + minLength: 14 + type: string + x-kubernetes-validations: + - message: rhcosVersion must match format [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] + or must match legacy format [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber] + rule: self.matches('^[0-9]+\\.[0-9]+\\.([0-9]{8}|[0-9]{12})-[0-9]+$') + type: object + x-kubernetes-validations: + - message: at least one of ocpVersion or rhcosVersion is required + rule: has(self.ocpVersion) || has(self.rhcosVersion) + mode: + description: |- + mode determines the underlying behavior of skew enforcement mechanism. + Valid values are Automatic, Manual and None. + Automatic means that the MCO will perform boot image updates and store the + OCP & RHCOS version associated with the last boot image update in the automatic field. + Manual means that the cluster admin is expected to perform manual boot image updates and store the OCP + & RHCOS version associated with the last boot image update in the manual field. + In Automatic and Manual mode, the MCO will prevent upgrades when the boot image skew exceeds the + skew limit described by the release image. + None means that the MCO will no longer monitor the boot image skew. This may affect + the cluster's ability to scale. + This field is required. + enum: + - Automatic + - Manual + - None + type: string + required: + - mode + type: object + x-kubernetes-validations: + - message: automatic is required when mode is Automatic, and forbidden + otherwise + rule: 'has(self.mode) && (self.mode == ''Automatic'') ? has(self.automatic) + : !has(self.automatic)' + - message: manual is required when mode is Manual, and forbidden otherwise + rule: 'has(self.mode) && (self.mode == ''Manual'') ? has(self.manual) + : !has(self.manual)' conditions: description: conditions is a list of conditions and their status items: diff --git a/operator/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfigurations-DevPreviewNoUpgrade.crd.yaml b/operator/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfigurations-DevPreviewNoUpgrade.crd.yaml index 9062795e78d..a718965803f 100644 --- a/operator/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfigurations-DevPreviewNoUpgrade.crd.yaml +++ b/operator/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfigurations-DevPreviewNoUpgrade.crd.yaml @@ -46,6 +46,78 @@ spec: description: spec is the specification of the desired behavior of the Machine Config Operator properties: + bootImageSkewEnforcement: + description: |- + bootImageSkewEnforcement allows an admin to configure how boot image version skew is + enforced on the cluster. + When omitted, this will default to Automatic for clusters that support automatic boot image updates. + For clusters that do not support automatic boot image updates, cluster upgrades will be disabled until + a skew enforcement mode has been specified. + When version skew is being enforced, cluster upgrades will be disabled until the version skew is deemed + acceptable for the current release payload. + properties: + manual: + description: |- + manual describes the current boot image of the cluster. + This should be set to the oldest boot image used amongst all machine resources in the cluster. + This includes the RHCOS version of the boot image and the OCP release version which shipped with that RHCOS boot image. + If ocpVersion and rhcosVersion are defined, both values will be used for checking skew compliance. + If only ocpVersion is defined, only that value will be used for checking skew compliance. + If only rhcosVersion is defined, only that value will be used for checking skew compliance. + Required when mode is set to "Manual" and forbidden otherwise. + minProperties: 1 + properties: + ocpVersion: + description: |- + ocpVersion provides a string which represents the OCP version of the boot image. + This field must match the OCP semver compatible format of x.y.z. This field must be between + 5 and 10 characters long. + maxLength: 10 + minLength: 5 + type: string + x-kubernetes-validations: + - message: bootImageOCPVersion must match the OCP semver compatible + format of x.y.z + rule: self.matches('^[0-9]+\\.[0-9]+\\.[0-9]+$') + rhcosVersion: + description: |- + rhcosVersion provides a string which represents the RHCOS version of the boot image + This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy + format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between + 14 and 21 characters long. + maxLength: 21 + minLength: 14 + type: string + x-kubernetes-validations: + - message: rhcosVersion must match format [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] + or must match legacy format [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber] + rule: self.matches('^[0-9]+\\.[0-9]+\\.([0-9]{8}|[0-9]{12})-[0-9]+$') + type: object + x-kubernetes-validations: + - message: at least one of ocpVersion or rhcosVersion is required + rule: has(self.ocpVersion) || has(self.rhcosVersion) + mode: + description: |- + mode determines the underlying behavior of skew enforcement mechanism. + Valid values are Manual and None. + Manual means that the cluster admin is expected to perform manual boot image updates and store the OCP + & RHCOS version associated with the last boot image update in the manual field. + In Manual mode, the MCO will prevent upgrades when the boot image skew exceeds the + skew limit described by the release image. + None means that the MCO will no longer monitor the boot image skew. This may affect + the cluster's ability to scale. + This field is required. + enum: + - Manual + - None + type: string + required: + - mode + type: object + x-kubernetes-validations: + - message: manual is required when mode is Manual, and forbidden otherwise + rule: 'has(self.mode) && (self.mode ==''Manual'') ? has(self.manual) + : !has(self.manual)' failedRevisionLimit: description: |- failedRevisionLimit is the number of failed static pod installer revisions to keep on disk and in the api @@ -682,6 +754,118 @@ spec: description: status is the most recently observed status of the Machine Config Operator properties: + bootImageSkewEnforcementStatus: + description: |- + bootImageSkewEnforcementStatus reflects what the latest cluster-validated boot image skew enforcement + configuration is and will be used by Machine Config Controller while performing boot image skew enforcement. + When omitted, the MCO has no knowledge of how to enforce boot image skew. When the MCO does not know how + boot image skew should be enforced, cluster upgrades will be blocked until it can either automatically + determine skew enforcement or there is an explicit skew enforcement configuration provided in the + spec.bootImageSkewEnforcement field. + properties: + automatic: + description: |- + automatic describes the current boot image of the cluster. + This will be populated by the MCO when performing boot image updates. This value will be compared against + the cluster's skew limit to determine skew compliance. + Required when mode is set to "Automatic" and forbidden otherwise. + minProperties: 1 + properties: + ocpVersion: + description: |- + ocpVersion provides a string which represents the OCP version of the boot image. + This field must match the OCP semver compatible format of x.y.z. This field must be between + 5 and 10 characters long. + maxLength: 10 + minLength: 5 + type: string + x-kubernetes-validations: + - message: bootImageOCPVersion must match the OCP semver compatible + format of x.y.z + rule: self.matches('^[0-9]+\\.[0-9]+\\.[0-9]+$') + rhcosVersion: + description: |- + rhcosVersion provides a string which represents the RHCOS version of the boot image + This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy + format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between + 14 and 21 characters long. + maxLength: 21 + minLength: 14 + type: string + x-kubernetes-validations: + - message: rhcosVersion must match format [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] + or must match legacy format [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber] + rule: self.matches('^[0-9]+\\.[0-9]+\\.([0-9]{8}|[0-9]{12})-[0-9]+$') + type: object + x-kubernetes-validations: + - message: at least one of ocpVersion or rhcosVersion is required + rule: has(self.ocpVersion) || has(self.rhcosVersion) + manual: + description: |- + manual describes the current boot image of the cluster. + This will be populated by the MCO using the values provided in the spec.bootImageSkewEnforcement.manual field. + This value will be compared against the cluster's skew limit to determine skew compliance. + Required when mode is set to "Manual" and forbidden otherwise. + minProperties: 1 + properties: + ocpVersion: + description: |- + ocpVersion provides a string which represents the OCP version of the boot image. + This field must match the OCP semver compatible format of x.y.z. This field must be between + 5 and 10 characters long. + maxLength: 10 + minLength: 5 + type: string + x-kubernetes-validations: + - message: bootImageOCPVersion must match the OCP semver compatible + format of x.y.z + rule: self.matches('^[0-9]+\\.[0-9]+\\.[0-9]+$') + rhcosVersion: + description: |- + rhcosVersion provides a string which represents the RHCOS version of the boot image + This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy + format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between + 14 and 21 characters long. + maxLength: 21 + minLength: 14 + type: string + x-kubernetes-validations: + - message: rhcosVersion must match format [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] + or must match legacy format [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber] + rule: self.matches('^[0-9]+\\.[0-9]+\\.([0-9]{8}|[0-9]{12})-[0-9]+$') + type: object + x-kubernetes-validations: + - message: at least one of ocpVersion or rhcosVersion is required + rule: has(self.ocpVersion) || has(self.rhcosVersion) + mode: + description: |- + mode determines the underlying behavior of skew enforcement mechanism. + Valid values are Automatic, Manual and None. + Automatic means that the MCO will perform boot image updates and store the + OCP & RHCOS version associated with the last boot image update in the automatic field. + Manual means that the cluster admin is expected to perform manual boot image updates and store the OCP + & RHCOS version associated with the last boot image update in the manual field. + In Automatic and Manual mode, the MCO will prevent upgrades when the boot image skew exceeds the + skew limit described by the release image. + None means that the MCO will no longer monitor the boot image skew. This may affect + the cluster's ability to scale. + This field is required. + enum: + - Automatic + - Manual + - None + type: string + required: + - mode + type: object + x-kubernetes-validations: + - message: automatic is required when mode is Automatic, and forbidden + otherwise + rule: 'has(self.mode) && (self.mode == ''Automatic'') ? has(self.automatic) + : !has(self.automatic)' + - message: manual is required when mode is Manual, and forbidden otherwise + rule: 'has(self.mode) && (self.mode == ''Manual'') ? has(self.manual) + : !has(self.manual)' conditions: description: conditions is a list of conditions and their status items: diff --git a/operator/v1/zz_generated.deepcopy.go b/operator/v1/zz_generated.deepcopy.go index d2e74e68387..d8594ff5452 100644 --- a/operator/v1/zz_generated.deepcopy.go +++ b/operator/v1/zz_generated.deepcopy.go @@ -390,6 +390,41 @@ func (in *AzureDiskEncryptionSet) DeepCopy() *AzureDiskEncryptionSet { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BootImageSkewEnforcementConfig) DeepCopyInto(out *BootImageSkewEnforcementConfig) { + *out = *in + out.Manual = in.Manual + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BootImageSkewEnforcementConfig. +func (in *BootImageSkewEnforcementConfig) DeepCopy() *BootImageSkewEnforcementConfig { + if in == nil { + return nil + } + out := new(BootImageSkewEnforcementConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BootImageSkewEnforcementStatus) DeepCopyInto(out *BootImageSkewEnforcementStatus) { + *out = *in + out.Automatic = in.Automatic + out.Manual = in.Manual + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BootImageSkewEnforcementStatus. +func (in *BootImageSkewEnforcementStatus) DeepCopy() *BootImageSkewEnforcementStatus { + if in == nil { + return nil + } + out := new(BootImageSkewEnforcementStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CSIDriverConfigSpec) DeepCopyInto(out *CSIDriverConfigSpec) { *out = *in @@ -676,6 +711,22 @@ func (in *CloudCredentialStatus) DeepCopy() *CloudCredentialStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterBootImage) DeepCopyInto(out *ClusterBootImage) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterBootImage. +func (in *ClusterBootImage) DeepCopy() *ClusterBootImage { + if in == nil { + return nil + } + out := new(ClusterBootImage) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterCSIDriver) DeepCopyInto(out *ClusterCSIDriver) { *out = *in @@ -3243,6 +3294,7 @@ func (in *MachineConfigurationSpec) DeepCopyInto(out *MachineConfigurationSpec) in.ManagedBootImages.DeepCopyInto(&out.ManagedBootImages) in.NodeDisruptionPolicy.DeepCopyInto(&out.NodeDisruptionPolicy) in.IrreconcilableValidationOverrides.DeepCopyInto(&out.IrreconcilableValidationOverrides) + out.BootImageSkewEnforcement = in.BootImageSkewEnforcement return } @@ -3268,6 +3320,7 @@ func (in *MachineConfigurationStatus) DeepCopyInto(out *MachineConfigurationStat } in.NodeDisruptionPolicyStatus.DeepCopyInto(&out.NodeDisruptionPolicyStatus) in.ManagedBootImagesStatus.DeepCopyInto(&out.ManagedBootImagesStatus) + out.BootImageSkewEnforcementStatus = in.BootImageSkewEnforcementStatus return } diff --git a/operator/v1/zz_generated.featuregated-crd-manifests.yaml b/operator/v1/zz_generated.featuregated-crd-manifests.yaml index a893b0e0f37..bfdce9cf5b0 100644 --- a/operator/v1/zz_generated.featuregated-crd-manifests.yaml +++ b/operator/v1/zz_generated.featuregated-crd-manifests.yaml @@ -305,6 +305,7 @@ machineconfigurations.operator.openshift.io: Capability: "" Category: "" FeatureGates: + - BootImageSkewEnforcement - IrreconcilableMachineConfig - ManagedBootImages FilenameOperatorName: machine-config diff --git a/operator/v1/zz_generated.featuregated-crd-manifests/machineconfigurations.operator.openshift.io/BootImageSkewEnforcement.yaml b/operator/v1/zz_generated.featuregated-crd-manifests/machineconfigurations.operator.openshift.io/BootImageSkewEnforcement.yaml new file mode 100644 index 00000000000..50537a244c0 --- /dev/null +++ b/operator/v1/zz_generated.featuregated-crd-manifests/machineconfigurations.operator.openshift.io/BootImageSkewEnforcement.yaml @@ -0,0 +1,1180 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.openshift.io: https://github.com/openshift/api/pull/1453 + api.openshift.io/filename-cvo-runlevel: "0000_80" + api.openshift.io/filename-operator: machine-config + api.openshift.io/filename-ordering: "01" + feature-gate.release.openshift.io/BootImageSkewEnforcement: "true" + name: machineconfigurations.operator.openshift.io +spec: + group: operator.openshift.io + names: + kind: MachineConfiguration + listKind: MachineConfigurationList + plural: machineconfigurations + singular: machineconfiguration + scope: Cluster + versions: + - name: v1 + schema: + openAPIV3Schema: + description: |- + MachineConfiguration provides information to configure an operator to manage Machine Configuration. + + 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 specification of the desired behavior of the + Machine Config Operator + properties: + bootImageSkewEnforcement: + description: |- + bootImageSkewEnforcement allows an admin to configure how boot image version skew is + enforced on the cluster. + When omitted, this will default to Automatic for clusters that support automatic boot image updates. + For clusters that do not support automatic boot image updates, cluster upgrades will be disabled until + a skew enforcement mode has been specified. + When version skew is being enforced, cluster upgrades will be disabled until the version skew is deemed + acceptable for the current release payload. + properties: + manual: + description: |- + manual describes the current boot image of the cluster. + This should be set to the oldest boot image used amongst all machine resources in the cluster. + This includes the RHCOS version of the boot image and the OCP release version which shipped with that RHCOS boot image. + If ocpVersion and rhcosVersion are defined, both values will be used for checking skew compliance. + If only ocpVersion is defined, only that value will be used for checking skew compliance. + If only rhcosVersion is defined, only that value will be used for checking skew compliance. + Required when mode is set to "Manual" and forbidden otherwise. + minProperties: 1 + properties: + ocpVersion: + description: |- + ocpVersion provides a string which represents the OCP version of the boot image. + This field must match the OCP semver compatible format of x.y.z. This field must be between + 5 and 10 characters long. + maxLength: 10 + minLength: 5 + type: string + x-kubernetes-validations: + - message: bootImageOCPVersion must match the OCP semver compatible + format of x.y.z + rule: self.matches('^[0-9]+\\.[0-9]+\\.[0-9]+$') + rhcosVersion: + description: |- + rhcosVersion provides a string which represents the RHCOS version of the boot image + This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy + format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between + 14 and 21 characters long. + maxLength: 21 + minLength: 14 + type: string + x-kubernetes-validations: + - message: rhcosVersion must match format [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] + or must match legacy format [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber] + rule: self.matches('^[0-9]+\\.[0-9]+\\.([0-9]{8}|[0-9]{12})-[0-9]+$') + type: object + x-kubernetes-validations: + - message: at least one of ocpVersion or rhcosVersion is required + rule: has(self.ocpVersion) || has(self.rhcosVersion) + mode: + description: |- + mode determines the underlying behavior of skew enforcement mechanism. + Valid values are Manual and None. + Manual means that the cluster admin is expected to perform manual boot image updates and store the OCP + & RHCOS version associated with the last boot image update in the manual field. + In Manual mode, the MCO will prevent upgrades when the boot image skew exceeds the + skew limit described by the release image. + None means that the MCO will no longer monitor the boot image skew. This may affect + the cluster's ability to scale. + This field is required. + enum: + - Manual + - None + type: string + required: + - mode + type: object + x-kubernetes-validations: + - message: manual is required when mode is Manual, and forbidden otherwise + rule: 'has(self.mode) && (self.mode ==''Manual'') ? has(self.manual) + : !has(self.manual)' + failedRevisionLimit: + description: |- + failedRevisionLimit is the number of failed static pod installer revisions to keep on disk and in the api + -1 = unlimited, 0 or unset = 5 (default) + format: int32 + type: integer + forceRedeploymentReason: + description: |- + forceRedeploymentReason can be used to force the redeployment of the operand by providing a unique string. + This provides a mechanism to kick a previously failed deployment and provide a reason why you think it will work + this time instead of failing again on the same config. + type: string + logLevel: + default: Normal + description: |- + logLevel is an intent based logging for an overall component. It does not give fine grained control, but it is a + simple way to manage coarse grained logging choices that operators have to interpret for their operands. + + Valid values are: "Normal", "Debug", "Trace", "TraceAll". + Defaults to "Normal". + enum: + - "" + - Normal + - Debug + - Trace + - TraceAll + type: string + managementState: + description: managementState indicates whether and how the operator + should manage the component + pattern: ^(Managed|Unmanaged|Force|Removed)$ + type: string + nodeDisruptionPolicy: + description: |- + nodeDisruptionPolicy allows an admin to set granular node disruption actions for + MachineConfig-based updates, such as drains, service reloads, etc. Specifying this will allow + for less downtime when doing small configuration updates to the cluster. This configuration + has no effect on cluster upgrades which will still incur node disruption where required. + properties: + files: + description: |- + files is a list of MachineConfig file definitions and actions to take to changes on those paths + This list supports a maximum of 50 entries. + items: + description: NodeDisruptionPolicySpecFile is a file entry and + corresponding actions to take and is used in the NodeDisruptionPolicyConfig + object + properties: + actions: + description: |- + actions represents the series of commands to be executed on changes to the file at + the corresponding file path. Actions will be applied in the order that + they are set in this list. If there are other incoming changes to other MachineConfig + entries in the same update that require a reboot, the reboot will supercede these actions. + Valid actions are Reboot, Drain, Reload, DaemonReload and None. + The Reboot action and the None action cannot be used in conjunction with any of the other actions. + This list supports a maximum of 10 entries. + items: + properties: + reload: + description: reload specifies the service to reload, + only valid if type is reload + properties: + serviceName: + description: |- + serviceName is the full name (e.g. crio.service) of the service to be reloaded + Service names should be of the format ${NAME}${SERVICETYPE} and can up to 255 characters long. + ${NAME} must be atleast 1 character long and can only consist of alphabets, digits, ":", "-", "_", ".", and "\". + ${SERVICETYPE} must be one of ".service", ".socket", ".device", ".mount", ".automount", ".swap", ".target", ".path", ".timer", ".snapshot", ".slice" or ".scope". + maxLength: 255 + type: string + x-kubernetes-validations: + - message: Invalid ${SERVICETYPE} in service name. + Expected format is ${NAME}${SERVICETYPE}, + where ${SERVICETYPE} must be one of ".service", + ".socket", ".device", ".mount", ".automount", + ".swap", ".target", ".path", ".timer",".snapshot", + ".slice" or ".scope". + rule: self.matches('\\.(service|socket|device|mount|automount|swap|target|path|timer|snapshot|slice|scope)$') + - message: Invalid ${NAME} in service name. Expected + format is ${NAME}${SERVICETYPE}, where {NAME} + must be atleast 1 character long and can only + consist of alphabets, digits, ":", "-", "_", + ".", and "\" + rule: self.matches('^[a-zA-Z0-9:._\\\\-]+\\..') + required: + - serviceName + type: object + restart: + description: restart specifies the service to restart, + only valid if type is restart + properties: + serviceName: + description: |- + serviceName is the full name (e.g. crio.service) of the service to be restarted + Service names should be of the format ${NAME}${SERVICETYPE} and can up to 255 characters long. + ${NAME} must be atleast 1 character long and can only consist of alphabets, digits, ":", "-", "_", ".", and "\". + ${SERVICETYPE} must be one of ".service", ".socket", ".device", ".mount", ".automount", ".swap", ".target", ".path", ".timer", ".snapshot", ".slice" or ".scope". + maxLength: 255 + type: string + x-kubernetes-validations: + - message: Invalid ${SERVICETYPE} in service name. + Expected format is ${NAME}${SERVICETYPE}, + where ${SERVICETYPE} must be one of ".service", + ".socket", ".device", ".mount", ".automount", + ".swap", ".target", ".path", ".timer",".snapshot", + ".slice" or ".scope". + rule: self.matches('\\.(service|socket|device|mount|automount|swap|target|path|timer|snapshot|slice|scope)$') + - message: Invalid ${NAME} in service name. Expected + format is ${NAME}${SERVICETYPE}, where {NAME} + must be atleast 1 character long and can only + consist of alphabets, digits, ":", "-", "_", + ".", and "\" + rule: self.matches('^[a-zA-Z0-9:._\\\\-]+\\..') + required: + - serviceName + type: object + type: + description: |- + type represents the commands that will be carried out if this NodeDisruptionPolicySpecActionType is executed + Valid values are Reboot, Drain, Reload, Restart, DaemonReload and None. + reload/restart requires a corresponding service target specified in the reload/restart field. + Other values require no further configuration + enum: + - Reboot + - Drain + - Reload + - Restart + - DaemonReload + - None + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: reload is required when type is Reload, and + forbidden otherwise + rule: 'has(self.type) && self.type == ''Reload'' ? has(self.reload) + : !has(self.reload)' + - message: restart is required when type is Restart, and + forbidden otherwise + rule: 'has(self.type) && self.type == ''Restart'' ? + has(self.restart) : !has(self.restart)' + maxItems: 10 + type: array + x-kubernetes-list-type: atomic + x-kubernetes-validations: + - message: Reboot action can only be specified standalone, + as it will override any other actions + rule: 'self.exists(x, x.type==''Reboot'') ? size(self) + == 1 : true' + - message: None action can only be specified standalone, + as it will override any other actions + rule: 'self.exists(x, x.type==''None'') ? size(self) == + 1 : true' + path: + description: |- + path is the location of a file being managed through a MachineConfig. + The Actions in the policy will apply to changes to the file at this path. + type: string + required: + - actions + - path + type: object + maxItems: 50 + type: array + x-kubernetes-list-map-keys: + - path + x-kubernetes-list-type: map + sshkey: + description: |- + sshkey maps to the ignition.sshkeys field in the MachineConfig object, definition an action for this + will apply to all sshkey changes in the cluster + properties: + actions: + description: |- + actions represents the series of commands to be executed on changes to the file at + the corresponding file path. Actions will be applied in the order that + they are set in this list. If there are other incoming changes to other MachineConfig + entries in the same update that require a reboot, the reboot will supercede these actions. + Valid actions are Reboot, Drain, Reload, DaemonReload and None. + The Reboot action and the None action cannot be used in conjunction with any of the other actions. + This list supports a maximum of 10 entries. + items: + properties: + reload: + description: reload specifies the service to reload, + only valid if type is reload + properties: + serviceName: + description: |- + serviceName is the full name (e.g. crio.service) of the service to be reloaded + Service names should be of the format ${NAME}${SERVICETYPE} and can up to 255 characters long. + ${NAME} must be atleast 1 character long and can only consist of alphabets, digits, ":", "-", "_", ".", and "\". + ${SERVICETYPE} must be one of ".service", ".socket", ".device", ".mount", ".automount", ".swap", ".target", ".path", ".timer", ".snapshot", ".slice" or ".scope". + maxLength: 255 + type: string + x-kubernetes-validations: + - message: Invalid ${SERVICETYPE} in service name. + Expected format is ${NAME}${SERVICETYPE}, where + ${SERVICETYPE} must be one of ".service", ".socket", + ".device", ".mount", ".automount", ".swap", + ".target", ".path", ".timer",".snapshot", ".slice" + or ".scope". + rule: self.matches('\\.(service|socket|device|mount|automount|swap|target|path|timer|snapshot|slice|scope)$') + - message: Invalid ${NAME} in service name. Expected + format is ${NAME}${SERVICETYPE}, where {NAME} + must be atleast 1 character long and can only + consist of alphabets, digits, ":", "-", "_", + ".", and "\" + rule: self.matches('^[a-zA-Z0-9:._\\\\-]+\\..') + required: + - serviceName + type: object + restart: + description: restart specifies the service to restart, + only valid if type is restart + properties: + serviceName: + description: |- + serviceName is the full name (e.g. crio.service) of the service to be restarted + Service names should be of the format ${NAME}${SERVICETYPE} and can up to 255 characters long. + ${NAME} must be atleast 1 character long and can only consist of alphabets, digits, ":", "-", "_", ".", and "\". + ${SERVICETYPE} must be one of ".service", ".socket", ".device", ".mount", ".automount", ".swap", ".target", ".path", ".timer", ".snapshot", ".slice" or ".scope". + maxLength: 255 + type: string + x-kubernetes-validations: + - message: Invalid ${SERVICETYPE} in service name. + Expected format is ${NAME}${SERVICETYPE}, where + ${SERVICETYPE} must be one of ".service", ".socket", + ".device", ".mount", ".automount", ".swap", + ".target", ".path", ".timer",".snapshot", ".slice" + or ".scope". + rule: self.matches('\\.(service|socket|device|mount|automount|swap|target|path|timer|snapshot|slice|scope)$') + - message: Invalid ${NAME} in service name. Expected + format is ${NAME}${SERVICETYPE}, where {NAME} + must be atleast 1 character long and can only + consist of alphabets, digits, ":", "-", "_", + ".", and "\" + rule: self.matches('^[a-zA-Z0-9:._\\\\-]+\\..') + required: + - serviceName + type: object + type: + description: |- + type represents the commands that will be carried out if this NodeDisruptionPolicySpecActionType is executed + Valid values are Reboot, Drain, Reload, Restart, DaemonReload and None. + reload/restart requires a corresponding service target specified in the reload/restart field. + Other values require no further configuration + enum: + - Reboot + - Drain + - Reload + - Restart + - DaemonReload + - None + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: reload is required when type is Reload, and forbidden + otherwise + rule: 'has(self.type) && self.type == ''Reload'' ? has(self.reload) + : !has(self.reload)' + - message: restart is required when type is Restart, and + forbidden otherwise + rule: 'has(self.type) && self.type == ''Restart'' ? has(self.restart) + : !has(self.restart)' + maxItems: 10 + type: array + x-kubernetes-list-type: atomic + x-kubernetes-validations: + - message: Reboot action can only be specified standalone, + as it will override any other actions + rule: 'self.exists(x, x.type==''Reboot'') ? size(self) == + 1 : true' + - message: None action can only be specified standalone, as + it will override any other actions + rule: 'self.exists(x, x.type==''None'') ? size(self) == + 1 : true' + required: + - actions + type: object + units: + description: |- + units is a list MachineConfig unit definitions and actions to take on changes to those services + This list supports a maximum of 50 entries. + items: + description: NodeDisruptionPolicySpecUnit is a systemd unit + name and corresponding actions to take and is used in the + NodeDisruptionPolicyConfig object + properties: + actions: + description: |- + actions represents the series of commands to be executed on changes to the file at + the corresponding file path. Actions will be applied in the order that + they are set in this list. If there are other incoming changes to other MachineConfig + entries in the same update that require a reboot, the reboot will supercede these actions. + Valid actions are Reboot, Drain, Reload, DaemonReload and None. + The Reboot action and the None action cannot be used in conjunction with any of the other actions. + This list supports a maximum of 10 entries. + items: + properties: + reload: + description: reload specifies the service to reload, + only valid if type is reload + properties: + serviceName: + description: |- + serviceName is the full name (e.g. crio.service) of the service to be reloaded + Service names should be of the format ${NAME}${SERVICETYPE} and can up to 255 characters long. + ${NAME} must be atleast 1 character long and can only consist of alphabets, digits, ":", "-", "_", ".", and "\". + ${SERVICETYPE} must be one of ".service", ".socket", ".device", ".mount", ".automount", ".swap", ".target", ".path", ".timer", ".snapshot", ".slice" or ".scope". + maxLength: 255 + type: string + x-kubernetes-validations: + - message: Invalid ${SERVICETYPE} in service name. + Expected format is ${NAME}${SERVICETYPE}, + where ${SERVICETYPE} must be one of ".service", + ".socket", ".device", ".mount", ".automount", + ".swap", ".target", ".path", ".timer",".snapshot", + ".slice" or ".scope". + rule: self.matches('\\.(service|socket|device|mount|automount|swap|target|path|timer|snapshot|slice|scope)$') + - message: Invalid ${NAME} in service name. Expected + format is ${NAME}${SERVICETYPE}, where {NAME} + must be atleast 1 character long and can only + consist of alphabets, digits, ":", "-", "_", + ".", and "\" + rule: self.matches('^[a-zA-Z0-9:._\\\\-]+\\..') + required: + - serviceName + type: object + restart: + description: restart specifies the service to restart, + only valid if type is restart + properties: + serviceName: + description: |- + serviceName is the full name (e.g. crio.service) of the service to be restarted + Service names should be of the format ${NAME}${SERVICETYPE} and can up to 255 characters long. + ${NAME} must be atleast 1 character long and can only consist of alphabets, digits, ":", "-", "_", ".", and "\". + ${SERVICETYPE} must be one of ".service", ".socket", ".device", ".mount", ".automount", ".swap", ".target", ".path", ".timer", ".snapshot", ".slice" or ".scope". + maxLength: 255 + type: string + x-kubernetes-validations: + - message: Invalid ${SERVICETYPE} in service name. + Expected format is ${NAME}${SERVICETYPE}, + where ${SERVICETYPE} must be one of ".service", + ".socket", ".device", ".mount", ".automount", + ".swap", ".target", ".path", ".timer",".snapshot", + ".slice" or ".scope". + rule: self.matches('\\.(service|socket|device|mount|automount|swap|target|path|timer|snapshot|slice|scope)$') + - message: Invalid ${NAME} in service name. Expected + format is ${NAME}${SERVICETYPE}, where {NAME} + must be atleast 1 character long and can only + consist of alphabets, digits, ":", "-", "_", + ".", and "\" + rule: self.matches('^[a-zA-Z0-9:._\\\\-]+\\..') + required: + - serviceName + type: object + type: + description: |- + type represents the commands that will be carried out if this NodeDisruptionPolicySpecActionType is executed + Valid values are Reboot, Drain, Reload, Restart, DaemonReload and None. + reload/restart requires a corresponding service target specified in the reload/restart field. + Other values require no further configuration + enum: + - Reboot + - Drain + - Reload + - Restart + - DaemonReload + - None + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: reload is required when type is Reload, and + forbidden otherwise + rule: 'has(self.type) && self.type == ''Reload'' ? has(self.reload) + : !has(self.reload)' + - message: restart is required when type is Restart, and + forbidden otherwise + rule: 'has(self.type) && self.type == ''Restart'' ? + has(self.restart) : !has(self.restart)' + maxItems: 10 + type: array + x-kubernetes-list-type: atomic + x-kubernetes-validations: + - message: Reboot action can only be specified standalone, + as it will override any other actions + rule: 'self.exists(x, x.type==''Reboot'') ? size(self) + == 1 : true' + - message: None action can only be specified standalone, + as it will override any other actions + rule: 'self.exists(x, x.type==''None'') ? size(self) == + 1 : true' + name: + description: |- + name represents the service name of a systemd service managed through a MachineConfig + Actions specified will be applied for changes to the named service. + Service names should be of the format ${NAME}${SERVICETYPE} and can up to 255 characters long. + ${NAME} must be atleast 1 character long and can only consist of alphabets, digits, ":", "-", "_", ".", and "\". + ${SERVICETYPE} must be one of ".service", ".socket", ".device", ".mount", ".automount", ".swap", ".target", ".path", ".timer", ".snapshot", ".slice" or ".scope". + maxLength: 255 + type: string + x-kubernetes-validations: + - message: Invalid ${SERVICETYPE} in service name. Expected + format is ${NAME}${SERVICETYPE}, where ${SERVICETYPE} + must be one of ".service", ".socket", ".device", ".mount", + ".automount", ".swap", ".target", ".path", ".timer",".snapshot", + ".slice" or ".scope". + rule: self.matches('\\.(service|socket|device|mount|automount|swap|target|path|timer|snapshot|slice|scope)$') + - message: Invalid ${NAME} in service name. Expected format + is ${NAME}${SERVICETYPE}, where {NAME} must be atleast + 1 character long and can only consist of alphabets, + digits, ":", "-", "_", ".", and "\" + rule: self.matches('^[a-zA-Z0-9:._\\\\-]+\\..') + required: + - actions + - name + type: object + maxItems: 50 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + observedConfig: + description: |- + observedConfig holds a sparse config that controller has observed from the cluster state. It exists in spec because + it is an input to the level for the operator + nullable: true + type: object + x-kubernetes-preserve-unknown-fields: true + operatorLogLevel: + default: Normal + description: |- + operatorLogLevel is an intent based logging for the operator itself. It does not give fine grained control, but it is a + simple way to manage coarse grained logging choices that operators have to interpret for themselves. + + Valid values are: "Normal", "Debug", "Trace", "TraceAll". + Defaults to "Normal". + enum: + - "" + - Normal + - Debug + - Trace + - TraceAll + type: string + succeededRevisionLimit: + description: |- + succeededRevisionLimit is the number of successful static pod installer revisions to keep on disk and in the api + -1 = unlimited, 0 or unset = 5 (default) + format: int32 + type: integer + unsupportedConfigOverrides: + description: |- + unsupportedConfigOverrides overrides the final configuration that was computed by the operator. + Red Hat does not support the use of this field. + Misuse of this field could lead to unexpected behavior or conflict with other configuration options. + Seek guidance from the Red Hat support before using this field. + Use of this property blocks cluster upgrades, it must be removed before upgrading your cluster. + nullable: true + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + status: + description: status is the most recently observed status of the Machine + Config Operator + properties: + bootImageSkewEnforcementStatus: + description: |- + bootImageSkewEnforcementStatus reflects what the latest cluster-validated boot image skew enforcement + configuration is and will be used by Machine Config Controller while performing boot image skew enforcement. + When omitted, the MCO has no knowledge of how to enforce boot image skew. When the MCO does not know how + boot image skew should be enforced, cluster upgrades will be blocked until it can either automatically + determine skew enforcement or there is an explicit skew enforcement configuration provided in the + spec.bootImageSkewEnforcement field. + properties: + automatic: + description: |- + automatic describes the current boot image of the cluster. + This will be populated by the MCO when performing boot image updates. This value will be compared against + the cluster's skew limit to determine skew compliance. + Required when mode is set to "Automatic" and forbidden otherwise. + minProperties: 1 + properties: + ocpVersion: + description: |- + ocpVersion provides a string which represents the OCP version of the boot image. + This field must match the OCP semver compatible format of x.y.z. This field must be between + 5 and 10 characters long. + maxLength: 10 + minLength: 5 + type: string + x-kubernetes-validations: + - message: bootImageOCPVersion must match the OCP semver compatible + format of x.y.z + rule: self.matches('^[0-9]+\\.[0-9]+\\.[0-9]+$') + rhcosVersion: + description: |- + rhcosVersion provides a string which represents the RHCOS version of the boot image + This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy + format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between + 14 and 21 characters long. + maxLength: 21 + minLength: 14 + type: string + x-kubernetes-validations: + - message: rhcosVersion must match format [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] + or must match legacy format [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber] + rule: self.matches('^[0-9]+\\.[0-9]+\\.([0-9]{8}|[0-9]{12})-[0-9]+$') + type: object + x-kubernetes-validations: + - message: at least one of ocpVersion or rhcosVersion is required + rule: has(self.ocpVersion) || has(self.rhcosVersion) + manual: + description: |- + manual describes the current boot image of the cluster. + This will be populated by the MCO using the values provided in the spec.bootImageSkewEnforcement.manual field. + This value will be compared against the cluster's skew limit to determine skew compliance. + Required when mode is set to "Manual" and forbidden otherwise. + minProperties: 1 + properties: + ocpVersion: + description: |- + ocpVersion provides a string which represents the OCP version of the boot image. + This field must match the OCP semver compatible format of x.y.z. This field must be between + 5 and 10 characters long. + maxLength: 10 + minLength: 5 + type: string + x-kubernetes-validations: + - message: bootImageOCPVersion must match the OCP semver compatible + format of x.y.z + rule: self.matches('^[0-9]+\\.[0-9]+\\.[0-9]+$') + rhcosVersion: + description: |- + rhcosVersion provides a string which represents the RHCOS version of the boot image + This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy + format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between + 14 and 21 characters long. + maxLength: 21 + minLength: 14 + type: string + x-kubernetes-validations: + - message: rhcosVersion must match format [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] + or must match legacy format [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber] + rule: self.matches('^[0-9]+\\.[0-9]+\\.([0-9]{8}|[0-9]{12})-[0-9]+$') + type: object + x-kubernetes-validations: + - message: at least one of ocpVersion or rhcosVersion is required + rule: has(self.ocpVersion) || has(self.rhcosVersion) + mode: + description: |- + mode determines the underlying behavior of skew enforcement mechanism. + Valid values are Automatic, Manual and None. + Automatic means that the MCO will perform boot image updates and store the + OCP & RHCOS version associated with the last boot image update in the automatic field. + Manual means that the cluster admin is expected to perform manual boot image updates and store the OCP + & RHCOS version associated with the last boot image update in the manual field. + In Automatic and Manual mode, the MCO will prevent upgrades when the boot image skew exceeds the + skew limit described by the release image. + None means that the MCO will no longer monitor the boot image skew. This may affect + the cluster's ability to scale. + This field is required. + enum: + - Automatic + - Manual + - None + type: string + required: + - mode + type: object + x-kubernetes-validations: + - message: automatic is required when mode is Automatic, and forbidden + otherwise + rule: 'has(self.mode) && (self.mode == ''Automatic'') ? has(self.automatic) + : !has(self.automatic)' + - message: manual is required when mode is Manual, and forbidden otherwise + rule: 'has(self.mode) && (self.mode == ''Manual'') ? has(self.manual) + : !has(self.manual)' + conditions: + description: conditions is a list of conditions and their status + 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 + nodeDisruptionPolicyStatus: + description: |- + nodeDisruptionPolicyStatus status reflects what the latest cluster-validated policies are, + and will be used by the Machine Config Daemon during future node updates. + properties: + clusterPolicies: + description: clusterPolicies is a merge of cluster default and + user provided node disruption policies. + properties: + files: + description: files is a list of MachineConfig file definitions + and actions to take to changes on those paths + items: + description: NodeDisruptionPolicyStatusFile is a file entry + and corresponding actions to take and is used in the NodeDisruptionPolicyClusterStatus + object + properties: + actions: + description: |- + actions represents the series of commands to be executed on changes to the file at + the corresponding file path. Actions will be applied in the order that + they are set in this list. If there are other incoming changes to other MachineConfig + entries in the same update that require a reboot, the reboot will supercede these actions. + Valid actions are Reboot, Drain, Reload, DaemonReload and None. + The Reboot action and the None action cannot be used in conjunction with any of the other actions. + This list supports a maximum of 10 entries. + items: + properties: + reload: + description: reload specifies the service to reload, + only valid if type is reload + properties: + serviceName: + description: |- + serviceName is the full name (e.g. crio.service) of the service to be reloaded + Service names should be of the format ${NAME}${SERVICETYPE} and can up to 255 characters long. + ${NAME} must be atleast 1 character long and can only consist of alphabets, digits, ":", "-", "_", ".", and "\". + ${SERVICETYPE} must be one of ".service", ".socket", ".device", ".mount", ".automount", ".swap", ".target", ".path", ".timer", ".snapshot", ".slice" or ".scope". + maxLength: 255 + type: string + x-kubernetes-validations: + - message: Invalid ${SERVICETYPE} in service + name. Expected format is ${NAME}${SERVICETYPE}, + where ${SERVICETYPE} must be one of ".service", + ".socket", ".device", ".mount", ".automount", + ".swap", ".target", ".path", ".timer",".snapshot", + ".slice" or ".scope". + rule: self.matches('\\.(service|socket|device|mount|automount|swap|target|path|timer|snapshot|slice|scope)$') + - message: Invalid ${NAME} in service name. + Expected format is ${NAME}${SERVICETYPE}, + where {NAME} must be atleast 1 character + long and can only consist of alphabets, + digits, ":", "-", "_", ".", and "\" + rule: self.matches('^[a-zA-Z0-9:._\\\\-]+\\..') + required: + - serviceName + type: object + restart: + description: restart specifies the service to + restart, only valid if type is restart + properties: + serviceName: + description: |- + serviceName is the full name (e.g. crio.service) of the service to be restarted + Service names should be of the format ${NAME}${SERVICETYPE} and can up to 255 characters long. + ${NAME} must be atleast 1 character long and can only consist of alphabets, digits, ":", "-", "_", ".", and "\". + ${SERVICETYPE} must be one of ".service", ".socket", ".device", ".mount", ".automount", ".swap", ".target", ".path", ".timer", ".snapshot", ".slice" or ".scope". + maxLength: 255 + type: string + x-kubernetes-validations: + - message: Invalid ${SERVICETYPE} in service + name. Expected format is ${NAME}${SERVICETYPE}, + where ${SERVICETYPE} must be one of ".service", + ".socket", ".device", ".mount", ".automount", + ".swap", ".target", ".path", ".timer",".snapshot", + ".slice" or ".scope". + rule: self.matches('\\.(service|socket|device|mount|automount|swap|target|path|timer|snapshot|slice|scope)$') + - message: Invalid ${NAME} in service name. + Expected format is ${NAME}${SERVICETYPE}, + where {NAME} must be atleast 1 character + long and can only consist of alphabets, + digits, ":", "-", "_", ".", and "\" + rule: self.matches('^[a-zA-Z0-9:._\\\\-]+\\..') + required: + - serviceName + type: object + type: + description: |- + type represents the commands that will be carried out if this NodeDisruptionPolicyStatusActionType is executed + Valid values are Reboot, Drain, Reload, Restart, DaemonReload, None and Special. + reload/restart requires a corresponding service target specified in the reload/restart field. + Other values require no further configuration + enum: + - Reboot + - Drain + - Reload + - Restart + - DaemonReload + - None + - Special + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: reload is required when type is Reload, + and forbidden otherwise + rule: 'has(self.type) && self.type == ''Reload'' + ? has(self.reload) : !has(self.reload)' + - message: restart is required when type is Restart, + and forbidden otherwise + rule: 'has(self.type) && self.type == ''Restart'' + ? has(self.restart) : !has(self.restart)' + maxItems: 10 + type: array + x-kubernetes-list-type: atomic + x-kubernetes-validations: + - message: Reboot action can only be specified standalone, + as it will override any other actions + rule: 'self.exists(x, x.type==''Reboot'') ? size(self) + == 1 : true' + - message: None action can only be specified standalone, + as it will override any other actions + rule: 'self.exists(x, x.type==''None'') ? size(self) + == 1 : true' + path: + description: |- + path is the location of a file being managed through a MachineConfig. + The Actions in the policy will apply to changes to the file at this path. + type: string + required: + - actions + - path + type: object + maxItems: 100 + type: array + x-kubernetes-list-map-keys: + - path + x-kubernetes-list-type: map + sshkey: + description: sshkey is the overall sshkey MachineConfig definition + properties: + actions: + description: |- + actions represents the series of commands to be executed on changes to the file at + the corresponding file path. Actions will be applied in the order that + they are set in this list. If there are other incoming changes to other MachineConfig + entries in the same update that require a reboot, the reboot will supercede these actions. + Valid actions are Reboot, Drain, Reload, DaemonReload and None. + The Reboot action and the None action cannot be used in conjunction with any of the other actions. + This list supports a maximum of 10 entries. + items: + properties: + reload: + description: reload specifies the service to reload, + only valid if type is reload + properties: + serviceName: + description: |- + serviceName is the full name (e.g. crio.service) of the service to be reloaded + Service names should be of the format ${NAME}${SERVICETYPE} and can up to 255 characters long. + ${NAME} must be atleast 1 character long and can only consist of alphabets, digits, ":", "-", "_", ".", and "\". + ${SERVICETYPE} must be one of ".service", ".socket", ".device", ".mount", ".automount", ".swap", ".target", ".path", ".timer", ".snapshot", ".slice" or ".scope". + maxLength: 255 + type: string + x-kubernetes-validations: + - message: Invalid ${SERVICETYPE} in service + name. Expected format is ${NAME}${SERVICETYPE}, + where ${SERVICETYPE} must be one of ".service", + ".socket", ".device", ".mount", ".automount", + ".swap", ".target", ".path", ".timer",".snapshot", + ".slice" or ".scope". + rule: self.matches('\\.(service|socket|device|mount|automount|swap|target|path|timer|snapshot|slice|scope)$') + - message: Invalid ${NAME} in service name. + Expected format is ${NAME}${SERVICETYPE}, + where {NAME} must be atleast 1 character + long and can only consist of alphabets, + digits, ":", "-", "_", ".", and "\" + rule: self.matches('^[a-zA-Z0-9:._\\\\-]+\\..') + required: + - serviceName + type: object + restart: + description: restart specifies the service to restart, + only valid if type is restart + properties: + serviceName: + description: |- + serviceName is the full name (e.g. crio.service) of the service to be restarted + Service names should be of the format ${NAME}${SERVICETYPE} and can up to 255 characters long. + ${NAME} must be atleast 1 character long and can only consist of alphabets, digits, ":", "-", "_", ".", and "\". + ${SERVICETYPE} must be one of ".service", ".socket", ".device", ".mount", ".automount", ".swap", ".target", ".path", ".timer", ".snapshot", ".slice" or ".scope". + maxLength: 255 + type: string + x-kubernetes-validations: + - message: Invalid ${SERVICETYPE} in service + name. Expected format is ${NAME}${SERVICETYPE}, + where ${SERVICETYPE} must be one of ".service", + ".socket", ".device", ".mount", ".automount", + ".swap", ".target", ".path", ".timer",".snapshot", + ".slice" or ".scope". + rule: self.matches('\\.(service|socket|device|mount|automount|swap|target|path|timer|snapshot|slice|scope)$') + - message: Invalid ${NAME} in service name. + Expected format is ${NAME}${SERVICETYPE}, + where {NAME} must be atleast 1 character + long and can only consist of alphabets, + digits, ":", "-", "_", ".", and "\" + rule: self.matches('^[a-zA-Z0-9:._\\\\-]+\\..') + required: + - serviceName + type: object + type: + description: |- + type represents the commands that will be carried out if this NodeDisruptionPolicyStatusActionType is executed + Valid values are Reboot, Drain, Reload, Restart, DaemonReload, None and Special. + reload/restart requires a corresponding service target specified in the reload/restart field. + Other values require no further configuration + enum: + - Reboot + - Drain + - Reload + - Restart + - DaemonReload + - None + - Special + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: reload is required when type is Reload, and + forbidden otherwise + rule: 'has(self.type) && self.type == ''Reload'' ? + has(self.reload) : !has(self.reload)' + - message: restart is required when type is Restart, + and forbidden otherwise + rule: 'has(self.type) && self.type == ''Restart'' + ? has(self.restart) : !has(self.restart)' + maxItems: 10 + type: array + x-kubernetes-list-type: atomic + x-kubernetes-validations: + - message: Reboot action can only be specified standalone, + as it will override any other actions + rule: 'self.exists(x, x.type==''Reboot'') ? size(self) + == 1 : true' + - message: None action can only be specified standalone, + as it will override any other actions + rule: 'self.exists(x, x.type==''None'') ? size(self) + == 1 : true' + required: + - actions + type: object + units: + description: units is a list MachineConfig unit definitions + and actions to take on changes to those services + items: + description: NodeDisruptionPolicyStatusUnit is a systemd + unit name and corresponding actions to take and is used + in the NodeDisruptionPolicyClusterStatus object + properties: + actions: + description: |- + actions represents the series of commands to be executed on changes to the file at + the corresponding file path. Actions will be applied in the order that + they are set in this list. If there are other incoming changes to other MachineConfig + entries in the same update that require a reboot, the reboot will supercede these actions. + Valid actions are Reboot, Drain, Reload, DaemonReload and None. + The Reboot action and the None action cannot be used in conjunction with any of the other actions. + This list supports a maximum of 10 entries. + items: + properties: + reload: + description: reload specifies the service to reload, + only valid if type is reload + properties: + serviceName: + description: |- + serviceName is the full name (e.g. crio.service) of the service to be reloaded + Service names should be of the format ${NAME}${SERVICETYPE} and can up to 255 characters long. + ${NAME} must be atleast 1 character long and can only consist of alphabets, digits, ":", "-", "_", ".", and "\". + ${SERVICETYPE} must be one of ".service", ".socket", ".device", ".mount", ".automount", ".swap", ".target", ".path", ".timer", ".snapshot", ".slice" or ".scope". + maxLength: 255 + type: string + x-kubernetes-validations: + - message: Invalid ${SERVICETYPE} in service + name. Expected format is ${NAME}${SERVICETYPE}, + where ${SERVICETYPE} must be one of ".service", + ".socket", ".device", ".mount", ".automount", + ".swap", ".target", ".path", ".timer",".snapshot", + ".slice" or ".scope". + rule: self.matches('\\.(service|socket|device|mount|automount|swap|target|path|timer|snapshot|slice|scope)$') + - message: Invalid ${NAME} in service name. + Expected format is ${NAME}${SERVICETYPE}, + where {NAME} must be atleast 1 character + long and can only consist of alphabets, + digits, ":", "-", "_", ".", and "\" + rule: self.matches('^[a-zA-Z0-9:._\\\\-]+\\..') + required: + - serviceName + type: object + restart: + description: restart specifies the service to + restart, only valid if type is restart + properties: + serviceName: + description: |- + serviceName is the full name (e.g. crio.service) of the service to be restarted + Service names should be of the format ${NAME}${SERVICETYPE} and can up to 255 characters long. + ${NAME} must be atleast 1 character long and can only consist of alphabets, digits, ":", "-", "_", ".", and "\". + ${SERVICETYPE} must be one of ".service", ".socket", ".device", ".mount", ".automount", ".swap", ".target", ".path", ".timer", ".snapshot", ".slice" or ".scope". + maxLength: 255 + type: string + x-kubernetes-validations: + - message: Invalid ${SERVICETYPE} in service + name. Expected format is ${NAME}${SERVICETYPE}, + where ${SERVICETYPE} must be one of ".service", + ".socket", ".device", ".mount", ".automount", + ".swap", ".target", ".path", ".timer",".snapshot", + ".slice" or ".scope". + rule: self.matches('\\.(service|socket|device|mount|automount|swap|target|path|timer|snapshot|slice|scope)$') + - message: Invalid ${NAME} in service name. + Expected format is ${NAME}${SERVICETYPE}, + where {NAME} must be atleast 1 character + long and can only consist of alphabets, + digits, ":", "-", "_", ".", and "\" + rule: self.matches('^[a-zA-Z0-9:._\\\\-]+\\..') + required: + - serviceName + type: object + type: + description: |- + type represents the commands that will be carried out if this NodeDisruptionPolicyStatusActionType is executed + Valid values are Reboot, Drain, Reload, Restart, DaemonReload, None and Special. + reload/restart requires a corresponding service target specified in the reload/restart field. + Other values require no further configuration + enum: + - Reboot + - Drain + - Reload + - Restart + - DaemonReload + - None + - Special + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: reload is required when type is Reload, + and forbidden otherwise + rule: 'has(self.type) && self.type == ''Reload'' + ? has(self.reload) : !has(self.reload)' + - message: restart is required when type is Restart, + and forbidden otherwise + rule: 'has(self.type) && self.type == ''Restart'' + ? has(self.restart) : !has(self.restart)' + maxItems: 10 + type: array + x-kubernetes-list-type: atomic + x-kubernetes-validations: + - message: Reboot action can only be specified standalone, + as it will override any other actions + rule: 'self.exists(x, x.type==''Reboot'') ? size(self) + == 1 : true' + - message: None action can only be specified standalone, + as it will override any other actions + rule: 'self.exists(x, x.type==''None'') ? size(self) + == 1 : true' + name: + description: |- + name represents the service name of a systemd service managed through a MachineConfig + Actions specified will be applied for changes to the named service. + Service names should be of the format ${NAME}${SERVICETYPE} and can up to 255 characters long. + ${NAME} must be atleast 1 character long and can only consist of alphabets, digits, ":", "-", "_", ".", and "\". + ${SERVICETYPE} must be one of ".service", ".socket", ".device", ".mount", ".automount", ".swap", ".target", ".path", ".timer", ".snapshot", ".slice" or ".scope". + maxLength: 255 + type: string + x-kubernetes-validations: + - message: Invalid ${SERVICETYPE} in service name. Expected + format is ${NAME}${SERVICETYPE}, where ${SERVICETYPE} + must be one of ".service", ".socket", ".device", + ".mount", ".automount", ".swap", ".target", ".path", + ".timer",".snapshot", ".slice" or ".scope". + rule: self.matches('\\.(service|socket|device|mount|automount|swap|target|path|timer|snapshot|slice|scope)$') + - message: Invalid ${NAME} in service name. Expected + format is ${NAME}${SERVICETYPE}, where {NAME} must + be atleast 1 character long and can only consist + of alphabets, digits, ":", "-", "_", ".", and "\" + rule: self.matches('^[a-zA-Z0-9:._\\\\-]+\\..') + required: + - actions + - name + type: object + maxItems: 100 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: object + observedGeneration: + description: observedGeneration is the last generation change you've + dealt with + format: int64 + type: integer + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/operator/v1/zz_generated.swagger_doc_generated.go b/operator/v1/zz_generated.swagger_doc_generated.go index 206dd98c43b..80408d0db70 100644 --- a/operator/v1/zz_generated.swagger_doc_generated.go +++ b/operator/v1/zz_generated.swagger_doc_generated.go @@ -1379,6 +1379,37 @@ func (KubeStorageVersionMigratorList) SwaggerDoc() map[string]string { return map_KubeStorageVersionMigratorList } +var map_BootImageSkewEnforcementConfig = map[string]string{ + "": "BootImageSkewEnforcementConfig is used to configure how boot image version skew is enforced on the cluster.", + "mode": "mode determines the underlying behavior of skew enforcement mechanism. Valid values are Manual and None. Manual means that the cluster admin is expected to perform manual boot image updates and store the OCP & RHCOS version associated with the last boot image update in the manual field. In Manual mode, the MCO will prevent upgrades when the boot image skew exceeds the skew limit described by the release image. None means that the MCO will no longer monitor the boot image skew. This may affect the cluster's ability to scale. This field is required.", + "manual": "manual describes the current boot image of the cluster. This should be set to the oldest boot image used amongst all machine resources in the cluster. This includes the RHCOS version of the boot image and the OCP release version which shipped with that RHCOS boot image. If ocpVersion and rhcosVersion are defined, both values will be used for checking skew compliance. If only ocpVersion is defined, only that value will be used for checking skew compliance. If only rhcosVersion is defined, only that value will be used for checking skew compliance. Required when mode is set to \"Manual\" and forbidden otherwise.", +} + +func (BootImageSkewEnforcementConfig) SwaggerDoc() map[string]string { + return map_BootImageSkewEnforcementConfig +} + +var map_BootImageSkewEnforcementStatus = map[string]string{ + "": "BootImageSkewEnforcementStatus is the type for the status object. It represents the cluster defaults when the boot image skew enforcement configuration is undefined and reflects the actual configuration when it is defined.", + "mode": "mode determines the underlying behavior of skew enforcement mechanism. Valid values are Automatic, Manual and None. Automatic means that the MCO will perform boot image updates and store the OCP & RHCOS version associated with the last boot image update in the automatic field. Manual means that the cluster admin is expected to perform manual boot image updates and store the OCP & RHCOS version associated with the last boot image update in the manual field. In Automatic and Manual mode, the MCO will prevent upgrades when the boot image skew exceeds the skew limit described by the release image. None means that the MCO will no longer monitor the boot image skew. This may affect the cluster's ability to scale. This field is required.", + "automatic": "automatic describes the current boot image of the cluster. This will be populated by the MCO when performing boot image updates. This value will be compared against the cluster's skew limit to determine skew compliance. Required when mode is set to \"Automatic\" and forbidden otherwise.", + "manual": "manual describes the current boot image of the cluster. This will be populated by the MCO using the values provided in the spec.bootImageSkewEnforcement.manual field. This value will be compared against the cluster's skew limit to determine skew compliance. Required when mode is set to \"Manual\" and forbidden otherwise.", +} + +func (BootImageSkewEnforcementStatus) SwaggerDoc() map[string]string { + return map_BootImageSkewEnforcementStatus +} + +var map_ClusterBootImage = map[string]string{ + "": "ClusterBootImage describes the boot image of a cluster. It stores the RHCOS version of the boot image and the OCP release version which shipped with that RHCOS boot image. At least one of these values are required. If ocpVersion and rhcosVersion are defined, both values will be used for checking skew compliance. If only ocpVersion is defined, only that value will be used for checking skew compliance. If only rhcosVersion is defined, only that value will be used for checking skew compliance.", + "ocpVersion": "ocpVersion provides a string which represents the OCP version of the boot image. This field must match the OCP semver compatible format of x.y.z. This field must be between 5 and 10 characters long.", + "rhcosVersion": "rhcosVersion provides a string which represents the RHCOS version of the boot image This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between 14 and 21 characters long.", +} + +func (ClusterBootImage) SwaggerDoc() map[string]string { + return map_ClusterBootImage +} + var map_IrreconcilableValidationOverrides = map[string]string{ "": "IrreconcilableValidationOverrides holds the irreconcilable validations overrides to be applied on each rendered MachineConfig generation.", "storage": "storage can be used to allow making irreconcilable changes to the selected sections under the `spec.config.storage` field of MachineConfig CRs It must have at least one item, may not exceed 3 items and must not contain duplicates. Allowed element values are \"Disks\", \"FileSystems\", \"Raid\" and omitted. When contains \"Disks\" changes to the `spec.config.storage.disks` section of MachineConfig CRs are allowed. When contains \"FileSystems\" changes to the `spec.config.storage.filesystems` section of MachineConfig CRs are allowed. When contains \"Raid\" changes to the `spec.config.storage.raid` section of MachineConfig CRs are allowed. When omitted changes to the `spec.config.storage` section are forbidden.", @@ -1413,6 +1444,7 @@ var map_MachineConfigurationSpec = map[string]string{ "managedBootImages": "managedBootImages allows configuration for the management of boot images for machine resources within the cluster. This configuration allows users to select resources that should be updated to the latest boot images during cluster upgrades, ensuring that new machines always boot with the current cluster version's boot image. When omitted, this means no opinion and the platform is left to choose a reasonable default, which is subject to change over time. The default for each machine manager mode is All for GCP and AWS platforms, and None for all other platforms.", "nodeDisruptionPolicy": "nodeDisruptionPolicy allows an admin to set granular node disruption actions for MachineConfig-based updates, such as drains, service reloads, etc. Specifying this will allow for less downtime when doing small configuration updates to the cluster. This configuration has no effect on cluster upgrades which will still incur node disruption where required.", "irreconcilableValidationOverrides": "irreconcilableValidationOverrides is an optional field that can used to make changes to a MachineConfig that cannot be applied to existing nodes. When specified, the fields configured with validation overrides will no longer reject changes to those respective fields due to them not being able to be applied to existing nodes. Only newly provisioned nodes will have these configurations applied. Existing nodes will report observed configuration differences in their MachineConfigNode status.", + "bootImageSkewEnforcement": "bootImageSkewEnforcement allows an admin to configure how boot image version skew is enforced on the cluster. When omitted, this will default to Automatic for clusters that support automatic boot image updates. For clusters that do not support automatic boot image updates, cluster upgrades will be disabled until a skew enforcement mode has been specified. When version skew is being enforced, cluster upgrades will be disabled until the version skew is deemed acceptable for the current release payload.", } func (MachineConfigurationSpec) SwaggerDoc() map[string]string { @@ -1420,10 +1452,11 @@ func (MachineConfigurationSpec) SwaggerDoc() map[string]string { } var map_MachineConfigurationStatus = map[string]string{ - "observedGeneration": "observedGeneration is the last generation change you've dealt with", - "conditions": "conditions is a list of conditions and their status", - "nodeDisruptionPolicyStatus": "nodeDisruptionPolicyStatus status reflects what the latest cluster-validated policies are, and will be used by the Machine Config Daemon during future node updates.", - "managedBootImagesStatus": "managedBootImagesStatus reflects what the latest cluster-validated boot image configuration is and will be used by Machine Config Controller while performing boot image updates.", + "observedGeneration": "observedGeneration is the last generation change you've dealt with", + "conditions": "conditions is a list of conditions and their status", + "nodeDisruptionPolicyStatus": "nodeDisruptionPolicyStatus status reflects what the latest cluster-validated policies are, and will be used by the Machine Config Daemon during future node updates.", + "managedBootImagesStatus": "managedBootImagesStatus reflects what the latest cluster-validated boot image configuration is and will be used by Machine Config Controller while performing boot image updates.", + "bootImageSkewEnforcementStatus": "bootImageSkewEnforcementStatus reflects what the latest cluster-validated boot image skew enforcement configuration is and will be used by Machine Config Controller while performing boot image skew enforcement. When omitted, the MCO has no knowledge of how to enforce boot image skew. When the MCO does not know how boot image skew should be enforced, cluster upgrades will be blocked until it can either automatically determine skew enforcement or there is an explicit skew enforcement configuration provided in the spec.bootImageSkewEnforcement field.", } func (MachineConfigurationStatus) SwaggerDoc() map[string]string { diff --git a/payload-manifests/crds/0000_80_machine-config_01_machineconfigurations-CustomNoUpgrade.crd.yaml b/payload-manifests/crds/0000_80_machine-config_01_machineconfigurations-CustomNoUpgrade.crd.yaml index da62cb7eec1..cb5697ddff8 100644 --- a/payload-manifests/crds/0000_80_machine-config_01_machineconfigurations-CustomNoUpgrade.crd.yaml +++ b/payload-manifests/crds/0000_80_machine-config_01_machineconfigurations-CustomNoUpgrade.crd.yaml @@ -46,6 +46,78 @@ spec: description: spec is the specification of the desired behavior of the Machine Config Operator properties: + bootImageSkewEnforcement: + description: |- + bootImageSkewEnforcement allows an admin to configure how boot image version skew is + enforced on the cluster. + When omitted, this will default to Automatic for clusters that support automatic boot image updates. + For clusters that do not support automatic boot image updates, cluster upgrades will be disabled until + a skew enforcement mode has been specified. + When version skew is being enforced, cluster upgrades will be disabled until the version skew is deemed + acceptable for the current release payload. + properties: + manual: + description: |- + manual describes the current boot image of the cluster. + This should be set to the oldest boot image used amongst all machine resources in the cluster. + This includes the RHCOS version of the boot image and the OCP release version which shipped with that RHCOS boot image. + If ocpVersion and rhcosVersion are defined, both values will be used for checking skew compliance. + If only ocpVersion is defined, only that value will be used for checking skew compliance. + If only rhcosVersion is defined, only that value will be used for checking skew compliance. + Required when mode is set to "Manual" and forbidden otherwise. + minProperties: 1 + properties: + ocpVersion: + description: |- + ocpVersion provides a string which represents the OCP version of the boot image. + This field must match the OCP semver compatible format of x.y.z. This field must be between + 5 and 10 characters long. + maxLength: 10 + minLength: 5 + type: string + x-kubernetes-validations: + - message: bootImageOCPVersion must match the OCP semver compatible + format of x.y.z + rule: self.matches('^[0-9]+\\.[0-9]+\\.[0-9]+$') + rhcosVersion: + description: |- + rhcosVersion provides a string which represents the RHCOS version of the boot image + This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy + format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between + 14 and 21 characters long. + maxLength: 21 + minLength: 14 + type: string + x-kubernetes-validations: + - message: rhcosVersion must match format [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] + or must match legacy format [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber] + rule: self.matches('^[0-9]+\\.[0-9]+\\.([0-9]{8}|[0-9]{12})-[0-9]+$') + type: object + x-kubernetes-validations: + - message: at least one of ocpVersion or rhcosVersion is required + rule: has(self.ocpVersion) || has(self.rhcosVersion) + mode: + description: |- + mode determines the underlying behavior of skew enforcement mechanism. + Valid values are Manual and None. + Manual means that the cluster admin is expected to perform manual boot image updates and store the OCP + & RHCOS version associated with the last boot image update in the manual field. + In Manual mode, the MCO will prevent upgrades when the boot image skew exceeds the + skew limit described by the release image. + None means that the MCO will no longer monitor the boot image skew. This may affect + the cluster's ability to scale. + This field is required. + enum: + - Manual + - None + type: string + required: + - mode + type: object + x-kubernetes-validations: + - message: manual is required when mode is Manual, and forbidden otherwise + rule: 'has(self.mode) && (self.mode ==''Manual'') ? has(self.manual) + : !has(self.manual)' failedRevisionLimit: description: |- failedRevisionLimit is the number of failed static pod installer revisions to keep on disk and in the api @@ -682,6 +754,118 @@ spec: description: status is the most recently observed status of the Machine Config Operator properties: + bootImageSkewEnforcementStatus: + description: |- + bootImageSkewEnforcementStatus reflects what the latest cluster-validated boot image skew enforcement + configuration is and will be used by Machine Config Controller while performing boot image skew enforcement. + When omitted, the MCO has no knowledge of how to enforce boot image skew. When the MCO does not know how + boot image skew should be enforced, cluster upgrades will be blocked until it can either automatically + determine skew enforcement or there is an explicit skew enforcement configuration provided in the + spec.bootImageSkewEnforcement field. + properties: + automatic: + description: |- + automatic describes the current boot image of the cluster. + This will be populated by the MCO when performing boot image updates. This value will be compared against + the cluster's skew limit to determine skew compliance. + Required when mode is set to "Automatic" and forbidden otherwise. + minProperties: 1 + properties: + ocpVersion: + description: |- + ocpVersion provides a string which represents the OCP version of the boot image. + This field must match the OCP semver compatible format of x.y.z. This field must be between + 5 and 10 characters long. + maxLength: 10 + minLength: 5 + type: string + x-kubernetes-validations: + - message: bootImageOCPVersion must match the OCP semver compatible + format of x.y.z + rule: self.matches('^[0-9]+\\.[0-9]+\\.[0-9]+$') + rhcosVersion: + description: |- + rhcosVersion provides a string which represents the RHCOS version of the boot image + This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy + format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between + 14 and 21 characters long. + maxLength: 21 + minLength: 14 + type: string + x-kubernetes-validations: + - message: rhcosVersion must match format [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] + or must match legacy format [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber] + rule: self.matches('^[0-9]+\\.[0-9]+\\.([0-9]{8}|[0-9]{12})-[0-9]+$') + type: object + x-kubernetes-validations: + - message: at least one of ocpVersion or rhcosVersion is required + rule: has(self.ocpVersion) || has(self.rhcosVersion) + manual: + description: |- + manual describes the current boot image of the cluster. + This will be populated by the MCO using the values provided in the spec.bootImageSkewEnforcement.manual field. + This value will be compared against the cluster's skew limit to determine skew compliance. + Required when mode is set to "Manual" and forbidden otherwise. + minProperties: 1 + properties: + ocpVersion: + description: |- + ocpVersion provides a string which represents the OCP version of the boot image. + This field must match the OCP semver compatible format of x.y.z. This field must be between + 5 and 10 characters long. + maxLength: 10 + minLength: 5 + type: string + x-kubernetes-validations: + - message: bootImageOCPVersion must match the OCP semver compatible + format of x.y.z + rule: self.matches('^[0-9]+\\.[0-9]+\\.[0-9]+$') + rhcosVersion: + description: |- + rhcosVersion provides a string which represents the RHCOS version of the boot image + This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy + format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between + 14 and 21 characters long. + maxLength: 21 + minLength: 14 + type: string + x-kubernetes-validations: + - message: rhcosVersion must match format [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] + or must match legacy format [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber] + rule: self.matches('^[0-9]+\\.[0-9]+\\.([0-9]{8}|[0-9]{12})-[0-9]+$') + type: object + x-kubernetes-validations: + - message: at least one of ocpVersion or rhcosVersion is required + rule: has(self.ocpVersion) || has(self.rhcosVersion) + mode: + description: |- + mode determines the underlying behavior of skew enforcement mechanism. + Valid values are Automatic, Manual and None. + Automatic means that the MCO will perform boot image updates and store the + OCP & RHCOS version associated with the last boot image update in the automatic field. + Manual means that the cluster admin is expected to perform manual boot image updates and store the OCP + & RHCOS version associated with the last boot image update in the manual field. + In Automatic and Manual mode, the MCO will prevent upgrades when the boot image skew exceeds the + skew limit described by the release image. + None means that the MCO will no longer monitor the boot image skew. This may affect + the cluster's ability to scale. + This field is required. + enum: + - Automatic + - Manual + - None + type: string + required: + - mode + type: object + x-kubernetes-validations: + - message: automatic is required when mode is Automatic, and forbidden + otherwise + rule: 'has(self.mode) && (self.mode == ''Automatic'') ? has(self.automatic) + : !has(self.automatic)' + - message: manual is required when mode is Manual, and forbidden otherwise + rule: 'has(self.mode) && (self.mode == ''Manual'') ? has(self.manual) + : !has(self.manual)' conditions: description: conditions is a list of conditions and their status items: diff --git a/payload-manifests/crds/0000_80_machine-config_01_machineconfigurations-DevPreviewNoUpgrade.crd.yaml b/payload-manifests/crds/0000_80_machine-config_01_machineconfigurations-DevPreviewNoUpgrade.crd.yaml index 9062795e78d..a718965803f 100644 --- a/payload-manifests/crds/0000_80_machine-config_01_machineconfigurations-DevPreviewNoUpgrade.crd.yaml +++ b/payload-manifests/crds/0000_80_machine-config_01_machineconfigurations-DevPreviewNoUpgrade.crd.yaml @@ -46,6 +46,78 @@ spec: description: spec is the specification of the desired behavior of the Machine Config Operator properties: + bootImageSkewEnforcement: + description: |- + bootImageSkewEnforcement allows an admin to configure how boot image version skew is + enforced on the cluster. + When omitted, this will default to Automatic for clusters that support automatic boot image updates. + For clusters that do not support automatic boot image updates, cluster upgrades will be disabled until + a skew enforcement mode has been specified. + When version skew is being enforced, cluster upgrades will be disabled until the version skew is deemed + acceptable for the current release payload. + properties: + manual: + description: |- + manual describes the current boot image of the cluster. + This should be set to the oldest boot image used amongst all machine resources in the cluster. + This includes the RHCOS version of the boot image and the OCP release version which shipped with that RHCOS boot image. + If ocpVersion and rhcosVersion are defined, both values will be used for checking skew compliance. + If only ocpVersion is defined, only that value will be used for checking skew compliance. + If only rhcosVersion is defined, only that value will be used for checking skew compliance. + Required when mode is set to "Manual" and forbidden otherwise. + minProperties: 1 + properties: + ocpVersion: + description: |- + ocpVersion provides a string which represents the OCP version of the boot image. + This field must match the OCP semver compatible format of x.y.z. This field must be between + 5 and 10 characters long. + maxLength: 10 + minLength: 5 + type: string + x-kubernetes-validations: + - message: bootImageOCPVersion must match the OCP semver compatible + format of x.y.z + rule: self.matches('^[0-9]+\\.[0-9]+\\.[0-9]+$') + rhcosVersion: + description: |- + rhcosVersion provides a string which represents the RHCOS version of the boot image + This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy + format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between + 14 and 21 characters long. + maxLength: 21 + minLength: 14 + type: string + x-kubernetes-validations: + - message: rhcosVersion must match format [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] + or must match legacy format [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber] + rule: self.matches('^[0-9]+\\.[0-9]+\\.([0-9]{8}|[0-9]{12})-[0-9]+$') + type: object + x-kubernetes-validations: + - message: at least one of ocpVersion or rhcosVersion is required + rule: has(self.ocpVersion) || has(self.rhcosVersion) + mode: + description: |- + mode determines the underlying behavior of skew enforcement mechanism. + Valid values are Manual and None. + Manual means that the cluster admin is expected to perform manual boot image updates and store the OCP + & RHCOS version associated with the last boot image update in the manual field. + In Manual mode, the MCO will prevent upgrades when the boot image skew exceeds the + skew limit described by the release image. + None means that the MCO will no longer monitor the boot image skew. This may affect + the cluster's ability to scale. + This field is required. + enum: + - Manual + - None + type: string + required: + - mode + type: object + x-kubernetes-validations: + - message: manual is required when mode is Manual, and forbidden otherwise + rule: 'has(self.mode) && (self.mode ==''Manual'') ? has(self.manual) + : !has(self.manual)' failedRevisionLimit: description: |- failedRevisionLimit is the number of failed static pod installer revisions to keep on disk and in the api @@ -682,6 +754,118 @@ spec: description: status is the most recently observed status of the Machine Config Operator properties: + bootImageSkewEnforcementStatus: + description: |- + bootImageSkewEnforcementStatus reflects what the latest cluster-validated boot image skew enforcement + configuration is and will be used by Machine Config Controller while performing boot image skew enforcement. + When omitted, the MCO has no knowledge of how to enforce boot image skew. When the MCO does not know how + boot image skew should be enforced, cluster upgrades will be blocked until it can either automatically + determine skew enforcement or there is an explicit skew enforcement configuration provided in the + spec.bootImageSkewEnforcement field. + properties: + automatic: + description: |- + automatic describes the current boot image of the cluster. + This will be populated by the MCO when performing boot image updates. This value will be compared against + the cluster's skew limit to determine skew compliance. + Required when mode is set to "Automatic" and forbidden otherwise. + minProperties: 1 + properties: + ocpVersion: + description: |- + ocpVersion provides a string which represents the OCP version of the boot image. + This field must match the OCP semver compatible format of x.y.z. This field must be between + 5 and 10 characters long. + maxLength: 10 + minLength: 5 + type: string + x-kubernetes-validations: + - message: bootImageOCPVersion must match the OCP semver compatible + format of x.y.z + rule: self.matches('^[0-9]+\\.[0-9]+\\.[0-9]+$') + rhcosVersion: + description: |- + rhcosVersion provides a string which represents the RHCOS version of the boot image + This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy + format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between + 14 and 21 characters long. + maxLength: 21 + minLength: 14 + type: string + x-kubernetes-validations: + - message: rhcosVersion must match format [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] + or must match legacy format [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber] + rule: self.matches('^[0-9]+\\.[0-9]+\\.([0-9]{8}|[0-9]{12})-[0-9]+$') + type: object + x-kubernetes-validations: + - message: at least one of ocpVersion or rhcosVersion is required + rule: has(self.ocpVersion) || has(self.rhcosVersion) + manual: + description: |- + manual describes the current boot image of the cluster. + This will be populated by the MCO using the values provided in the spec.bootImageSkewEnforcement.manual field. + This value will be compared against the cluster's skew limit to determine skew compliance. + Required when mode is set to "Manual" and forbidden otherwise. + minProperties: 1 + properties: + ocpVersion: + description: |- + ocpVersion provides a string which represents the OCP version of the boot image. + This field must match the OCP semver compatible format of x.y.z. This field must be between + 5 and 10 characters long. + maxLength: 10 + minLength: 5 + type: string + x-kubernetes-validations: + - message: bootImageOCPVersion must match the OCP semver compatible + format of x.y.z + rule: self.matches('^[0-9]+\\.[0-9]+\\.[0-9]+$') + rhcosVersion: + description: |- + rhcosVersion provides a string which represents the RHCOS version of the boot image + This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy + format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between + 14 and 21 characters long. + maxLength: 21 + minLength: 14 + type: string + x-kubernetes-validations: + - message: rhcosVersion must match format [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] + or must match legacy format [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber] + rule: self.matches('^[0-9]+\\.[0-9]+\\.([0-9]{8}|[0-9]{12})-[0-9]+$') + type: object + x-kubernetes-validations: + - message: at least one of ocpVersion or rhcosVersion is required + rule: has(self.ocpVersion) || has(self.rhcosVersion) + mode: + description: |- + mode determines the underlying behavior of skew enforcement mechanism. + Valid values are Automatic, Manual and None. + Automatic means that the MCO will perform boot image updates and store the + OCP & RHCOS version associated with the last boot image update in the automatic field. + Manual means that the cluster admin is expected to perform manual boot image updates and store the OCP + & RHCOS version associated with the last boot image update in the manual field. + In Automatic and Manual mode, the MCO will prevent upgrades when the boot image skew exceeds the + skew limit described by the release image. + None means that the MCO will no longer monitor the boot image skew. This may affect + the cluster's ability to scale. + This field is required. + enum: + - Automatic + - Manual + - None + type: string + required: + - mode + type: object + x-kubernetes-validations: + - message: automatic is required when mode is Automatic, and forbidden + otherwise + rule: 'has(self.mode) && (self.mode == ''Automatic'') ? has(self.automatic) + : !has(self.automatic)' + - message: manual is required when mode is Manual, and forbidden otherwise + rule: 'has(self.mode) && (self.mode == ''Manual'') ? has(self.manual) + : !has(self.manual)' conditions: description: conditions is a list of conditions and their status items: From bcad2088d8ac67cbb79b9b4491b62553c66451cf Mon Sep 17 00:00:00 2001 From: David Date: Thu, 11 Sep 2025 15:46:52 -0400 Subject: [PATCH 2/3] cross-validate boot images & skew enforcement --- .../BootImageSkewEnforcement.yaml | 263 +++++++++++++++++- operator/v1/types_machineconfiguration.go | 3 + ...ineconfigurations-CustomNoUpgrade.crd.yaml | 19 ++ ...onfigurations-DevPreviewNoUpgrade.crd.yaml | 19 ++ .../BootImageSkewEnforcement.yaml | 19 ++ ...ineconfigurations-CustomNoUpgrade.crd.yaml | 19 ++ ...onfigurations-DevPreviewNoUpgrade.crd.yaml | 19 ++ 7 files changed, 360 insertions(+), 1 deletion(-) diff --git a/operator/v1/tests/machineconfigurations.operator.openshift.io/BootImageSkewEnforcement.yaml b/operator/v1/tests/machineconfigurations.operator.openshift.io/BootImageSkewEnforcement.yaml index b47641a93b3..c090bed0677 100644 --- a/operator/v1/tests/machineconfigurations.operator.openshift.io/BootImageSkewEnforcement.yaml +++ b/operator/v1/tests/machineconfigurations.operator.openshift.io/BootImageSkewEnforcement.yaml @@ -220,6 +220,12 @@ tests: kind: MachineConfiguration spec: {} status: + managedBootImagesStatus: + machineManagers: + - resource: machinesets + apiGroup: machine.openshift.io + selection: + mode: All bootImageSkewEnforcementStatus: mode: Automatic automatic: @@ -232,8 +238,263 @@ tests: logLevel: Normal operatorLogLevel: Normal status: + managedBootImagesStatus: + machineManagers: + - resource: machinesets + apiGroup: machine.openshift.io + selection: + mode: All bootImageSkewEnforcementStatus: mode: Automatic automatic: ocpVersion: "4.18.2" - rhcosVersion: "416.94.202411201433-0" + rhcosVersion: "416.94.202411201433-0" + - name: Should require boot image configuration to be set to All when bootImageSkewEnforcementStatus.mode is Automatic + initial: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: {} + status: + managedBootImagesStatus: + machineManagers: + - resource: machinesets + apiGroup: machine.openshift.io + selection: + mode: All + bootImageSkewEnforcementStatus: + mode: Automatic + automatic: + ocpVersion: "4.18.2" + rhcosVersion: "416.94.202411201433-0" + updated: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: + managedBootImages: + machineManagers: + - resource: machinesets + apiGroup: machine.openshift.io + selection: + mode: None + status: + managedBootImagesStatus: + machineManagers: + - resource: machinesets + apiGroup: machine.openshift.io + selection: + mode: All + bootImageSkewEnforcementStatus: + mode: Automatic + automatic: + ocpVersion: "4.18.2" + rhcosVersion: "416.94.202411201433-0" + expectedError: "when skew enforcement is in Automatic mode, managedBootImages must contain a MachineManager opting in all MachineAPI MachineSets" + - name: Should not be able to set boot image configuration to an empty list if bootImageSkewEnforcementStatus.mode is set to Automatic + initial: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: {} + status: + managedBootImagesStatus: + machineManagers: + - resource: machinesets + apiGroup: machine.openshift.io + selection: + mode: All + bootImageSkewEnforcementStatus: + mode: Automatic + automatic: + ocpVersion: "4.18.2" + rhcosVersion: "416.94.202411201433-0" + updated: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: + managedBootImages: + machineManagers: + [] + status: + managedBootImagesStatus: + machineManagers: + - resource: machinesets + apiGroup: machine.openshift.io + selection: + mode: All + bootImageSkewEnforcementStatus: + mode: Automatic + automatic: + ocpVersion: "4.18.2" + rhcosVersion: "416.94.202411201433-0" + expectedError: "when skew enforcement is in Automatic mode, managedBootImages must contain a MachineManager opting in all MachineAPI MachineSets" + - name: Should require boot image configuration status to be set to All when bootImageSkewEnforcementStatus.mode is Automatic + initial: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: {} + status: + managedBootImagesStatus: + machineManagers: + - resource: machinesets + apiGroup: machine.openshift.io + selection: + mode: All + bootImageSkewEnforcementStatus: + mode: Automatic + automatic: + ocpVersion: "4.18.2" + rhcosVersion: "416.94.202411201433-0" + updated: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: {} + status: + managedBootImagesStatus: + machineManagers: + - resource: machinesets + apiGroup: machine.openshift.io + selection: + mode: None + bootImageSkewEnforcementStatus: + mode: Automatic + automatic: + ocpVersion: "4.18.2" + rhcosVersion: "416.94.202411201433-0" + expectedStatusError: "when skew enforcement is in Automatic mode, managedBootImagesStatus must contain a MachineManager opting in all MachineAPI MachineSets" + - name: Should be able change boot image configuration if bootImageSkewEnforcementStatus.mode is set to Manual + initial: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: + bootImageSkewEnforcement: + mode: Manual + manual: + ocpVersion: "4.18.2" + rhcosVersion: "9.6.20250523-1" + status: + managedBootImagesStatus: + machineManagers: + - resource: machinesets + apiGroup: machine.openshift.io + selection: + mode: All + bootImageSkewEnforcementStatus: + mode: Manual + manual: + ocpVersion: "4.18.2" + rhcosVersion: "416.94.202411201433-0" + updated: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: + managedBootImages: + machineManagers: + - resource: machinesets + apiGroup: machine.openshift.io + selection: + mode: None + bootImageSkewEnforcement: + mode: Manual + manual: + ocpVersion: "4.18.2" + rhcosVersion: "9.6.20250523-1" + status: + managedBootImagesStatus: + machineManagers: + - resource: machinesets + apiGroup: machine.openshift.io + selection: + mode: All + bootImageSkewEnforcementStatus: + mode: Manual + manual: + ocpVersion: "4.18.2" + rhcosVersion: "416.94.202411201433-0" + expected: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: + logLevel: Normal + operatorLogLevel: Normal + managedBootImages: + machineManagers: + - resource: machinesets + apiGroup: machine.openshift.io + selection: + mode: None + bootImageSkewEnforcement: + mode: Manual + manual: + ocpVersion: "4.18.2" + rhcosVersion: "9.6.20250523-1" + status: + managedBootImagesStatus: + machineManagers: + - resource: machinesets + apiGroup: machine.openshift.io + selection: + mode: All + bootImageSkewEnforcementStatus: + mode: Manual + manual: + ocpVersion: "4.18.2" + rhcosVersion: "416.94.202411201433-0" + - name: Should be able change boot image configuration if bootImageSkewEnforcementStatus.mode is set to None + initial: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: + bootImageSkewEnforcement: + mode: None + status: + managedBootImagesStatus: + machineManagers: + - resource: machinesets + apiGroup: machine.openshift.io + selection: + mode: All + bootImageSkewEnforcementStatus: + mode: None + updated: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: + managedBootImages: + machineManagers: + - resource: machinesets + apiGroup: machine.openshift.io + selection: + mode: None + bootImageSkewEnforcement: + mode: None + status: + managedBootImagesStatus: + machineManagers: + - resource: machinesets + apiGroup: machine.openshift.io + selection: + mode: All + bootImageSkewEnforcementStatus: + mode: None + expected: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: + logLevel: Normal + operatorLogLevel: Normal + managedBootImages: + machineManagers: + - resource: machinesets + apiGroup: machine.openshift.io + selection: + mode: None + bootImageSkewEnforcement: + mode: None + status: + managedBootImagesStatus: + machineManagers: + - resource: machinesets + apiGroup: machine.openshift.io + selection: + mode: All + bootImageSkewEnforcementStatus: + mode: None diff --git a/operator/v1/types_machineconfiguration.go b/operator/v1/types_machineconfiguration.go index 7dd9727375d..74591041571 100644 --- a/operator/v1/types_machineconfiguration.go +++ b/operator/v1/types_machineconfiguration.go @@ -17,6 +17,9 @@ import ( // // Compatibility level 1: Stable within a major release for a minimum of 12 months or 3 minor releases (whichever is longer). // +openshift:compatibility-gen:level=1 +// +openshift:validation:FeatureGateAwareXValidation:featureGate=BootImageSkewEnforcement,rule="self.?status.bootImageSkewEnforcementStatus.mode.orValue(\"\") == 'Automatic' ? self.?spec.managedBootImages.hasValue() || self.?status.managedBootImagesStatus.hasValue() : true",message="when skew enforcement is in Automatic mode, a boot image configuration is required" +// +openshift:validation:FeatureGateAwareXValidation:featureGate=BootImageSkewEnforcement,rule="self.?status.bootImageSkewEnforcementStatus.mode.orValue(\"\") == 'Automatic' ? !(self.?spec.managedBootImages.machineManagers.hasValue()) || self.spec.managedBootImages.machineManagers.exists(m, m.selection.mode == 'All' && m.resource == 'machinesets' && m.apiGroup == 'machine.openshift.io') : true",message="when skew enforcement is in Automatic mode, managedBootImages must contain a MachineManager opting in all MachineAPI MachineSets" +// +openshift:validation:FeatureGateAwareXValidation:featureGate=BootImageSkewEnforcement,rule="self.?status.bootImageSkewEnforcementStatus.mode.orValue(\"\") == 'Automatic' ? !(self.?status.managedBootImagesStatus.machineManagers.hasValue()) || self.status.managedBootImagesStatus.machineManagers.exists(m, m.selection.mode == 'All' && m.resource == 'machinesets' && m.apiGroup == 'machine.openshift.io'): true",message="when skew enforcement is in Automatic mode, managedBootImagesStatus must contain a MachineManager opting in all MachineAPI MachineSets" type MachineConfiguration struct { metav1.TypeMeta `json:",inline"` diff --git a/operator/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfigurations-CustomNoUpgrade.crd.yaml b/operator/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfigurations-CustomNoUpgrade.crd.yaml index cb5697ddff8..6980ce10765 100644 --- a/operator/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfigurations-CustomNoUpgrade.crd.yaml +++ b/operator/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfigurations-CustomNoUpgrade.crd.yaml @@ -1460,6 +1460,25 @@ spec: required: - spec type: object + x-kubernetes-validations: + - message: when skew enforcement is in Automatic mode, a boot image configuration + is required + rule: 'self.?status.bootImageSkewEnforcementStatus.mode.orValue("") == ''Automatic'' + ? self.?spec.managedBootImages.hasValue() || self.?status.managedBootImagesStatus.hasValue() + : true' + - message: when skew enforcement is in Automatic mode, managedBootImages must + contain a MachineManager opting in all MachineAPI MachineSets + rule: 'self.?status.bootImageSkewEnforcementStatus.mode.orValue("") == ''Automatic'' + ? !(self.?spec.managedBootImages.machineManagers.hasValue()) || self.spec.managedBootImages.machineManagers.exists(m, + m.selection.mode == ''All'' && m.resource == ''machinesets'' && m.apiGroup + == ''machine.openshift.io'') : true' + - message: when skew enforcement is in Automatic mode, managedBootImagesStatus + must contain a MachineManager opting in all MachineAPI MachineSets + rule: 'self.?status.bootImageSkewEnforcementStatus.mode.orValue("") == ''Automatic'' + ? !(self.?status.managedBootImagesStatus.machineManagers.hasValue()) || + self.status.managedBootImagesStatus.machineManagers.exists(m, m.selection.mode + == ''All'' && m.resource == ''machinesets'' && m.apiGroup == ''machine.openshift.io''): + true' served: true storage: true subresources: diff --git a/operator/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfigurations-DevPreviewNoUpgrade.crd.yaml b/operator/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfigurations-DevPreviewNoUpgrade.crd.yaml index a718965803f..899cc92b44b 100644 --- a/operator/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfigurations-DevPreviewNoUpgrade.crd.yaml +++ b/operator/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfigurations-DevPreviewNoUpgrade.crd.yaml @@ -1460,6 +1460,25 @@ spec: required: - spec type: object + x-kubernetes-validations: + - message: when skew enforcement is in Automatic mode, a boot image configuration + is required + rule: 'self.?status.bootImageSkewEnforcementStatus.mode.orValue("") == ''Automatic'' + ? self.?spec.managedBootImages.hasValue() || self.?status.managedBootImagesStatus.hasValue() + : true' + - message: when skew enforcement is in Automatic mode, managedBootImages must + contain a MachineManager opting in all MachineAPI MachineSets + rule: 'self.?status.bootImageSkewEnforcementStatus.mode.orValue("") == ''Automatic'' + ? !(self.?spec.managedBootImages.machineManagers.hasValue()) || self.spec.managedBootImages.machineManagers.exists(m, + m.selection.mode == ''All'' && m.resource == ''machinesets'' && m.apiGroup + == ''machine.openshift.io'') : true' + - message: when skew enforcement is in Automatic mode, managedBootImagesStatus + must contain a MachineManager opting in all MachineAPI MachineSets + rule: 'self.?status.bootImageSkewEnforcementStatus.mode.orValue("") == ''Automatic'' + ? !(self.?status.managedBootImagesStatus.machineManagers.hasValue()) || + self.status.managedBootImagesStatus.machineManagers.exists(m, m.selection.mode + == ''All'' && m.resource == ''machinesets'' && m.apiGroup == ''machine.openshift.io''): + true' served: true storage: true subresources: diff --git a/operator/v1/zz_generated.featuregated-crd-manifests/machineconfigurations.operator.openshift.io/BootImageSkewEnforcement.yaml b/operator/v1/zz_generated.featuregated-crd-manifests/machineconfigurations.operator.openshift.io/BootImageSkewEnforcement.yaml index 50537a244c0..8bfed9933ef 100644 --- a/operator/v1/zz_generated.featuregated-crd-manifests/machineconfigurations.operator.openshift.io/BootImageSkewEnforcement.yaml +++ b/operator/v1/zz_generated.featuregated-crd-manifests/machineconfigurations.operator.openshift.io/BootImageSkewEnforcement.yaml @@ -1174,6 +1174,25 @@ spec: required: - spec type: object + x-kubernetes-validations: + - message: when skew enforcement is in Automatic mode, a boot image configuration + is required + rule: 'self.?status.bootImageSkewEnforcementStatus.mode.orValue("") == ''Automatic'' + ? self.?spec.managedBootImages.hasValue() || self.?status.managedBootImagesStatus.hasValue() + : true' + - message: when skew enforcement is in Automatic mode, managedBootImages must + contain a MachineManager opting in all MachineAPI MachineSets + rule: 'self.?status.bootImageSkewEnforcementStatus.mode.orValue("") == ''Automatic'' + ? !(self.?spec.managedBootImages.machineManagers.hasValue()) || self.spec.managedBootImages.machineManagers.exists(m, + m.selection.mode == ''All'' && m.resource == ''machinesets'' && m.apiGroup + == ''machine.openshift.io'') : true' + - message: when skew enforcement is in Automatic mode, managedBootImagesStatus + must contain a MachineManager opting in all MachineAPI MachineSets + rule: 'self.?status.bootImageSkewEnforcementStatus.mode.orValue("") == ''Automatic'' + ? !(self.?status.managedBootImagesStatus.machineManagers.hasValue()) || + self.status.managedBootImagesStatus.machineManagers.exists(m, m.selection.mode + == ''All'' && m.resource == ''machinesets'' && m.apiGroup == ''machine.openshift.io''): + true' served: true storage: true subresources: diff --git a/payload-manifests/crds/0000_80_machine-config_01_machineconfigurations-CustomNoUpgrade.crd.yaml b/payload-manifests/crds/0000_80_machine-config_01_machineconfigurations-CustomNoUpgrade.crd.yaml index cb5697ddff8..6980ce10765 100644 --- a/payload-manifests/crds/0000_80_machine-config_01_machineconfigurations-CustomNoUpgrade.crd.yaml +++ b/payload-manifests/crds/0000_80_machine-config_01_machineconfigurations-CustomNoUpgrade.crd.yaml @@ -1460,6 +1460,25 @@ spec: required: - spec type: object + x-kubernetes-validations: + - message: when skew enforcement is in Automatic mode, a boot image configuration + is required + rule: 'self.?status.bootImageSkewEnforcementStatus.mode.orValue("") == ''Automatic'' + ? self.?spec.managedBootImages.hasValue() || self.?status.managedBootImagesStatus.hasValue() + : true' + - message: when skew enforcement is in Automatic mode, managedBootImages must + contain a MachineManager opting in all MachineAPI MachineSets + rule: 'self.?status.bootImageSkewEnforcementStatus.mode.orValue("") == ''Automatic'' + ? !(self.?spec.managedBootImages.machineManagers.hasValue()) || self.spec.managedBootImages.machineManagers.exists(m, + m.selection.mode == ''All'' && m.resource == ''machinesets'' && m.apiGroup + == ''machine.openshift.io'') : true' + - message: when skew enforcement is in Automatic mode, managedBootImagesStatus + must contain a MachineManager opting in all MachineAPI MachineSets + rule: 'self.?status.bootImageSkewEnforcementStatus.mode.orValue("") == ''Automatic'' + ? !(self.?status.managedBootImagesStatus.machineManagers.hasValue()) || + self.status.managedBootImagesStatus.machineManagers.exists(m, m.selection.mode + == ''All'' && m.resource == ''machinesets'' && m.apiGroup == ''machine.openshift.io''): + true' served: true storage: true subresources: diff --git a/payload-manifests/crds/0000_80_machine-config_01_machineconfigurations-DevPreviewNoUpgrade.crd.yaml b/payload-manifests/crds/0000_80_machine-config_01_machineconfigurations-DevPreviewNoUpgrade.crd.yaml index a718965803f..899cc92b44b 100644 --- a/payload-manifests/crds/0000_80_machine-config_01_machineconfigurations-DevPreviewNoUpgrade.crd.yaml +++ b/payload-manifests/crds/0000_80_machine-config_01_machineconfigurations-DevPreviewNoUpgrade.crd.yaml @@ -1460,6 +1460,25 @@ spec: required: - spec type: object + x-kubernetes-validations: + - message: when skew enforcement is in Automatic mode, a boot image configuration + is required + rule: 'self.?status.bootImageSkewEnforcementStatus.mode.orValue("") == ''Automatic'' + ? self.?spec.managedBootImages.hasValue() || self.?status.managedBootImagesStatus.hasValue() + : true' + - message: when skew enforcement is in Automatic mode, managedBootImages must + contain a MachineManager opting in all MachineAPI MachineSets + rule: 'self.?status.bootImageSkewEnforcementStatus.mode.orValue("") == ''Automatic'' + ? !(self.?spec.managedBootImages.machineManagers.hasValue()) || self.spec.managedBootImages.machineManagers.exists(m, + m.selection.mode == ''All'' && m.resource == ''machinesets'' && m.apiGroup + == ''machine.openshift.io'') : true' + - message: when skew enforcement is in Automatic mode, managedBootImagesStatus + must contain a MachineManager opting in all MachineAPI MachineSets + rule: 'self.?status.bootImageSkewEnforcementStatus.mode.orValue("") == ''Automatic'' + ? !(self.?status.managedBootImagesStatus.machineManagers.hasValue()) || + self.status.managedBootImagesStatus.machineManagers.exists(m, m.selection.mode + == ''All'' && m.resource == ''machinesets'' && m.apiGroup == ''machine.openshift.io''): + true' served: true storage: true subresources: From 08bfa12c37f91264e66ff52de2b69971200834d7 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 19 Sep 2025 13:08:36 -0400 Subject: [PATCH 3/3] add union discriminator for manual mode --- .../generated_openapi/zz_generated.openapi.go | 67 +++++- openapi/openapi.json | 42 +++- .../BootImageSkewEnforcement.yaml | 190 ++++++++++++++---- operator/v1/types_machineconfiguration.go | 70 ++++++- ...ineconfigurations-CustomNoUpgrade.crd.yaml | 68 +++++-- ...onfigurations-DevPreviewNoUpgrade.crd.yaml | 68 +++++-- operator/v1/zz_generated.deepcopy.go | 24 ++- .../BootImageSkewEnforcement.yaml | 68 +++++-- .../v1/zz_generated.swagger_doc_generated.go | 21 +- ...ineconfigurations-CustomNoUpgrade.crd.yaml | 68 +++++-- ...onfigurations-DevPreviewNoUpgrade.crd.yaml | 68 +++++-- 11 files changed, 612 insertions(+), 142 deletions(-) diff --git a/openapi/generated_openapi/zz_generated.openapi.go b/openapi/generated_openapi/zz_generated.openapi.go index 1938bcdf604..bdac81c1608 100644 --- a/openapi/generated_openapi/zz_generated.openapi.go +++ b/openapi/generated_openapi/zz_generated.openapi.go @@ -936,7 +936,8 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/openshift/api/operator/v1.CloudCredentialList": schema_openshift_api_operator_v1_CloudCredentialList(ref), "github.com/openshift/api/operator/v1.CloudCredentialSpec": schema_openshift_api_operator_v1_CloudCredentialSpec(ref), "github.com/openshift/api/operator/v1.CloudCredentialStatus": schema_openshift_api_operator_v1_CloudCredentialStatus(ref), - "github.com/openshift/api/operator/v1.ClusterBootImage": schema_openshift_api_operator_v1_ClusterBootImage(ref), + "github.com/openshift/api/operator/v1.ClusterBootImageAutomatic": schema_openshift_api_operator_v1_ClusterBootImageAutomatic(ref), + "github.com/openshift/api/operator/v1.ClusterBootImageManual": schema_openshift_api_operator_v1_ClusterBootImageManual(ref), "github.com/openshift/api/operator/v1.ClusterCSIDriver": schema_openshift_api_operator_v1_ClusterCSIDriver(ref), "github.com/openshift/api/operator/v1.ClusterCSIDriverList": schema_openshift_api_operator_v1_ClusterCSIDriverList(ref), "github.com/openshift/api/operator/v1.ClusterCSIDriverSpec": schema_openshift_api_operator_v1_ClusterCSIDriverSpec(ref), @@ -46946,9 +46947,9 @@ func schema_openshift_api_operator_v1_BootImageSkewEnforcementConfig(ref common. }, "manual": { SchemaProps: spec.SchemaProps{ - Description: "manual describes the current boot image of the cluster. This should be set to the oldest boot image used amongst all machine resources in the cluster. This includes the RHCOS version of the boot image and the OCP release version which shipped with that RHCOS boot image. If ocpVersion and rhcosVersion are defined, both values will be used for checking skew compliance. If only ocpVersion is defined, only that value will be used for checking skew compliance. If only rhcosVersion is defined, only that value will be used for checking skew compliance. Required when mode is set to \"Manual\" and forbidden otherwise.", + Description: "manual describes the current boot image of the cluster. This should be set to the oldest boot image used amongst all machine resources in the cluster. This must include either the RHCOS version of the boot image or the OCP release version which shipped with that RHCOS boot image. Required when mode is set to \"Manual\" and forbidden otherwise.", Default: map[string]interface{}{}, - Ref: ref("github.com/openshift/api/operator/v1.ClusterBootImage"), + Ref: ref("github.com/openshift/api/operator/v1.ClusterBootImageManual"), }, }, }, @@ -46968,7 +46969,7 @@ func schema_openshift_api_operator_v1_BootImageSkewEnforcementConfig(ref common. }, }, Dependencies: []string{ - "github.com/openshift/api/operator/v1.ClusterBootImage"}, + "github.com/openshift/api/operator/v1.ClusterBootImageManual"}, } } @@ -46990,14 +46991,14 @@ func schema_openshift_api_operator_v1_BootImageSkewEnforcementStatus(ref common. SchemaProps: spec.SchemaProps{ Description: "automatic describes the current boot image of the cluster. This will be populated by the MCO when performing boot image updates. This value will be compared against the cluster's skew limit to determine skew compliance. Required when mode is set to \"Automatic\" and forbidden otherwise.", Default: map[string]interface{}{}, - Ref: ref("github.com/openshift/api/operator/v1.ClusterBootImage"), + Ref: ref("github.com/openshift/api/operator/v1.ClusterBootImageAutomatic"), }, }, "manual": { SchemaProps: spec.SchemaProps{ Description: "manual describes the current boot image of the cluster. This will be populated by the MCO using the values provided in the spec.bootImageSkewEnforcement.manual field. This value will be compared against the cluster's skew limit to determine skew compliance. Required when mode is set to \"Manual\" and forbidden otherwise.", Default: map[string]interface{}{}, - Ref: ref("github.com/openshift/api/operator/v1.ClusterBootImage"), + Ref: ref("github.com/openshift/api/operator/v1.ClusterBootImageManual"), }, }, }, @@ -47018,7 +47019,7 @@ func schema_openshift_api_operator_v1_BootImageSkewEnforcementStatus(ref common. }, }, Dependencies: []string{ - "github.com/openshift/api/operator/v1.ClusterBootImage"}, + "github.com/openshift/api/operator/v1.ClusterBootImageAutomatic", "github.com/openshift/api/operator/v1.ClusterBootImageManual"}, } } @@ -47695,11 +47696,11 @@ func schema_openshift_api_operator_v1_CloudCredentialStatus(ref common.Reference } } -func schema_openshift_api_operator_v1_ClusterBootImage(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openshift_api_operator_v1_ClusterBootImageAutomatic(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ClusterBootImage describes the boot image of a cluster. It stores the RHCOS version of the boot image and the OCP release version which shipped with that RHCOS boot image. At least one of these values are required. If ocpVersion and rhcosVersion are defined, both values will be used for checking skew compliance. If only ocpVersion is defined, only that value will be used for checking skew compliance. If only rhcosVersion is defined, only that value will be used for checking skew compliance.", + Description: "ClusterBootImageAutomatic is used to describe the cluster boot image in Automatic mode. It stores the RHCOS version of the boot image and the OCP release version which shipped with that RHCOS boot image. At least one of these values are required. If ocpVersion and rhcosVersion are defined, both values will be used for checking skew compliance. If only ocpVersion is defined, only that value will be used for checking skew compliance. If only rhcosVersion is defined, only that value will be used for checking skew compliance.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "ocpVersion": { @@ -47722,6 +47723,54 @@ func schema_openshift_api_operator_v1_ClusterBootImage(ref common.ReferenceCallb } } +func schema_openshift_api_operator_v1_ClusterBootImageManual(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ClusterBootImageManual is used to describe the cluster boot image in Manual mode.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "mode": { + SchemaProps: spec.SchemaProps{ + Description: "mode is used to configure which boot image field is defined in Manual mode. Valid values are OCPVersion and RHCOSVersion. OCPVersion means that the cluster admin is expected to set the OCP version associated with the last boot image update in the OCPVersion field. RHCOSVersion means that the cluster admin is expected to set the RHCOS version associated with the last boot image update in the RHCOSVersion field. This field is required.", + Type: []string{"string"}, + Format: "", + }, + }, + "ocpVersion": { + SchemaProps: spec.SchemaProps{ + Description: "ocpVersion provides a string which represents the OCP version of the boot image. This field must match the OCP semver compatible format of x.y.z. This field must be between 5 and 10 characters long. Required when mode is set to \"OCPVersion\" and forbidden otherwise.", + Type: []string{"string"}, + Format: "", + }, + }, + "rhcosVersion": { + SchemaProps: spec.SchemaProps{ + Description: "rhcosVersion provides a string which represents the RHCOS version of the boot image This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between 14 and 21 characters long. Required when mode is set to \"RHCOSVersion\" and forbidden otherwise.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"mode"}, + }, + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-unions": []interface{}{ + map[string]interface{}{ + "discriminator": "mode", + "fields-to-discriminateBy": map[string]interface{}{ + "ocpVersion": "OCPVersion", + "rhcosVersion": "RHCOSVersion", + }, + }, + }, + }, + }, + }, + } +} + func schema_openshift_api_operator_v1_ClusterCSIDriver(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/openapi/openapi.json b/openapi/openapi.json index 10429079ade..c3d8e5bac49 100644 --- a/openapi/openapi.json +++ b/openapi/openapi.json @@ -27206,9 +27206,9 @@ ], "properties": { "manual": { - "description": "manual describes the current boot image of the cluster. This should be set to the oldest boot image used amongst all machine resources in the cluster. This includes the RHCOS version of the boot image and the OCP release version which shipped with that RHCOS boot image. If ocpVersion and rhcosVersion are defined, both values will be used for checking skew compliance. If only ocpVersion is defined, only that value will be used for checking skew compliance. If only rhcosVersion is defined, only that value will be used for checking skew compliance. Required when mode is set to \"Manual\" and forbidden otherwise.", + "description": "manual describes the current boot image of the cluster. This should be set to the oldest boot image used amongst all machine resources in the cluster. This must include either the RHCOS version of the boot image or the OCP release version which shipped with that RHCOS boot image. Required when mode is set to \"Manual\" and forbidden otherwise.", "default": {}, - "$ref": "#/definitions/com.github.openshift.api.operator.v1.ClusterBootImage" + "$ref": "#/definitions/com.github.openshift.api.operator.v1.ClusterBootImageManual" }, "mode": { "description": "mode determines the underlying behavior of skew enforcement mechanism. Valid values are Manual and None. Manual means that the cluster admin is expected to perform manual boot image updates and store the OCP & RHCOS version associated with the last boot image update in the manual field. In Manual mode, the MCO will prevent upgrades when the boot image skew exceeds the skew limit described by the release image. None means that the MCO will no longer monitor the boot image skew. This may affect the cluster's ability to scale. This field is required.", @@ -27234,12 +27234,12 @@ "automatic": { "description": "automatic describes the current boot image of the cluster. This will be populated by the MCO when performing boot image updates. This value will be compared against the cluster's skew limit to determine skew compliance. Required when mode is set to \"Automatic\" and forbidden otherwise.", "default": {}, - "$ref": "#/definitions/com.github.openshift.api.operator.v1.ClusterBootImage" + "$ref": "#/definitions/com.github.openshift.api.operator.v1.ClusterBootImageAutomatic" }, "manual": { "description": "manual describes the current boot image of the cluster. This will be populated by the MCO using the values provided in the spec.bootImageSkewEnforcement.manual field. This value will be compared against the cluster's skew limit to determine skew compliance. Required when mode is set to \"Manual\" and forbidden otherwise.", "default": {}, - "$ref": "#/definitions/com.github.openshift.api.operator.v1.ClusterBootImage" + "$ref": "#/definitions/com.github.openshift.api.operator.v1.ClusterBootImageManual" }, "mode": { "description": "mode determines the underlying behavior of skew enforcement mechanism. Valid values are Automatic, Manual and None. Automatic means that the MCO will perform boot image updates and store the OCP & RHCOS version associated with the last boot image update in the automatic field. Manual means that the cluster admin is expected to perform manual boot image updates and store the OCP & RHCOS version associated with the last boot image update in the manual field. In Automatic and Manual mode, the MCO will prevent upgrades when the boot image skew exceeds the skew limit described by the release image. None means that the MCO will no longer monitor the boot image skew. This may affect the cluster's ability to scale. This field is required.", @@ -27662,8 +27662,8 @@ } } }, - "com.github.openshift.api.operator.v1.ClusterBootImage": { - "description": "ClusterBootImage describes the boot image of a cluster. It stores the RHCOS version of the boot image and the OCP release version which shipped with that RHCOS boot image. At least one of these values are required. If ocpVersion and rhcosVersion are defined, both values will be used for checking skew compliance. If only ocpVersion is defined, only that value will be used for checking skew compliance. If only rhcosVersion is defined, only that value will be used for checking skew compliance.", + "com.github.openshift.api.operator.v1.ClusterBootImageAutomatic": { + "description": "ClusterBootImageAutomatic is used to describe the cluster boot image in Automatic mode. It stores the RHCOS version of the boot image and the OCP release version which shipped with that RHCOS boot image. At least one of these values are required. If ocpVersion and rhcosVersion are defined, both values will be used for checking skew compliance. If only ocpVersion is defined, only that value will be used for checking skew compliance. If only rhcosVersion is defined, only that value will be used for checking skew compliance.", "type": "object", "properties": { "ocpVersion": { @@ -27676,6 +27676,36 @@ } } }, + "com.github.openshift.api.operator.v1.ClusterBootImageManual": { + "description": "ClusterBootImageManual is used to describe the cluster boot image in Manual mode.", + "type": "object", + "required": [ + "mode" + ], + "properties": { + "mode": { + "description": "mode is used to configure which boot image field is defined in Manual mode. Valid values are OCPVersion and RHCOSVersion. OCPVersion means that the cluster admin is expected to set the OCP version associated with the last boot image update in the OCPVersion field. RHCOSVersion means that the cluster admin is expected to set the RHCOS version associated with the last boot image update in the RHCOSVersion field. This field is required.", + "type": "string" + }, + "ocpVersion": { + "description": "ocpVersion provides a string which represents the OCP version of the boot image. This field must match the OCP semver compatible format of x.y.z. This field must be between 5 and 10 characters long. Required when mode is set to \"OCPVersion\" and forbidden otherwise.", + "type": "string" + }, + "rhcosVersion": { + "description": "rhcosVersion provides a string which represents the RHCOS version of the boot image This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between 14 and 21 characters long. Required when mode is set to \"RHCOSVersion\" and forbidden otherwise.", + "type": "string" + } + }, + "x-kubernetes-unions": [ + { + "discriminator": "mode", + "fields-to-discriminateBy": { + "ocpVersion": "OCPVersion", + "rhcosVersion": "RHCOSVersion" + } + } + ] + }, "com.github.openshift.api.operator.v1.ClusterCSIDriver": { "description": "ClusterCSIDriver object allows management and configuration of a CSI driver operator installed by default in OpenShift. Name of the object must be name of the CSI driver it operates. See CSIDriverName type for list of allowed values.\n\nCompatibility level 1: Stable within a major release for a minimum of 12 months or 3 minor releases (whichever is longer).", "type": "object", diff --git a/operator/v1/tests/machineconfigurations.operator.openshift.io/BootImageSkewEnforcement.yaml b/operator/v1/tests/machineconfigurations.operator.openshift.io/BootImageSkewEnforcement.yaml index c090bed0677..a9aa8253f9f 100644 --- a/operator/v1/tests/machineconfigurations.operator.openshift.io/BootImageSkewEnforcement.yaml +++ b/operator/v1/tests/machineconfigurations.operator.openshift.io/BootImageSkewEnforcement.yaml @@ -16,7 +16,15 @@ tests: spec: logLevel: Normal operatorLogLevel: Normal - - name: Should be able to create a manual BootImageSkewEnforcement configuration knob + - name: Should not be able to create an automatic BootImageSkewEnforcement configuration knob + initial: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: + bootImageSkewEnforcement: + mode: Automatic + expectedError: "Unsupported value: \"Automatic\": supported values: \"Manual\", \"None\"" + - name: Should be able to create a manual BootImageSkewEnforcement configuration knob with only ocpVersion defined initial: | apiVersion: operator.openshift.io/v1 kind: MachineConfiguration @@ -24,8 +32,8 @@ tests: bootImageSkewEnforcement: mode: Manual manual: + mode: OCPVersion ocpVersion: "4.18.2" - rhcosVersion: "9.6.20250523-1" expected: | apiVersion: operator.openshift.io/v1 kind: MachineConfiguration @@ -35,17 +43,9 @@ tests: bootImageSkewEnforcement: mode: Manual manual: + mode: OCPVersion ocpVersion: "4.18.2" - rhcosVersion: "9.6.20250523-1" - - name: Should not be able to create an automatic BootImageSkewEnforcement configuration knob - initial: | - apiVersion: operator.openshift.io/v1 - kind: MachineConfiguration - spec: - bootImageSkewEnforcement: - mode: Automatic - expectedError: "Unsupported value: \"Automatic\": supported values: \"Manual\", \"None\"" - - name: Should be able to create a manual BootImageSkewEnforcement configuration knob with a legacy cluster boot image + - name: Should be able to create a manual BootImageSkewEnforcement configuration knob with only rhcosVersion defined initial: | apiVersion: operator.openshift.io/v1 kind: MachineConfiguration @@ -53,7 +53,7 @@ tests: bootImageSkewEnforcement: mode: Manual manual: - ocpVersion: "4.18.2" + mode: RHCOSVersion rhcosVersion: "416.94.202411201433-0" expected: | apiVersion: operator.openshift.io/v1 @@ -64,9 +64,9 @@ tests: bootImageSkewEnforcement: mode: Manual manual: - ocpVersion: "4.18.2" + mode: RHCOSVersion rhcosVersion: "416.94.202411201433-0" - - name: Should be able to create a manual BootImageSkewEnforcement configuration knob with only ocpVersion defined + - name: Should not be able to create a manual BootImageSkewEnforcement configuration knob with rhcosVersion defined in OCPVersion mode initial: | apiVersion: operator.openshift.io/v1 kind: MachineConfiguration @@ -74,18 +74,23 @@ tests: bootImageSkewEnforcement: mode: Manual manual: + mode: OCPVersion ocpVersion: "4.18.2" - expected: | + rhcosVersion: "416.94.202411201433-0" + expectedError: "rhcosVersion is required when mode is RHCOSVersion, and forbidden otherwise" + - name: Should not be able to create a manual BootImageSkewEnforcement configuration knob with ocpVersion defined in RHCOSVersion mode + initial: | apiVersion: operator.openshift.io/v1 kind: MachineConfiguration spec: - logLevel: Normal - operatorLogLevel: Normal bootImageSkewEnforcement: mode: Manual manual: + mode: RHCOSVersion ocpVersion: "4.18.2" - - name: Should be able to create a manual BootImageSkewEnforcement configuration knob with only rhcosVersion defined + rhcosVersion: "416.94.202411201433-0" + expectedError: "ocpVersion is required when mode is OCPVersion, and forbidden otherwise" + - name: Should not be able to create a manual BootImageSkewEnforcement configuration knob with an invalid ocpVersion initial: | apiVersion: operator.openshift.io/v1 kind: MachineConfiguration @@ -93,17 +98,20 @@ tests: bootImageSkewEnforcement: mode: Manual manual: - rhcosVersion: "416.94.202411201433-0" - expected: | + mode: OCPVersion + ocpVersion: "4.18" + expectedError: "ocpVersion must match the OCP semver compatible format of x.y.z" + - name: Should not be able to create a manual BootImageSkewEnforcement configuration knob with an invalid rhcosVersion + initial: | apiVersion: operator.openshift.io/v1 kind: MachineConfiguration spec: - logLevel: Normal - operatorLogLevel: Normal bootImageSkewEnforcement: mode: Manual manual: - rhcosVersion: "416.94.202411201433-0" + mode: RHCOSVersion + rhcosVersion: "416.94.2024112021-0" + expectedError: "rhcosVersion must match format [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or must match legacy format [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]" - name: Should be able to create a None BootImageSkewEnforcement configuration knob initial: | apiVersion: operator.openshift.io/v1 @@ -127,8 +135,8 @@ tests: bootImageSkewEnforcement: mode: None manual: - ocpVersion: "4.18.2" - rhcosVersion: "9.6.20250523-1" + mode: RHCOSVersion + rhcosVersion: "416.94.202411201433-0" expectedError: "manual is required when mode is Manual, and forbidden otherwise" - name: manual field should be set if bootImageSkewEnforcement.mode is set to Manual initial: | @@ -155,8 +163,8 @@ tests: bootImageSkewEnforcementStatus: mode: None manual: - ocpVersion: "4.18.2" - rhcosVersion: "9.6.20250523-1" + mode: RHCOSVersion + rhcosVersion: "416.94.202411201433-0" expectedStatusError: "manual is required when mode is Manual, and forbidden otherwise" - name: Should not able to add automatic field in status if bootImageSkewEnforcementStatus.mode is set to None initial: | @@ -193,8 +201,8 @@ tests: bootImageSkewEnforcementStatus: mode: Manual manual: - ocpVersion: "4.18.2" - rhcosVersion: "9.6.20250523-1" + mode: RHCOSVersion + rhcosVersion: "416.94.202411201433-0" expected: | apiVersion: operator.openshift.io/v1 kind: MachineConfiguration @@ -205,8 +213,48 @@ tests: bootImageSkewEnforcementStatus: mode: Manual manual: + mode: RHCOSVersion + rhcosVersion: "416.94.202411201433-0" + - name: Should not be able to add a rhcosVersion field when bootImageSkewEnforcementStatus.mode.manual.mode is set to OCPVersion + initial: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: {} + status: + bootImageSkewEnforcementStatus: + mode: None + updated: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: {} + status: + bootImageSkewEnforcementStatus: + mode: Manual + manual: + mode: OCPVersion + ocpVersion: "4.18.2" + rhcosVersion: "416.94.202411201433-0" + expectedStatusError: "rhcosVersion is required when mode is RHCOSVersion, and forbidden otherwise" + - name: Should not be able to add a ocpVersion field when bootImageSkewEnforcementStatus.mode.manual.mode is set to RHCOSVersion + initial: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: {} + status: + bootImageSkewEnforcementStatus: + mode: None + updated: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: {} + status: + bootImageSkewEnforcementStatus: + mode: Manual + manual: + mode: RHCOSVersion ocpVersion: "4.18.2" - rhcosVersion: "9.6.20250523-1" + rhcosVersion: "416.94.202411201433-0" + expectedStatusError: "ocpVersion is required when mode is OCPVersion, and forbidden otherwise" - name: Should be able to add automatic field in status if bootImageSkewEnforcementStatus.mode is set to automatic initial: | apiVersion: operator.openshift.io/v1 @@ -368,8 +416,8 @@ tests: bootImageSkewEnforcement: mode: Manual manual: - ocpVersion: "4.18.2" - rhcosVersion: "9.6.20250523-1" + mode: RHCOSVersion + rhcosVersion: "416.94.202411201433-0" status: managedBootImagesStatus: machineManagers: @@ -380,8 +428,8 @@ tests: bootImageSkewEnforcementStatus: mode: Manual manual: + mode: OCPVersion ocpVersion: "4.18.2" - rhcosVersion: "416.94.202411201433-0" updated: | apiVersion: operator.openshift.io/v1 kind: MachineConfiguration @@ -395,8 +443,8 @@ tests: bootImageSkewEnforcement: mode: Manual manual: - ocpVersion: "4.18.2" - rhcosVersion: "9.6.20250523-1" + mode: RHCOSVersion + rhcosVersion: "416.94.202411201433-0" status: managedBootImagesStatus: machineManagers: @@ -407,8 +455,8 @@ tests: bootImageSkewEnforcementStatus: mode: Manual manual: + mode: OCPVersion ocpVersion: "4.18.2" - rhcosVersion: "416.94.202411201433-0" expected: | apiVersion: operator.openshift.io/v1 kind: MachineConfiguration @@ -424,8 +472,8 @@ tests: bootImageSkewEnforcement: mode: Manual manual: - ocpVersion: "4.18.2" - rhcosVersion: "9.6.20250523-1" + mode: RHCOSVersion + rhcosVersion: "416.94.202411201433-0" status: managedBootImagesStatus: machineManagers: @@ -436,8 +484,8 @@ tests: bootImageSkewEnforcementStatus: mode: Manual manual: - ocpVersion: "4.18.2" - rhcosVersion: "416.94.202411201433-0" + mode: OCPVersion + ocpVersion: "4.18.2" - name: Should be able change boot image configuration if bootImageSkewEnforcementStatus.mode is set to None initial: | apiVersion: operator.openshift.io/v1 @@ -497,4 +545,62 @@ tests: selection: mode: All bootImageSkewEnforcementStatus: - mode: None + mode: None + - name: Should not be able to update an automatic bootImageSkewEnforcementStatus.mode with an invalid ocpVersion + initial: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: {} + status: + managedBootImagesStatus: + machineManagers: + - resource: machinesets + apiGroup: machine.openshift.io + selection: + mode: All + updated: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: {} + status: + managedBootImagesStatus: + machineManagers: + - resource: machinesets + apiGroup: machine.openshift.io + selection: + mode: All + bootImageSkewEnforcementStatus: + mode: Automatic + automatic: + ocpVersion: "4.18" + rhcosVersion: "416.94.202411201433-0" + expectedStatusError: "ocpVersion must match the OCP semver compatible format of x.y.z" + - name: Should not be able to update an automatic bootImageSkewEnforcementStatus.mode with an invalid rhcosVersion + initial: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: {} + status: + managedBootImagesStatus: + machineManagers: + - resource: machinesets + apiGroup: machine.openshift.io + selection: + mode: All + updated: | + apiVersion: operator.openshift.io/v1 + kind: MachineConfiguration + spec: {} + status: + managedBootImagesStatus: + machineManagers: + - resource: machinesets + apiGroup: machine.openshift.io + selection: + mode: All + bootImageSkewEnforcementStatus: + mode: Automatic + automatic: + ocpVersion: "4.18" + rhcosVersion: "416.94.2024112021-0" + expectedStatusError: "rhcosVersion must match format [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or must match legacy format [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]" diff --git a/operator/v1/types_machineconfiguration.go b/operator/v1/types_machineconfiguration.go index 74591041571..489887af726 100644 --- a/operator/v1/types_machineconfiguration.go +++ b/operator/v1/types_machineconfiguration.go @@ -98,15 +98,63 @@ type BootImageSkewEnforcementConfig struct { // manual describes the current boot image of the cluster. // This should be set to the oldest boot image used amongst all machine resources in the cluster. - // This includes the RHCOS version of the boot image and the OCP release version which shipped with that RHCOS boot image. - // If ocpVersion and rhcosVersion are defined, both values will be used for checking skew compliance. - // If only ocpVersion is defined, only that value will be used for checking skew compliance. - // If only rhcosVersion is defined, only that value will be used for checking skew compliance. + // This must include either the RHCOS version of the boot image or the OCP release version which shipped with that + // RHCOS boot image. // Required when mode is set to "Manual" and forbidden otherwise. // +optional - Manual ClusterBootImage `json:"manual,omitempty,omitzero"` + Manual ClusterBootImageManual `json:"manual,omitempty,omitzero"` } +// ClusterBootImageManual is used to describe the cluster boot image in Manual mode. +// +kubebuilder:validation:XValidation:rule="has(self.mode) && (self.mode =='OCPVersion') ? has(self.ocpVersion) : !has(self.ocpVersion)",message="ocpVersion is required when mode is OCPVersion, and forbidden otherwise" +// +kubebuilder:validation:XValidation:rule="has(self.mode) && (self.mode =='RHCOSVersion') ? has(self.rhcosVersion) : !has(self.rhcosVersion)",message="rhcosVersion is required when mode is RHCOSVersion, and forbidden otherwise" +// +union +type ClusterBootImageManual struct { + // mode is used to configure which boot image field is defined in Manual mode. + // Valid values are OCPVersion and RHCOSVersion. + // OCPVersion means that the cluster admin is expected to set the OCP version associated with the last boot image update + // in the OCPVersion field. + // RHCOSVersion means that the cluster admin is expected to set the RHCOS version associated with the last boot image update + // in the RHCOSVersion field. + // This field is required. + // +unionDiscriminator + // +required + Mode ClusterBootImageManualMode `json:"mode,omitempty"` + + // ocpVersion provides a string which represents the OCP version of the boot image. + // This field must match the OCP semver compatible format of x.y.z. This field must be between + // 5 and 10 characters long. + // Required when mode is set to "OCPVersion" and forbidden otherwise. + // +kubebuilder:validation:XValidation:rule="self.matches('^[0-9]+\\\\.[0-9]+\\\\.[0-9]+$')",message="ocpVersion must match the OCP semver compatible format of x.y.z" + // +kubebuilder:validation:MaxLength:=10 + // +kubebuilder:validation:MinLength:=5 + // +optional + OCPVersion string `json:"ocpVersion,omitempty"` + + // rhcosVersion provides a string which represents the RHCOS version of the boot image + // This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy + // format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between + // 14 and 21 characters long. + // Required when mode is set to "RHCOSVersion" and forbidden otherwise. + // +kubebuilder:validation:XValidation:rule="self.matches('^[0-9]+\\\\.[0-9]+\\\\.([0-9]{8}|[0-9]{12})-[0-9]+$')",message="rhcosVersion must match format [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or must match legacy format [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]" + // +kubebuilder:validation:MaxLength:=21 + // +kubebuilder:validation:MinLength:=14 + // +optional + RHCOSVersion string `json:"rhcosVersion,omitempty"` +} + +// ClusterBootImageManualMode is a string enum used to define the cluster's boot image in manual mode. +// +kubebuilder:validation:Enum:="OCPVersion";"RHCOSVersion" +type ClusterBootImageManualMode string + +const ( + // OCPVersion represents a configuration mode used to define the OCPVersion. + ClusterBootImageSpecModeOCPVersion ClusterBootImageManualMode = "OCPVersion" + + // RHCOSVersion represents a configuration mode used to define the RHCOSVersion. + ClusterBootImageSpecModeRHCOSVersion ClusterBootImageManualMode = "RHCOSVersion" +) + // BootImageSkewEnforcementStatus is the type for the status object. It represents the cluster defaults when // the boot image skew enforcement configuration is undefined and reflects the actual configuration when it is defined. // +kubebuilder:validation:XValidation:rule="has(self.mode) && (self.mode == 'Automatic') ? has(self.automatic) : !has(self.automatic)",message="automatic is required when mode is Automatic, and forbidden otherwise" @@ -133,28 +181,28 @@ type BootImageSkewEnforcementStatus struct { // the cluster's skew limit to determine skew compliance. // Required when mode is set to "Automatic" and forbidden otherwise. // +optional - Automatic ClusterBootImage `json:"automatic,omitempty,omitzero"` + Automatic ClusterBootImageAutomatic `json:"automatic,omitempty,omitzero"` // manual describes the current boot image of the cluster. // This will be populated by the MCO using the values provided in the spec.bootImageSkewEnforcement.manual field. // This value will be compared against the cluster's skew limit to determine skew compliance. // Required when mode is set to "Manual" and forbidden otherwise. // +optional - Manual ClusterBootImage `json:"manual,omitempty,omitzero"` + Manual ClusterBootImageManual `json:"manual,omitempty,omitzero"` } -// ClusterBootImage describes the boot image of a cluster. It stores the RHCOS version of the boot image and -// the OCP release version which shipped with that RHCOS boot image. At least one of these values are required. +// ClusterBootImageAutomatic is used to describe the cluster boot image in Automatic mode. It stores the RHCOS version of the +// boot image and the OCP release version which shipped with that RHCOS boot image. At least one of these values are required. // If ocpVersion and rhcosVersion are defined, both values will be used for checking skew compliance. // If only ocpVersion is defined, only that value will be used for checking skew compliance. // If only rhcosVersion is defined, only that value will be used for checking skew compliance. // +kubebuilder:validation:XValidation:rule="has(self.ocpVersion) || has(self.rhcosVersion)",message="at least one of ocpVersion or rhcosVersion is required" // +kubebuilder:validation:MinProperties=1 -type ClusterBootImage struct { +type ClusterBootImageAutomatic struct { // ocpVersion provides a string which represents the OCP version of the boot image. // This field must match the OCP semver compatible format of x.y.z. This field must be between // 5 and 10 characters long. - // +kubebuilder:validation:XValidation:rule="self.matches('^[0-9]+\\\\.[0-9]+\\\\.[0-9]+$')",message="bootImageOCPVersion must match the OCP semver compatible format of x.y.z" + // +kubebuilder:validation:XValidation:rule="self.matches('^[0-9]+\\\\.[0-9]+\\\\.[0-9]+$')",message="ocpVersion must match the OCP semver compatible format of x.y.z" // +kubebuilder:validation:MaxLength:=10 // +kubebuilder:validation:MinLength:=5 // +optional diff --git a/operator/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfigurations-CustomNoUpgrade.crd.yaml b/operator/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfigurations-CustomNoUpgrade.crd.yaml index 6980ce10765..a4fe0264ea0 100644 --- a/operator/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfigurations-CustomNoUpgrade.crd.yaml +++ b/operator/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfigurations-CustomNoUpgrade.crd.yaml @@ -60,23 +60,34 @@ spec: description: |- manual describes the current boot image of the cluster. This should be set to the oldest boot image used amongst all machine resources in the cluster. - This includes the RHCOS version of the boot image and the OCP release version which shipped with that RHCOS boot image. - If ocpVersion and rhcosVersion are defined, both values will be used for checking skew compliance. - If only ocpVersion is defined, only that value will be used for checking skew compliance. - If only rhcosVersion is defined, only that value will be used for checking skew compliance. + This must include either the RHCOS version of the boot image or the OCP release version which shipped with that + RHCOS boot image. Required when mode is set to "Manual" and forbidden otherwise. - minProperties: 1 properties: + mode: + description: |- + mode is used to configure which boot image field is defined in Manual mode. + Valid values are OCPVersion and RHCOSVersion. + OCPVersion means that the cluster admin is expected to set the OCP version associated with the last boot image update + in the OCPVersion field. + RHCOSVersion means that the cluster admin is expected to set the RHCOS version associated with the last boot image update + in the RHCOSVersion field. + This field is required. + enum: + - OCPVersion + - RHCOSVersion + type: string ocpVersion: description: |- ocpVersion provides a string which represents the OCP version of the boot image. This field must match the OCP semver compatible format of x.y.z. This field must be between 5 and 10 characters long. + Required when mode is set to "OCPVersion" and forbidden otherwise. maxLength: 10 minLength: 5 type: string x-kubernetes-validations: - - message: bootImageOCPVersion must match the OCP semver compatible + - message: ocpVersion must match the OCP semver compatible format of x.y.z rule: self.matches('^[0-9]+\\.[0-9]+\\.[0-9]+$') rhcosVersion: @@ -85,6 +96,7 @@ spec: This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between 14 and 21 characters long. + Required when mode is set to "RHCOSVersion" and forbidden otherwise. maxLength: 21 minLength: 14 type: string @@ -92,10 +104,18 @@ spec: - message: rhcosVersion must match format [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or must match legacy format [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber] rule: self.matches('^[0-9]+\\.[0-9]+\\.([0-9]{8}|[0-9]{12})-[0-9]+$') + required: + - mode type: object x-kubernetes-validations: - - message: at least one of ocpVersion or rhcosVersion is required - rule: has(self.ocpVersion) || has(self.rhcosVersion) + - message: ocpVersion is required when mode is OCPVersion, and + forbidden otherwise + rule: 'has(self.mode) && (self.mode ==''OCPVersion'') ? has(self.ocpVersion) + : !has(self.ocpVersion)' + - message: rhcosVersion is required when mode is RHCOSVersion, + and forbidden otherwise + rule: 'has(self.mode) && (self.mode ==''RHCOSVersion'') ? has(self.rhcosVersion) + : !has(self.rhcosVersion)' mode: description: |- mode determines the underlying behavior of skew enforcement mechanism. @@ -780,7 +800,7 @@ spec: minLength: 5 type: string x-kubernetes-validations: - - message: bootImageOCPVersion must match the OCP semver compatible + - message: ocpVersion must match the OCP semver compatible format of x.y.z rule: self.matches('^[0-9]+\\.[0-9]+\\.[0-9]+$') rhcosVersion: @@ -806,18 +826,31 @@ spec: This will be populated by the MCO using the values provided in the spec.bootImageSkewEnforcement.manual field. This value will be compared against the cluster's skew limit to determine skew compliance. Required when mode is set to "Manual" and forbidden otherwise. - minProperties: 1 properties: + mode: + description: |- + mode is used to configure which boot image field is defined in Manual mode. + Valid values are OCPVersion and RHCOSVersion. + OCPVersion means that the cluster admin is expected to set the OCP version associated with the last boot image update + in the OCPVersion field. + RHCOSVersion means that the cluster admin is expected to set the RHCOS version associated with the last boot image update + in the RHCOSVersion field. + This field is required. + enum: + - OCPVersion + - RHCOSVersion + type: string ocpVersion: description: |- ocpVersion provides a string which represents the OCP version of the boot image. This field must match the OCP semver compatible format of x.y.z. This field must be between 5 and 10 characters long. + Required when mode is set to "OCPVersion" and forbidden otherwise. maxLength: 10 minLength: 5 type: string x-kubernetes-validations: - - message: bootImageOCPVersion must match the OCP semver compatible + - message: ocpVersion must match the OCP semver compatible format of x.y.z rule: self.matches('^[0-9]+\\.[0-9]+\\.[0-9]+$') rhcosVersion: @@ -826,6 +859,7 @@ spec: This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between 14 and 21 characters long. + Required when mode is set to "RHCOSVersion" and forbidden otherwise. maxLength: 21 minLength: 14 type: string @@ -833,10 +867,18 @@ spec: - message: rhcosVersion must match format [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or must match legacy format [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber] rule: self.matches('^[0-9]+\\.[0-9]+\\.([0-9]{8}|[0-9]{12})-[0-9]+$') + required: + - mode type: object x-kubernetes-validations: - - message: at least one of ocpVersion or rhcosVersion is required - rule: has(self.ocpVersion) || has(self.rhcosVersion) + - message: ocpVersion is required when mode is OCPVersion, and + forbidden otherwise + rule: 'has(self.mode) && (self.mode ==''OCPVersion'') ? has(self.ocpVersion) + : !has(self.ocpVersion)' + - message: rhcosVersion is required when mode is RHCOSVersion, + and forbidden otherwise + rule: 'has(self.mode) && (self.mode ==''RHCOSVersion'') ? has(self.rhcosVersion) + : !has(self.rhcosVersion)' mode: description: |- mode determines the underlying behavior of skew enforcement mechanism. diff --git a/operator/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfigurations-DevPreviewNoUpgrade.crd.yaml b/operator/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfigurations-DevPreviewNoUpgrade.crd.yaml index 899cc92b44b..5ef1733d145 100644 --- a/operator/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfigurations-DevPreviewNoUpgrade.crd.yaml +++ b/operator/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfigurations-DevPreviewNoUpgrade.crd.yaml @@ -60,23 +60,34 @@ spec: description: |- manual describes the current boot image of the cluster. This should be set to the oldest boot image used amongst all machine resources in the cluster. - This includes the RHCOS version of the boot image and the OCP release version which shipped with that RHCOS boot image. - If ocpVersion and rhcosVersion are defined, both values will be used for checking skew compliance. - If only ocpVersion is defined, only that value will be used for checking skew compliance. - If only rhcosVersion is defined, only that value will be used for checking skew compliance. + This must include either the RHCOS version of the boot image or the OCP release version which shipped with that + RHCOS boot image. Required when mode is set to "Manual" and forbidden otherwise. - minProperties: 1 properties: + mode: + description: |- + mode is used to configure which boot image field is defined in Manual mode. + Valid values are OCPVersion and RHCOSVersion. + OCPVersion means that the cluster admin is expected to set the OCP version associated with the last boot image update + in the OCPVersion field. + RHCOSVersion means that the cluster admin is expected to set the RHCOS version associated with the last boot image update + in the RHCOSVersion field. + This field is required. + enum: + - OCPVersion + - RHCOSVersion + type: string ocpVersion: description: |- ocpVersion provides a string which represents the OCP version of the boot image. This field must match the OCP semver compatible format of x.y.z. This field must be between 5 and 10 characters long. + Required when mode is set to "OCPVersion" and forbidden otherwise. maxLength: 10 minLength: 5 type: string x-kubernetes-validations: - - message: bootImageOCPVersion must match the OCP semver compatible + - message: ocpVersion must match the OCP semver compatible format of x.y.z rule: self.matches('^[0-9]+\\.[0-9]+\\.[0-9]+$') rhcosVersion: @@ -85,6 +96,7 @@ spec: This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between 14 and 21 characters long. + Required when mode is set to "RHCOSVersion" and forbidden otherwise. maxLength: 21 minLength: 14 type: string @@ -92,10 +104,18 @@ spec: - message: rhcosVersion must match format [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or must match legacy format [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber] rule: self.matches('^[0-9]+\\.[0-9]+\\.([0-9]{8}|[0-9]{12})-[0-9]+$') + required: + - mode type: object x-kubernetes-validations: - - message: at least one of ocpVersion or rhcosVersion is required - rule: has(self.ocpVersion) || has(self.rhcosVersion) + - message: ocpVersion is required when mode is OCPVersion, and + forbidden otherwise + rule: 'has(self.mode) && (self.mode ==''OCPVersion'') ? has(self.ocpVersion) + : !has(self.ocpVersion)' + - message: rhcosVersion is required when mode is RHCOSVersion, + and forbidden otherwise + rule: 'has(self.mode) && (self.mode ==''RHCOSVersion'') ? has(self.rhcosVersion) + : !has(self.rhcosVersion)' mode: description: |- mode determines the underlying behavior of skew enforcement mechanism. @@ -780,7 +800,7 @@ spec: minLength: 5 type: string x-kubernetes-validations: - - message: bootImageOCPVersion must match the OCP semver compatible + - message: ocpVersion must match the OCP semver compatible format of x.y.z rule: self.matches('^[0-9]+\\.[0-9]+\\.[0-9]+$') rhcosVersion: @@ -806,18 +826,31 @@ spec: This will be populated by the MCO using the values provided in the spec.bootImageSkewEnforcement.manual field. This value will be compared against the cluster's skew limit to determine skew compliance. Required when mode is set to "Manual" and forbidden otherwise. - minProperties: 1 properties: + mode: + description: |- + mode is used to configure which boot image field is defined in Manual mode. + Valid values are OCPVersion and RHCOSVersion. + OCPVersion means that the cluster admin is expected to set the OCP version associated with the last boot image update + in the OCPVersion field. + RHCOSVersion means that the cluster admin is expected to set the RHCOS version associated with the last boot image update + in the RHCOSVersion field. + This field is required. + enum: + - OCPVersion + - RHCOSVersion + type: string ocpVersion: description: |- ocpVersion provides a string which represents the OCP version of the boot image. This field must match the OCP semver compatible format of x.y.z. This field must be between 5 and 10 characters long. + Required when mode is set to "OCPVersion" and forbidden otherwise. maxLength: 10 minLength: 5 type: string x-kubernetes-validations: - - message: bootImageOCPVersion must match the OCP semver compatible + - message: ocpVersion must match the OCP semver compatible format of x.y.z rule: self.matches('^[0-9]+\\.[0-9]+\\.[0-9]+$') rhcosVersion: @@ -826,6 +859,7 @@ spec: This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between 14 and 21 characters long. + Required when mode is set to "RHCOSVersion" and forbidden otherwise. maxLength: 21 minLength: 14 type: string @@ -833,10 +867,18 @@ spec: - message: rhcosVersion must match format [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or must match legacy format [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber] rule: self.matches('^[0-9]+\\.[0-9]+\\.([0-9]{8}|[0-9]{12})-[0-9]+$') + required: + - mode type: object x-kubernetes-validations: - - message: at least one of ocpVersion or rhcosVersion is required - rule: has(self.ocpVersion) || has(self.rhcosVersion) + - message: ocpVersion is required when mode is OCPVersion, and + forbidden otherwise + rule: 'has(self.mode) && (self.mode ==''OCPVersion'') ? has(self.ocpVersion) + : !has(self.ocpVersion)' + - message: rhcosVersion is required when mode is RHCOSVersion, + and forbidden otherwise + rule: 'has(self.mode) && (self.mode ==''RHCOSVersion'') ? has(self.rhcosVersion) + : !has(self.rhcosVersion)' mode: description: |- mode determines the underlying behavior of skew enforcement mechanism. diff --git a/operator/v1/zz_generated.deepcopy.go b/operator/v1/zz_generated.deepcopy.go index d8594ff5452..fd83694c23f 100644 --- a/operator/v1/zz_generated.deepcopy.go +++ b/operator/v1/zz_generated.deepcopy.go @@ -712,17 +712,33 @@ func (in *CloudCredentialStatus) DeepCopy() *CloudCredentialStatus { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ClusterBootImage) DeepCopyInto(out *ClusterBootImage) { +func (in *ClusterBootImageAutomatic) DeepCopyInto(out *ClusterBootImageAutomatic) { *out = *in return } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterBootImage. -func (in *ClusterBootImage) DeepCopy() *ClusterBootImage { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterBootImageAutomatic. +func (in *ClusterBootImageAutomatic) DeepCopy() *ClusterBootImageAutomatic { if in == nil { return nil } - out := new(ClusterBootImage) + out := new(ClusterBootImageAutomatic) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterBootImageManual) DeepCopyInto(out *ClusterBootImageManual) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterBootImageManual. +func (in *ClusterBootImageManual) DeepCopy() *ClusterBootImageManual { + if in == nil { + return nil + } + out := new(ClusterBootImageManual) in.DeepCopyInto(out) return out } diff --git a/operator/v1/zz_generated.featuregated-crd-manifests/machineconfigurations.operator.openshift.io/BootImageSkewEnforcement.yaml b/operator/v1/zz_generated.featuregated-crd-manifests/machineconfigurations.operator.openshift.io/BootImageSkewEnforcement.yaml index 8bfed9933ef..82e320556b0 100644 --- a/operator/v1/zz_generated.featuregated-crd-manifests/machineconfigurations.operator.openshift.io/BootImageSkewEnforcement.yaml +++ b/operator/v1/zz_generated.featuregated-crd-manifests/machineconfigurations.operator.openshift.io/BootImageSkewEnforcement.yaml @@ -60,23 +60,34 @@ spec: description: |- manual describes the current boot image of the cluster. This should be set to the oldest boot image used amongst all machine resources in the cluster. - This includes the RHCOS version of the boot image and the OCP release version which shipped with that RHCOS boot image. - If ocpVersion and rhcosVersion are defined, both values will be used for checking skew compliance. - If only ocpVersion is defined, only that value will be used for checking skew compliance. - If only rhcosVersion is defined, only that value will be used for checking skew compliance. + This must include either the RHCOS version of the boot image or the OCP release version which shipped with that + RHCOS boot image. Required when mode is set to "Manual" and forbidden otherwise. - minProperties: 1 properties: + mode: + description: |- + mode is used to configure which boot image field is defined in Manual mode. + Valid values are OCPVersion and RHCOSVersion. + OCPVersion means that the cluster admin is expected to set the OCP version associated with the last boot image update + in the OCPVersion field. + RHCOSVersion means that the cluster admin is expected to set the RHCOS version associated with the last boot image update + in the RHCOSVersion field. + This field is required. + enum: + - OCPVersion + - RHCOSVersion + type: string ocpVersion: description: |- ocpVersion provides a string which represents the OCP version of the boot image. This field must match the OCP semver compatible format of x.y.z. This field must be between 5 and 10 characters long. + Required when mode is set to "OCPVersion" and forbidden otherwise. maxLength: 10 minLength: 5 type: string x-kubernetes-validations: - - message: bootImageOCPVersion must match the OCP semver compatible + - message: ocpVersion must match the OCP semver compatible format of x.y.z rule: self.matches('^[0-9]+\\.[0-9]+\\.[0-9]+$') rhcosVersion: @@ -85,6 +96,7 @@ spec: This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between 14 and 21 characters long. + Required when mode is set to "RHCOSVersion" and forbidden otherwise. maxLength: 21 minLength: 14 type: string @@ -92,10 +104,18 @@ spec: - message: rhcosVersion must match format [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or must match legacy format [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber] rule: self.matches('^[0-9]+\\.[0-9]+\\.([0-9]{8}|[0-9]{12})-[0-9]+$') + required: + - mode type: object x-kubernetes-validations: - - message: at least one of ocpVersion or rhcosVersion is required - rule: has(self.ocpVersion) || has(self.rhcosVersion) + - message: ocpVersion is required when mode is OCPVersion, and + forbidden otherwise + rule: 'has(self.mode) && (self.mode ==''OCPVersion'') ? has(self.ocpVersion) + : !has(self.ocpVersion)' + - message: rhcosVersion is required when mode is RHCOSVersion, + and forbidden otherwise + rule: 'has(self.mode) && (self.mode ==''RHCOSVersion'') ? has(self.rhcosVersion) + : !has(self.rhcosVersion)' mode: description: |- mode determines the underlying behavior of skew enforcement mechanism. @@ -618,7 +638,7 @@ spec: minLength: 5 type: string x-kubernetes-validations: - - message: bootImageOCPVersion must match the OCP semver compatible + - message: ocpVersion must match the OCP semver compatible format of x.y.z rule: self.matches('^[0-9]+\\.[0-9]+\\.[0-9]+$') rhcosVersion: @@ -644,18 +664,31 @@ spec: This will be populated by the MCO using the values provided in the spec.bootImageSkewEnforcement.manual field. This value will be compared against the cluster's skew limit to determine skew compliance. Required when mode is set to "Manual" and forbidden otherwise. - minProperties: 1 properties: + mode: + description: |- + mode is used to configure which boot image field is defined in Manual mode. + Valid values are OCPVersion and RHCOSVersion. + OCPVersion means that the cluster admin is expected to set the OCP version associated with the last boot image update + in the OCPVersion field. + RHCOSVersion means that the cluster admin is expected to set the RHCOS version associated with the last boot image update + in the RHCOSVersion field. + This field is required. + enum: + - OCPVersion + - RHCOSVersion + type: string ocpVersion: description: |- ocpVersion provides a string which represents the OCP version of the boot image. This field must match the OCP semver compatible format of x.y.z. This field must be between 5 and 10 characters long. + Required when mode is set to "OCPVersion" and forbidden otherwise. maxLength: 10 minLength: 5 type: string x-kubernetes-validations: - - message: bootImageOCPVersion must match the OCP semver compatible + - message: ocpVersion must match the OCP semver compatible format of x.y.z rule: self.matches('^[0-9]+\\.[0-9]+\\.[0-9]+$') rhcosVersion: @@ -664,6 +697,7 @@ spec: This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between 14 and 21 characters long. + Required when mode is set to "RHCOSVersion" and forbidden otherwise. maxLength: 21 minLength: 14 type: string @@ -671,10 +705,18 @@ spec: - message: rhcosVersion must match format [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or must match legacy format [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber] rule: self.matches('^[0-9]+\\.[0-9]+\\.([0-9]{8}|[0-9]{12})-[0-9]+$') + required: + - mode type: object x-kubernetes-validations: - - message: at least one of ocpVersion or rhcosVersion is required - rule: has(self.ocpVersion) || has(self.rhcosVersion) + - message: ocpVersion is required when mode is OCPVersion, and + forbidden otherwise + rule: 'has(self.mode) && (self.mode ==''OCPVersion'') ? has(self.ocpVersion) + : !has(self.ocpVersion)' + - message: rhcosVersion is required when mode is RHCOSVersion, + and forbidden otherwise + rule: 'has(self.mode) && (self.mode ==''RHCOSVersion'') ? has(self.rhcosVersion) + : !has(self.rhcosVersion)' mode: description: |- mode determines the underlying behavior of skew enforcement mechanism. diff --git a/operator/v1/zz_generated.swagger_doc_generated.go b/operator/v1/zz_generated.swagger_doc_generated.go index 80408d0db70..be0185eda9b 100644 --- a/operator/v1/zz_generated.swagger_doc_generated.go +++ b/operator/v1/zz_generated.swagger_doc_generated.go @@ -1382,7 +1382,7 @@ func (KubeStorageVersionMigratorList) SwaggerDoc() map[string]string { var map_BootImageSkewEnforcementConfig = map[string]string{ "": "BootImageSkewEnforcementConfig is used to configure how boot image version skew is enforced on the cluster.", "mode": "mode determines the underlying behavior of skew enforcement mechanism. Valid values are Manual and None. Manual means that the cluster admin is expected to perform manual boot image updates and store the OCP & RHCOS version associated with the last boot image update in the manual field. In Manual mode, the MCO will prevent upgrades when the boot image skew exceeds the skew limit described by the release image. None means that the MCO will no longer monitor the boot image skew. This may affect the cluster's ability to scale. This field is required.", - "manual": "manual describes the current boot image of the cluster. This should be set to the oldest boot image used amongst all machine resources in the cluster. This includes the RHCOS version of the boot image and the OCP release version which shipped with that RHCOS boot image. If ocpVersion and rhcosVersion are defined, both values will be used for checking skew compliance. If only ocpVersion is defined, only that value will be used for checking skew compliance. If only rhcosVersion is defined, only that value will be used for checking skew compliance. Required when mode is set to \"Manual\" and forbidden otherwise.", + "manual": "manual describes the current boot image of the cluster. This should be set to the oldest boot image used amongst all machine resources in the cluster. This must include either the RHCOS version of the boot image or the OCP release version which shipped with that RHCOS boot image. Required when mode is set to \"Manual\" and forbidden otherwise.", } func (BootImageSkewEnforcementConfig) SwaggerDoc() map[string]string { @@ -1400,14 +1400,25 @@ func (BootImageSkewEnforcementStatus) SwaggerDoc() map[string]string { return map_BootImageSkewEnforcementStatus } -var map_ClusterBootImage = map[string]string{ - "": "ClusterBootImage describes the boot image of a cluster. It stores the RHCOS version of the boot image and the OCP release version which shipped with that RHCOS boot image. At least one of these values are required. If ocpVersion and rhcosVersion are defined, both values will be used for checking skew compliance. If only ocpVersion is defined, only that value will be used for checking skew compliance. If only rhcosVersion is defined, only that value will be used for checking skew compliance.", +var map_ClusterBootImageAutomatic = map[string]string{ + "": "ClusterBootImageAutomatic is used to describe the cluster boot image in Automatic mode. It stores the RHCOS version of the boot image and the OCP release version which shipped with that RHCOS boot image. At least one of these values are required. If ocpVersion and rhcosVersion are defined, both values will be used for checking skew compliance. If only ocpVersion is defined, only that value will be used for checking skew compliance. If only rhcosVersion is defined, only that value will be used for checking skew compliance.", "ocpVersion": "ocpVersion provides a string which represents the OCP version of the boot image. This field must match the OCP semver compatible format of x.y.z. This field must be between 5 and 10 characters long.", "rhcosVersion": "rhcosVersion provides a string which represents the RHCOS version of the boot image This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between 14 and 21 characters long.", } -func (ClusterBootImage) SwaggerDoc() map[string]string { - return map_ClusterBootImage +func (ClusterBootImageAutomatic) SwaggerDoc() map[string]string { + return map_ClusterBootImageAutomatic +} + +var map_ClusterBootImageManual = map[string]string{ + "": "ClusterBootImageManual is used to describe the cluster boot image in Manual mode.", + "mode": "mode is used to configure which boot image field is defined in Manual mode. Valid values are OCPVersion and RHCOSVersion. OCPVersion means that the cluster admin is expected to set the OCP version associated with the last boot image update in the OCPVersion field. RHCOSVersion means that the cluster admin is expected to set the RHCOS version associated with the last boot image update in the RHCOSVersion field. This field is required.", + "ocpVersion": "ocpVersion provides a string which represents the OCP version of the boot image. This field must match the OCP semver compatible format of x.y.z. This field must be between 5 and 10 characters long. Required when mode is set to \"OCPVersion\" and forbidden otherwise.", + "rhcosVersion": "rhcosVersion provides a string which represents the RHCOS version of the boot image This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between 14 and 21 characters long. Required when mode is set to \"RHCOSVersion\" and forbidden otherwise.", +} + +func (ClusterBootImageManual) SwaggerDoc() map[string]string { + return map_ClusterBootImageManual } var map_IrreconcilableValidationOverrides = map[string]string{ diff --git a/payload-manifests/crds/0000_80_machine-config_01_machineconfigurations-CustomNoUpgrade.crd.yaml b/payload-manifests/crds/0000_80_machine-config_01_machineconfigurations-CustomNoUpgrade.crd.yaml index 6980ce10765..a4fe0264ea0 100644 --- a/payload-manifests/crds/0000_80_machine-config_01_machineconfigurations-CustomNoUpgrade.crd.yaml +++ b/payload-manifests/crds/0000_80_machine-config_01_machineconfigurations-CustomNoUpgrade.crd.yaml @@ -60,23 +60,34 @@ spec: description: |- manual describes the current boot image of the cluster. This should be set to the oldest boot image used amongst all machine resources in the cluster. - This includes the RHCOS version of the boot image and the OCP release version which shipped with that RHCOS boot image. - If ocpVersion and rhcosVersion are defined, both values will be used for checking skew compliance. - If only ocpVersion is defined, only that value will be used for checking skew compliance. - If only rhcosVersion is defined, only that value will be used for checking skew compliance. + This must include either the RHCOS version of the boot image or the OCP release version which shipped with that + RHCOS boot image. Required when mode is set to "Manual" and forbidden otherwise. - minProperties: 1 properties: + mode: + description: |- + mode is used to configure which boot image field is defined in Manual mode. + Valid values are OCPVersion and RHCOSVersion. + OCPVersion means that the cluster admin is expected to set the OCP version associated with the last boot image update + in the OCPVersion field. + RHCOSVersion means that the cluster admin is expected to set the RHCOS version associated with the last boot image update + in the RHCOSVersion field. + This field is required. + enum: + - OCPVersion + - RHCOSVersion + type: string ocpVersion: description: |- ocpVersion provides a string which represents the OCP version of the boot image. This field must match the OCP semver compatible format of x.y.z. This field must be between 5 and 10 characters long. + Required when mode is set to "OCPVersion" and forbidden otherwise. maxLength: 10 minLength: 5 type: string x-kubernetes-validations: - - message: bootImageOCPVersion must match the OCP semver compatible + - message: ocpVersion must match the OCP semver compatible format of x.y.z rule: self.matches('^[0-9]+\\.[0-9]+\\.[0-9]+$') rhcosVersion: @@ -85,6 +96,7 @@ spec: This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between 14 and 21 characters long. + Required when mode is set to "RHCOSVersion" and forbidden otherwise. maxLength: 21 minLength: 14 type: string @@ -92,10 +104,18 @@ spec: - message: rhcosVersion must match format [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or must match legacy format [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber] rule: self.matches('^[0-9]+\\.[0-9]+\\.([0-9]{8}|[0-9]{12})-[0-9]+$') + required: + - mode type: object x-kubernetes-validations: - - message: at least one of ocpVersion or rhcosVersion is required - rule: has(self.ocpVersion) || has(self.rhcosVersion) + - message: ocpVersion is required when mode is OCPVersion, and + forbidden otherwise + rule: 'has(self.mode) && (self.mode ==''OCPVersion'') ? has(self.ocpVersion) + : !has(self.ocpVersion)' + - message: rhcosVersion is required when mode is RHCOSVersion, + and forbidden otherwise + rule: 'has(self.mode) && (self.mode ==''RHCOSVersion'') ? has(self.rhcosVersion) + : !has(self.rhcosVersion)' mode: description: |- mode determines the underlying behavior of skew enforcement mechanism. @@ -780,7 +800,7 @@ spec: minLength: 5 type: string x-kubernetes-validations: - - message: bootImageOCPVersion must match the OCP semver compatible + - message: ocpVersion must match the OCP semver compatible format of x.y.z rule: self.matches('^[0-9]+\\.[0-9]+\\.[0-9]+$') rhcosVersion: @@ -806,18 +826,31 @@ spec: This will be populated by the MCO using the values provided in the spec.bootImageSkewEnforcement.manual field. This value will be compared against the cluster's skew limit to determine skew compliance. Required when mode is set to "Manual" and forbidden otherwise. - minProperties: 1 properties: + mode: + description: |- + mode is used to configure which boot image field is defined in Manual mode. + Valid values are OCPVersion and RHCOSVersion. + OCPVersion means that the cluster admin is expected to set the OCP version associated with the last boot image update + in the OCPVersion field. + RHCOSVersion means that the cluster admin is expected to set the RHCOS version associated with the last boot image update + in the RHCOSVersion field. + This field is required. + enum: + - OCPVersion + - RHCOSVersion + type: string ocpVersion: description: |- ocpVersion provides a string which represents the OCP version of the boot image. This field must match the OCP semver compatible format of x.y.z. This field must be between 5 and 10 characters long. + Required when mode is set to "OCPVersion" and forbidden otherwise. maxLength: 10 minLength: 5 type: string x-kubernetes-validations: - - message: bootImageOCPVersion must match the OCP semver compatible + - message: ocpVersion must match the OCP semver compatible format of x.y.z rule: self.matches('^[0-9]+\\.[0-9]+\\.[0-9]+$') rhcosVersion: @@ -826,6 +859,7 @@ spec: This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between 14 and 21 characters long. + Required when mode is set to "RHCOSVersion" and forbidden otherwise. maxLength: 21 minLength: 14 type: string @@ -833,10 +867,18 @@ spec: - message: rhcosVersion must match format [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or must match legacy format [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber] rule: self.matches('^[0-9]+\\.[0-9]+\\.([0-9]{8}|[0-9]{12})-[0-9]+$') + required: + - mode type: object x-kubernetes-validations: - - message: at least one of ocpVersion or rhcosVersion is required - rule: has(self.ocpVersion) || has(self.rhcosVersion) + - message: ocpVersion is required when mode is OCPVersion, and + forbidden otherwise + rule: 'has(self.mode) && (self.mode ==''OCPVersion'') ? has(self.ocpVersion) + : !has(self.ocpVersion)' + - message: rhcosVersion is required when mode is RHCOSVersion, + and forbidden otherwise + rule: 'has(self.mode) && (self.mode ==''RHCOSVersion'') ? has(self.rhcosVersion) + : !has(self.rhcosVersion)' mode: description: |- mode determines the underlying behavior of skew enforcement mechanism. diff --git a/payload-manifests/crds/0000_80_machine-config_01_machineconfigurations-DevPreviewNoUpgrade.crd.yaml b/payload-manifests/crds/0000_80_machine-config_01_machineconfigurations-DevPreviewNoUpgrade.crd.yaml index 899cc92b44b..5ef1733d145 100644 --- a/payload-manifests/crds/0000_80_machine-config_01_machineconfigurations-DevPreviewNoUpgrade.crd.yaml +++ b/payload-manifests/crds/0000_80_machine-config_01_machineconfigurations-DevPreviewNoUpgrade.crd.yaml @@ -60,23 +60,34 @@ spec: description: |- manual describes the current boot image of the cluster. This should be set to the oldest boot image used amongst all machine resources in the cluster. - This includes the RHCOS version of the boot image and the OCP release version which shipped with that RHCOS boot image. - If ocpVersion and rhcosVersion are defined, both values will be used for checking skew compliance. - If only ocpVersion is defined, only that value will be used for checking skew compliance. - If only rhcosVersion is defined, only that value will be used for checking skew compliance. + This must include either the RHCOS version of the boot image or the OCP release version which shipped with that + RHCOS boot image. Required when mode is set to "Manual" and forbidden otherwise. - minProperties: 1 properties: + mode: + description: |- + mode is used to configure which boot image field is defined in Manual mode. + Valid values are OCPVersion and RHCOSVersion. + OCPVersion means that the cluster admin is expected to set the OCP version associated with the last boot image update + in the OCPVersion field. + RHCOSVersion means that the cluster admin is expected to set the RHCOS version associated with the last boot image update + in the RHCOSVersion field. + This field is required. + enum: + - OCPVersion + - RHCOSVersion + type: string ocpVersion: description: |- ocpVersion provides a string which represents the OCP version of the boot image. This field must match the OCP semver compatible format of x.y.z. This field must be between 5 and 10 characters long. + Required when mode is set to "OCPVersion" and forbidden otherwise. maxLength: 10 minLength: 5 type: string x-kubernetes-validations: - - message: bootImageOCPVersion must match the OCP semver compatible + - message: ocpVersion must match the OCP semver compatible format of x.y.z rule: self.matches('^[0-9]+\\.[0-9]+\\.[0-9]+$') rhcosVersion: @@ -85,6 +96,7 @@ spec: This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between 14 and 21 characters long. + Required when mode is set to "RHCOSVersion" and forbidden otherwise. maxLength: 21 minLength: 14 type: string @@ -92,10 +104,18 @@ spec: - message: rhcosVersion must match format [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or must match legacy format [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber] rule: self.matches('^[0-9]+\\.[0-9]+\\.([0-9]{8}|[0-9]{12})-[0-9]+$') + required: + - mode type: object x-kubernetes-validations: - - message: at least one of ocpVersion or rhcosVersion is required - rule: has(self.ocpVersion) || has(self.rhcosVersion) + - message: ocpVersion is required when mode is OCPVersion, and + forbidden otherwise + rule: 'has(self.mode) && (self.mode ==''OCPVersion'') ? has(self.ocpVersion) + : !has(self.ocpVersion)' + - message: rhcosVersion is required when mode is RHCOSVersion, + and forbidden otherwise + rule: 'has(self.mode) && (self.mode ==''RHCOSVersion'') ? has(self.rhcosVersion) + : !has(self.rhcosVersion)' mode: description: |- mode determines the underlying behavior of skew enforcement mechanism. @@ -780,7 +800,7 @@ spec: minLength: 5 type: string x-kubernetes-validations: - - message: bootImageOCPVersion must match the OCP semver compatible + - message: ocpVersion must match the OCP semver compatible format of x.y.z rule: self.matches('^[0-9]+\\.[0-9]+\\.[0-9]+$') rhcosVersion: @@ -806,18 +826,31 @@ spec: This will be populated by the MCO using the values provided in the spec.bootImageSkewEnforcement.manual field. This value will be compared against the cluster's skew limit to determine skew compliance. Required when mode is set to "Manual" and forbidden otherwise. - minProperties: 1 properties: + mode: + description: |- + mode is used to configure which boot image field is defined in Manual mode. + Valid values are OCPVersion and RHCOSVersion. + OCPVersion means that the cluster admin is expected to set the OCP version associated with the last boot image update + in the OCPVersion field. + RHCOSVersion means that the cluster admin is expected to set the RHCOS version associated with the last boot image update + in the RHCOSVersion field. + This field is required. + enum: + - OCPVersion + - RHCOSVersion + type: string ocpVersion: description: |- ocpVersion provides a string which represents the OCP version of the boot image. This field must match the OCP semver compatible format of x.y.z. This field must be between 5 and 10 characters long. + Required when mode is set to "OCPVersion" and forbidden otherwise. maxLength: 10 minLength: 5 type: string x-kubernetes-validations: - - message: bootImageOCPVersion must match the OCP semver compatible + - message: ocpVersion must match the OCP semver compatible format of x.y.z rule: self.matches('^[0-9]+\\.[0-9]+\\.[0-9]+$') rhcosVersion: @@ -826,6 +859,7 @@ spec: This field must match rhcosVersion formatting of [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or the legacy format of [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber]. This field must be between 14 and 21 characters long. + Required when mode is set to "RHCOSVersion" and forbidden otherwise. maxLength: 21 minLength: 14 type: string @@ -833,10 +867,18 @@ spec: - message: rhcosVersion must match format [major].[minor].[datestamp(YYYYMMDD)]-[buildnumber] or must match legacy format [major].[minor].[timestamp(YYYYMMDDHHmm)]-[buildnumber] rule: self.matches('^[0-9]+\\.[0-9]+\\.([0-9]{8}|[0-9]{12})-[0-9]+$') + required: + - mode type: object x-kubernetes-validations: - - message: at least one of ocpVersion or rhcosVersion is required - rule: has(self.ocpVersion) || has(self.rhcosVersion) + - message: ocpVersion is required when mode is OCPVersion, and + forbidden otherwise + rule: 'has(self.mode) && (self.mode ==''OCPVersion'') ? has(self.ocpVersion) + : !has(self.ocpVersion)' + - message: rhcosVersion is required when mode is RHCOSVersion, + and forbidden otherwise + rule: 'has(self.mode) && (self.mode ==''RHCOSVersion'') ? has(self.rhcosVersion) + : !has(self.rhcosVersion)' mode: description: |- mode determines the underlying behavior of skew enforcement mechanism.