diff --git a/.golangci.yaml b/.golangci.yaml index 1b8472410f5..0f10c6c3837 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -121,6 +121,21 @@ linters: # to enforce specific condition types are always present. path: etcd/v1/types_pacemakercluster.go text: "conditions: Conditions field in (PacemakerClusterStatus|PacemakerClusterNodeStatus|PacemakerClusterFencingAgentStatus|PacemakerClusterResourceStatus) is missing the following markers: optional" + - linters: + - kubeapilinter + # Empty lists are meaningful: no available transitions, or no completed evaluation condition yet. + path: config/v1/types_infrastructure_transitions.go + text: 'minlength: field TopologyTransitionStatus\.(SupportedTransitions|Conditions) must have a minimum items' + - linters: + - kubeapilinter + # Keep the pointer so nil means no topology transition has started; omitempty omits nil. + path: config/v1/types_infrastructure_transitions.go + text: 'optionalfields: field TopologyTransitionStatus\.CurrentTransition' + - linters: + - kubeapilinter + # Keep an evaluated empty list serialized as [] rather than omitting this required field. + path: config/v1/types_infrastructure_transitions.go + text: 'requiredfields: field TopologyTransitionStatus\.SupportedTransitions should have the omitempty tag' - linters: - kubeapilinter path: features|payload-command/ diff --git a/config/v1/tests/infrastructures.config.openshift.io/AAA_ungated.yaml b/config/v1/tests/infrastructures.config.openshift.io/AAA_ungated.yaml index b692386b498..66127fc55a0 100644 --- a/config/v1/tests/infrastructures.config.openshift.io/AAA_ungated.yaml +++ b/config/v1/tests/infrastructures.config.openshift.io/AAA_ungated.yaml @@ -635,6 +635,29 @@ tests: type: UserManaged type: BareMetal expectedStatusError: 'status.platformStatus.baremetal.loadBalancer.type: Invalid value: "string": type is immutable once set' + - name: Should prune topologyTransitionStatus when MutableTopology is disabled + initial: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + controlPlaneTopology: SingleReplica + updated: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + controlPlaneTopology: SingleReplica + topologyTransitionStatus: + supportedTransitions: [] + expected: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + controlPlaneTopology: SingleReplica + infrastructureTopology: HighlyAvailable + cpuPartitioning: None - name: Should not allow changing the immutable OpenStack load balancer type field initial: | apiVersion: config.openshift.io/v1 diff --git a/config/v1/tests/infrastructures.config.openshift.io/MutableTopology.yaml b/config/v1/tests/infrastructures.config.openshift.io/MutableTopology.yaml index b7cdc4876e1..ac533aee345 100644 --- a/config/v1/tests/infrastructures.config.openshift.io/MutableTopology.yaml +++ b/config/v1/tests/infrastructures.config.openshift.io/MutableTopology.yaml @@ -259,3 +259,249 @@ tests: spec: controlPlaneTopology: InvalidValue expectedError: 'spec.controlPlaneTopology: Unsupported value: "InvalidValue": supported values: "HighlyAvailable", "SingleReplica"' + - name: Should allow updating Infrastructure status without topologyTransitionStatus + initial: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + controlPlaneTopology: SingleReplica + updated: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + controlPlaneTopology: SingleReplica + infrastructureTopology: HighlyAvailable + expected: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + controlPlaneTopology: SingleReplica + infrastructureTopology: HighlyAvailable + cpuPartitioning: None + - name: Should allow an empty supportedTransitions list after successful evaluation + initial: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + controlPlaneTopology: SingleReplica + updated: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + controlPlaneTopology: SingleReplica + topologyTransitionStatus: + supportedTransitions: [] + conditions: + - type: TopologyTransitionsEvaluated + status: "True" + lastTransitionTime: "2025-01-01T00:00:00Z" + reason: EvaluationComplete + message: No transitions are available + expected: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + controlPlaneTopology: SingleReplica + infrastructureTopology: HighlyAvailable + cpuPartitioning: None + topologyTransitionStatus: + supportedTransitions: [] + conditions: + - type: TopologyTransitionsEvaluated + status: "True" + lastTransitionTime: "2025-01-01T00:00:00Z" + reason: EvaluationComplete + message: No transitions are available + - name: Should allow reporting current transition progress + initial: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + controlPlaneTopology: SingleReplica + infrastructureTopology: SingleReplica + updated: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + controlPlaneTopology: SingleReplica + infrastructureTopology: SingleReplica + topologyTransitionStatus: + supportedTransitions: + - source: + controlPlaneTopology: SingleReplica + infrastructureTopology: SingleReplica + target: + controlPlaneTopology: HighlyAvailable + infrastructureTopology: HighlyAvailable + reason: PreflightCheckFailed + currentTransition: + state: Partial + reason: TransitionInProgress + message: Applying topology changes + startedTime: "2025-01-01T00:00:00Z" + expected: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + controlPlaneTopology: SingleReplica + infrastructureTopology: SingleReplica + cpuPartitioning: None + topologyTransitionStatus: + supportedTransitions: + - source: + controlPlaneTopology: SingleReplica + infrastructureTopology: SingleReplica + target: + controlPlaneTopology: HighlyAvailable + infrastructureTopology: HighlyAvailable + reason: PreflightCheckFailed + currentTransition: + state: Partial + reason: TransitionInProgress + message: Applying topology changes + startedTime: "2025-01-01T00:00:00Z" + - name: Should reject an unsupported current transition state + initial: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + controlPlaneTopology: SingleReplica + infrastructureTopology: SingleReplica + updated: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + controlPlaneTopology: SingleReplica + infrastructureTopology: SingleReplica + topologyTransitionStatus: + supportedTransitions: [] + currentTransition: + state: InProgress + reason: TransitionInProgress + message: Applying topology changes + expectedStatusError: 'status.topologyTransitionStatus.currentTransition.state: Unsupported value: "InProgress": supported values: "Completed", "Partial", "Failed"' + - name: Should reject a topology transition reason that is not CamelCase + initial: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + controlPlaneTopology: SingleReplica + infrastructureTopology: SingleReplica + updated: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + controlPlaneTopology: SingleReplica + infrastructureTopology: SingleReplica + topologyTransitionStatus: + supportedTransitions: + - source: + controlPlaneTopology: SingleReplica + infrastructureTopology: SingleReplica + target: + controlPlaneTopology: HighlyAvailable + infrastructureTopology: HighlyAvailable + reason: preflightCheckFailed + expectedStatusError: "reason must be CamelCase, matching ^[A-Z][A-Za-z0-9]*$" + - name: Should reject a supported transition whose source does not match status topology + initial: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + controlPlaneTopology: SingleReplica + infrastructureTopology: SingleReplica + updated: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + controlPlaneTopology: SingleReplica + infrastructureTopology: SingleReplica + topologyTransitionStatus: + supportedTransitions: + - source: + controlPlaneTopology: HighlyAvailable + infrastructureTopology: HighlyAvailable + target: + controlPlaneTopology: SingleReplica + infrastructureTopology: SingleReplica + expectedStatusError: "transition sources must match the current status topology" + - name: Should enforce the maximum supported transition count + initial: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + controlPlaneTopology: SingleReplica + infrastructureTopology: SingleReplica + updated: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + controlPlaneTopology: SingleReplica + infrastructureTopology: SingleReplica + topologyTransitionStatus: + supportedTransitions: + - source: + controlPlaneTopology: SingleReplica + infrastructureTopology: SingleReplica + target: + controlPlaneTopology: HighlyAvailable + infrastructureTopology: HighlyAvailable + - source: + controlPlaneTopology: SingleReplica + infrastructureTopology: SingleReplica + target: + controlPlaneTopology: HighlyAvailable + infrastructureTopology: HighlyAvailable + expectedStatusError: "Too many: 2: must have at most 1 items" + - name: Should require supportedTransitions when topologyTransitionStatus is set + initial: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + controlPlaneTopology: SingleReplica + updated: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + controlPlaneTopology: SingleReplica + topologyTransitionStatus: + conditions: [] + expectedStatusError: "Required value" + - name: Should require state on currentTransition + initial: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + controlPlaneTopology: SingleReplica + updated: | + apiVersion: config.openshift.io/v1 + kind: Infrastructure + spec: {} + status: + controlPlaneTopology: SingleReplica + topologyTransitionStatus: + supportedTransitions: [] + currentTransition: + reason: TransitionInProgress + message: Applying topology changes + expectedStatusError: "Required value" diff --git a/config/v1/types_infrastructure.go b/config/v1/types_infrastructure.go index 857f9b27929..25fbed08a1b 100644 --- a/config/v1/types_infrastructure.go +++ b/config/v1/types_infrastructure.go @@ -20,6 +20,7 @@ import ( // +kubebuilder:subresource:status // +kubebuilder:metadata:annotations=release.openshift.io/bootstrap-required=true // +openshift:validation:FeatureGateAwareXValidation:featureGate=MutableTopology,rule="!has(self.spec.controlPlaneTopology) || (has(oldSelf.spec.controlPlaneTopology) && self.spec.controlPlaneTopology == oldSelf.spec.controlPlaneTopology) || (has(self.status.controlPlaneTopology) && self.spec.controlPlaneTopology == self.status.controlPlaneTopology) || (has(self.status.controlPlaneTopology) && self.status.controlPlaneTopology == 'SingleReplica' && self.spec.controlPlaneTopology == 'HighlyAvailable')",message="spec.controlPlaneTopology must match status.controlPlaneTopology or be set to HighlyAvailable when status.controlPlaneTopology is SingleReplica" +// +openshift:validation:FeatureGateAwareXValidation:featureGate=MutableTopology,rule="!has(self.status) || !has(self.status.topologyTransitionStatus) || self.status.topologyTransitionStatus.supportedTransitions.all(t, has(self.status.controlPlaneTopology) && has(self.status.infrastructureTopology) && t.source.controlPlaneTopology == self.status.controlPlaneTopology && t.source.infrastructureTopology == self.status.infrastructureTopology)",message="transition sources must match the current status topology" type Infrastructure struct { metav1.TypeMeta `json:",inline"` @@ -138,6 +139,12 @@ type InfrastructureStatus struct { // +optional InfrastructureTopology TopologyMode `json:"infrastructureTopology,omitempty"` + // topologyTransitionStatus reports available topology transitions and current progress, if any. + // It is omitted until the topology controller evaluates transitions. + // +openshift:enable:FeatureGate=MutableTopology + // +optional + TopologyTransitionStatus *TopologyTransitionStatus `json:"topologyTransitionStatus,omitempty"` + // cpuPartitioning expresses if CPU partitioning is a currently enabled feature in the cluster. // CPU Partitioning means that this cluster can support partitioning workloads to specific CPU Sets. // Valid values are "None" and "AllNodes". When omitted, the default value is "None". diff --git a/config/v1/types_infrastructure_transitions.go b/config/v1/types_infrastructure_transitions.go new file mode 100644 index 00000000000..fcebd945303 --- /dev/null +++ b/config/v1/types_infrastructure_transitions.go @@ -0,0 +1,138 @@ +package v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// TopologyState describes the control-plane and infrastructure topology at one +// end of a topology transition. +type TopologyState struct { + // controlPlaneTopology is the topology of the control-plane nodes. Valid values + // are SingleReplica and HighlyAvailable. When set to SingleReplica, operators + // avoid spending resources for high availability. When set to HighlyAvailable, + // operators configure high availability as much as possible. + // controlPlaneTopology is required. + // +kubebuilder:validation:Enum=SingleReplica;HighlyAvailable + // +required + ControlPlaneTopology TopologyMode `json:"controlPlaneTopology,omitempty"` + + // infrastructureTopology is the topology of infrastructure services. Valid + // values are SingleReplica and HighlyAvailable. When set to SingleReplica, + // operators avoid spending resources for high availability. When set to + // HighlyAvailable, operators configure high availability as much as possible. + // infrastructureTopology is required. + // +kubebuilder:validation:Enum=SingleReplica;HighlyAvailable + // +required + InfrastructureTopology TopologyMode `json:"infrastructureTopology,omitempty"` +} + +type TopologyTransitionStatus struct { + // conditions reports whether supported transitions have been evaluated. + // TopologyTransitionsEvaluated is Unknown before evaluation, True when evaluation + // succeeds (even if no transitions are supported), and False when evaluation fails. + // An absent condition means evaluation has not completed. + // At most one condition is present. + // +kubebuilder:validation:MaxItems=1 + // +optional + // +listType=map + // +listMapKey=type + Conditions []metav1.Condition `json:"conditions,omitempty"` + + // supportedTransitions represents the transitions that are valid for this cluster. + // An empty list means that no transitions are currently supported from the current topology. + // At most one transition is supported currently (SNO to HA Compact) + // +kubebuilder:validation:MaxItems=1 + // +required + // +listType=atomic + SupportedTransitions []TopologyTransition `json:"supportedTransitions"` + + // currentTransition is omitted until a topology transition starts. + // +optional + CurrentTransition *TopologyTransitionProgress `json:"currentTransition,omitempty"` +} + +const ( + // TopologyTransitionsEvaluatedConditionType indicates whether available transitions have been evaluated. + TopologyTransitionsEvaluatedConditionType = "TopologyTransitionsEvaluated" +) + +// TopologyTransitionProgress describes a topology transition that has started. +type TopologyTransitionProgress struct { + // state indicates the current state of a triggered transition. + // Valid values are "Completed" when the transition was successfully applied, + // "Partial" when it was not completely applied or is still in progress, and + // "Failed" when it failed to apply. + // +kubebuilder:validation:Enum=Completed;Partial;Failed + // +required + State TransitionState `json:"state,omitempty"` + + // reason indicates why current state is as reported. + // It must be between 1 and 128 characters long. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=128 + // +required + Reason string `json:"reason,omitempty"` + + // message is human-readable information about the reason for the current state. + // It must be between 1 and 2048 characters long. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=2048 + // +required + Message string `json:"message,omitempty"` + + // startedTime is the time at which the transition was started. When omitted, the start time is not available. + // +optional + StartedTime *metav1.Time `json:"startedTime,omitempty"` + + // completionTime is when the transition was fully applied. It is omitted while a transition is being applied. + // +optional + CompletionTime *metav1.Time `json:"completionTime,omitempty"` +} + +// TransitionState tracks the last observed state of a requested transition. +type TransitionState string + +const ( + // CompletedTransition indicates an transition was successfully + // completed on the cluster. + CompletedTransition TransitionState = "Completed" + // PartialTransition indicates a transition was never completely applied + // or is currently being applied. + PartialTransition TransitionState = "Partial" + // FailedTransition indicates a transition failed to be applied. + FailedTransition TransitionState = "Failed" +) + +type TopologyTransition struct { + // source is the control-plane and infrastructure topology this transition starts + // from. It must equal the current topology in the corresponding status fields. + // source is required. + // +required + Source TopologyState `json:"source,omitempty,omitzero"` + + // target is the control-plane and infrastructure topology this transition would + // move to. target is required. + // +required + Target TopologyState `json:"target,omitempty,omitzero"` + + // reason is a CamelCase machine-readable explanation of the availability, e.g. + // PreflightCheckFailed. The set of reasons is diagnostic and not exhaustive. + // When omitted, no machine-readable explanation is available. + // Must start with an uppercase letter and contain only alphanumeric characters, + // and must be between 1 and 128 characters long. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=128 + // +kubebuilder:validation:XValidation:rule=`self.matches('^[A-Z][A-Za-z0-9]*$')`,message="reason must be CamelCase, matching ^[A-Z][A-Za-z0-9]*$" + // +optional + Reason string `json:"reason,omitempty"` + + // message is a human-readable explanation, primarily for Unavailable + // transitions (e.g. a concise summary of the failing preconditions). It is for + // humans only and must not be parsed. It may be truncated by the controller. + // When omitted, no human-readable explanation is available for the transition. + // When set, it must be between 1 and 2048 characters long. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=2048 + // +optional + Message string `json:"message,omitempty"` +} diff --git a/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_infrastructures-Hypershift-CustomNoUpgrade.crd.yaml b/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_infrastructures-Hypershift-CustomNoUpgrade.crd.yaml index 7a35e5fc0f7..fbc2483dda1 100644 --- a/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_infrastructures-Hypershift-CustomNoUpgrade.crd.yaml +++ b/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_infrastructures-Hypershift-CustomNoUpgrade.crd.yaml @@ -2843,6 +2843,225 @@ spec: rule: '!has(self.dnsRecordsType) || self.dnsRecordsType == ''Internal'' || (has(self.loadBalancer) && self.loadBalancer.type == ''UserManaged'')' type: object + topologyTransitionStatus: + description: |- + topologyTransitionStatus reports available topology transitions and current progress, if any. + It is omitted until the topology controller evaluates transitions. + properties: + conditions: + description: |- + conditions reports whether supported transitions have been evaluated. + TopologyTransitionsEvaluated is Unknown before evaluation, True when evaluation + succeeds (even if no transitions are supported), and False when evaluation fails. + An absent condition means evaluation has not completed. + At most one condition is present. + 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 + maxItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentTransition: + description: currentTransition is omitted until a topology transition + starts. + properties: + completionTime: + description: completionTime is when the transition was fully + applied. It is omitted while a transition is being applied. + format: date-time + type: string + message: + description: |- + message is human-readable information about the reason for the current state. + It must be between 1 and 2048 characters long. + maxLength: 2048 + minLength: 1 + type: string + reason: + description: |- + reason indicates why current state is as reported. + It must be between 1 and 128 characters long. + maxLength: 128 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the transition + was started. When omitted, the start time is not available. + format: date-time + type: string + state: + description: |- + state indicates the current state of a triggered transition. + Valid values are "Completed" when the transition was successfully applied, + "Partial" when it was not completely applied or is still in progress, and + "Failed" when it failed to apply. + enum: + - Completed + - Partial + - Failed + type: string + required: + - message + - reason + - state + type: object + supportedTransitions: + description: |- + supportedTransitions represents the transitions that are valid for this cluster. + An empty list means that no transitions are currently supported from the current topology. + At most one transition is supported currently (SNO to HA Compact) + items: + properties: + message: + description: |- + message is a human-readable explanation, primarily for Unavailable + transitions (e.g. a concise summary of the failing preconditions). It is for + humans only and must not be parsed. It may be truncated by the controller. + When omitted, no human-readable explanation is available for the transition. + When set, it must be between 1 and 2048 characters long. + maxLength: 2048 + minLength: 1 + type: string + reason: + description: |- + reason is a CamelCase machine-readable explanation of the availability, e.g. + PreflightCheckFailed. The set of reasons is diagnostic and not exhaustive. + When omitted, no machine-readable explanation is available. + Must start with an uppercase letter and contain only alphanumeric characters, + and must be between 1 and 128 characters long. + maxLength: 128 + minLength: 1 + type: string + x-kubernetes-validations: + - message: reason must be CamelCase, matching ^[A-Z][A-Za-z0-9]*$ + rule: self.matches('^[A-Z][A-Za-z0-9]*$') + source: + description: |- + source is the control-plane and infrastructure topology this transition starts + from. It must equal the current topology in the corresponding status fields. + source is required. + properties: + controlPlaneTopology: + description: |- + controlPlaneTopology is the topology of the control-plane nodes. Valid values + are SingleReplica and HighlyAvailable. When set to SingleReplica, operators + avoid spending resources for high availability. When set to HighlyAvailable, + operators configure high availability as much as possible. + controlPlaneTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + infrastructureTopology: + description: |- + infrastructureTopology is the topology of infrastructure services. Valid + values are SingleReplica and HighlyAvailable. When set to SingleReplica, + operators avoid spending resources for high availability. When set to + HighlyAvailable, operators configure high availability as much as possible. + infrastructureTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + required: + - controlPlaneTopology + - infrastructureTopology + type: object + target: + description: |- + target is the control-plane and infrastructure topology this transition would + move to. target is required. + properties: + controlPlaneTopology: + description: |- + controlPlaneTopology is the topology of the control-plane nodes. Valid values + are SingleReplica and HighlyAvailable. When set to SingleReplica, operators + avoid spending resources for high availability. When set to HighlyAvailable, + operators configure high availability as much as possible. + controlPlaneTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + infrastructureTopology: + description: |- + infrastructureTopology is the topology of infrastructure services. Valid + values are SingleReplica and HighlyAvailable. When set to SingleReplica, + operators avoid spending resources for high availability. When set to + HighlyAvailable, operators configure high availability as much as possible. + infrastructureTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + required: + - controlPlaneTopology + - infrastructureTopology + type: object + required: + - source + - target + type: object + maxItems: 1 + type: array + x-kubernetes-list-type: atomic + required: + - supportedTransitions + type: object type: object required: - spec @@ -2856,6 +3075,12 @@ spec: == self.status.controlPlaneTopology) || (has(self.status.controlPlaneTopology) && self.status.controlPlaneTopology == ''SingleReplica'' && self.spec.controlPlaneTopology == ''HighlyAvailable'')' + - message: transition sources must match the current status topology + rule: '!has(self.status) || !has(self.status.topologyTransitionStatus) || + self.status.topologyTransitionStatus.supportedTransitions.all(t, has(self.status.controlPlaneTopology) + && has(self.status.infrastructureTopology) && t.source.controlPlaneTopology + == self.status.controlPlaneTopology && t.source.infrastructureTopology + == self.status.infrastructureTopology)' served: true storage: true subresources: diff --git a/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_infrastructures-SelfManagedHA-CustomNoUpgrade.crd.yaml b/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_infrastructures-SelfManagedHA-CustomNoUpgrade.crd.yaml index bbeff9ec02e..bc231b00eac 100644 --- a/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_infrastructures-SelfManagedHA-CustomNoUpgrade.crd.yaml +++ b/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_infrastructures-SelfManagedHA-CustomNoUpgrade.crd.yaml @@ -2843,6 +2843,225 @@ spec: rule: '!has(self.dnsRecordsType) || self.dnsRecordsType == ''Internal'' || (has(self.loadBalancer) && self.loadBalancer.type == ''UserManaged'')' type: object + topologyTransitionStatus: + description: |- + topologyTransitionStatus reports available topology transitions and current progress, if any. + It is omitted until the topology controller evaluates transitions. + properties: + conditions: + description: |- + conditions reports whether supported transitions have been evaluated. + TopologyTransitionsEvaluated is Unknown before evaluation, True when evaluation + succeeds (even if no transitions are supported), and False when evaluation fails. + An absent condition means evaluation has not completed. + At most one condition is present. + 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 + maxItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentTransition: + description: currentTransition is omitted until a topology transition + starts. + properties: + completionTime: + description: completionTime is when the transition was fully + applied. It is omitted while a transition is being applied. + format: date-time + type: string + message: + description: |- + message is human-readable information about the reason for the current state. + It must be between 1 and 2048 characters long. + maxLength: 2048 + minLength: 1 + type: string + reason: + description: |- + reason indicates why current state is as reported. + It must be between 1 and 128 characters long. + maxLength: 128 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the transition + was started. When omitted, the start time is not available. + format: date-time + type: string + state: + description: |- + state indicates the current state of a triggered transition. + Valid values are "Completed" when the transition was successfully applied, + "Partial" when it was not completely applied or is still in progress, and + "Failed" when it failed to apply. + enum: + - Completed + - Partial + - Failed + type: string + required: + - message + - reason + - state + type: object + supportedTransitions: + description: |- + supportedTransitions represents the transitions that are valid for this cluster. + An empty list means that no transitions are currently supported from the current topology. + At most one transition is supported currently (SNO to HA Compact) + items: + properties: + message: + description: |- + message is a human-readable explanation, primarily for Unavailable + transitions (e.g. a concise summary of the failing preconditions). It is for + humans only and must not be parsed. It may be truncated by the controller. + When omitted, no human-readable explanation is available for the transition. + When set, it must be between 1 and 2048 characters long. + maxLength: 2048 + minLength: 1 + type: string + reason: + description: |- + reason is a CamelCase machine-readable explanation of the availability, e.g. + PreflightCheckFailed. The set of reasons is diagnostic and not exhaustive. + When omitted, no machine-readable explanation is available. + Must start with an uppercase letter and contain only alphanumeric characters, + and must be between 1 and 128 characters long. + maxLength: 128 + minLength: 1 + type: string + x-kubernetes-validations: + - message: reason must be CamelCase, matching ^[A-Z][A-Za-z0-9]*$ + rule: self.matches('^[A-Z][A-Za-z0-9]*$') + source: + description: |- + source is the control-plane and infrastructure topology this transition starts + from. It must equal the current topology in the corresponding status fields. + source is required. + properties: + controlPlaneTopology: + description: |- + controlPlaneTopology is the topology of the control-plane nodes. Valid values + are SingleReplica and HighlyAvailable. When set to SingleReplica, operators + avoid spending resources for high availability. When set to HighlyAvailable, + operators configure high availability as much as possible. + controlPlaneTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + infrastructureTopology: + description: |- + infrastructureTopology is the topology of infrastructure services. Valid + values are SingleReplica and HighlyAvailable. When set to SingleReplica, + operators avoid spending resources for high availability. When set to + HighlyAvailable, operators configure high availability as much as possible. + infrastructureTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + required: + - controlPlaneTopology + - infrastructureTopology + type: object + target: + description: |- + target is the control-plane and infrastructure topology this transition would + move to. target is required. + properties: + controlPlaneTopology: + description: |- + controlPlaneTopology is the topology of the control-plane nodes. Valid values + are SingleReplica and HighlyAvailable. When set to SingleReplica, operators + avoid spending resources for high availability. When set to HighlyAvailable, + operators configure high availability as much as possible. + controlPlaneTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + infrastructureTopology: + description: |- + infrastructureTopology is the topology of infrastructure services. Valid + values are SingleReplica and HighlyAvailable. When set to SingleReplica, + operators avoid spending resources for high availability. When set to + HighlyAvailable, operators configure high availability as much as possible. + infrastructureTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + required: + - controlPlaneTopology + - infrastructureTopology + type: object + required: + - source + - target + type: object + maxItems: 1 + type: array + x-kubernetes-list-type: atomic + required: + - supportedTransitions + type: object type: object required: - spec @@ -2856,6 +3075,12 @@ spec: == self.status.controlPlaneTopology) || (has(self.status.controlPlaneTopology) && self.status.controlPlaneTopology == ''SingleReplica'' && self.spec.controlPlaneTopology == ''HighlyAvailable'')' + - message: transition sources must match the current status topology + rule: '!has(self.status) || !has(self.status.topologyTransitionStatus) || + self.status.topologyTransitionStatus.supportedTransitions.all(t, has(self.status.controlPlaneTopology) + && has(self.status.infrastructureTopology) && t.source.controlPlaneTopology + == self.status.controlPlaneTopology && t.source.infrastructureTopology + == self.status.infrastructureTopology)' served: true storage: true subresources: diff --git a/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_infrastructures-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml b/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_infrastructures-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml index 0207127aa67..e3eb7cc5429 100644 --- a/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_infrastructures-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml +++ b/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_infrastructures-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml @@ -2843,6 +2843,225 @@ spec: rule: '!has(self.dnsRecordsType) || self.dnsRecordsType == ''Internal'' || (has(self.loadBalancer) && self.loadBalancer.type == ''UserManaged'')' type: object + topologyTransitionStatus: + description: |- + topologyTransitionStatus reports available topology transitions and current progress, if any. + It is omitted until the topology controller evaluates transitions. + properties: + conditions: + description: |- + conditions reports whether supported transitions have been evaluated. + TopologyTransitionsEvaluated is Unknown before evaluation, True when evaluation + succeeds (even if no transitions are supported), and False when evaluation fails. + An absent condition means evaluation has not completed. + At most one condition is present. + 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 + maxItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentTransition: + description: currentTransition is omitted until a topology transition + starts. + properties: + completionTime: + description: completionTime is when the transition was fully + applied. It is omitted while a transition is being applied. + format: date-time + type: string + message: + description: |- + message is human-readable information about the reason for the current state. + It must be between 1 and 2048 characters long. + maxLength: 2048 + minLength: 1 + type: string + reason: + description: |- + reason indicates why current state is as reported. + It must be between 1 and 128 characters long. + maxLength: 128 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the transition + was started. When omitted, the start time is not available. + format: date-time + type: string + state: + description: |- + state indicates the current state of a triggered transition. + Valid values are "Completed" when the transition was successfully applied, + "Partial" when it was not completely applied or is still in progress, and + "Failed" when it failed to apply. + enum: + - Completed + - Partial + - Failed + type: string + required: + - message + - reason + - state + type: object + supportedTransitions: + description: |- + supportedTransitions represents the transitions that are valid for this cluster. + An empty list means that no transitions are currently supported from the current topology. + At most one transition is supported currently (SNO to HA Compact) + items: + properties: + message: + description: |- + message is a human-readable explanation, primarily for Unavailable + transitions (e.g. a concise summary of the failing preconditions). It is for + humans only and must not be parsed. It may be truncated by the controller. + When omitted, no human-readable explanation is available for the transition. + When set, it must be between 1 and 2048 characters long. + maxLength: 2048 + minLength: 1 + type: string + reason: + description: |- + reason is a CamelCase machine-readable explanation of the availability, e.g. + PreflightCheckFailed. The set of reasons is diagnostic and not exhaustive. + When omitted, no machine-readable explanation is available. + Must start with an uppercase letter and contain only alphanumeric characters, + and must be between 1 and 128 characters long. + maxLength: 128 + minLength: 1 + type: string + x-kubernetes-validations: + - message: reason must be CamelCase, matching ^[A-Z][A-Za-z0-9]*$ + rule: self.matches('^[A-Z][A-Za-z0-9]*$') + source: + description: |- + source is the control-plane and infrastructure topology this transition starts + from. It must equal the current topology in the corresponding status fields. + source is required. + properties: + controlPlaneTopology: + description: |- + controlPlaneTopology is the topology of the control-plane nodes. Valid values + are SingleReplica and HighlyAvailable. When set to SingleReplica, operators + avoid spending resources for high availability. When set to HighlyAvailable, + operators configure high availability as much as possible. + controlPlaneTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + infrastructureTopology: + description: |- + infrastructureTopology is the topology of infrastructure services. Valid + values are SingleReplica and HighlyAvailable. When set to SingleReplica, + operators avoid spending resources for high availability. When set to + HighlyAvailable, operators configure high availability as much as possible. + infrastructureTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + required: + - controlPlaneTopology + - infrastructureTopology + type: object + target: + description: |- + target is the control-plane and infrastructure topology this transition would + move to. target is required. + properties: + controlPlaneTopology: + description: |- + controlPlaneTopology is the topology of the control-plane nodes. Valid values + are SingleReplica and HighlyAvailable. When set to SingleReplica, operators + avoid spending resources for high availability. When set to HighlyAvailable, + operators configure high availability as much as possible. + controlPlaneTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + infrastructureTopology: + description: |- + infrastructureTopology is the topology of infrastructure services. Valid + values are SingleReplica and HighlyAvailable. When set to SingleReplica, + operators avoid spending resources for high availability. When set to + HighlyAvailable, operators configure high availability as much as possible. + infrastructureTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + required: + - controlPlaneTopology + - infrastructureTopology + type: object + required: + - source + - target + type: object + maxItems: 1 + type: array + x-kubernetes-list-type: atomic + required: + - supportedTransitions + type: object type: object required: - spec @@ -2856,6 +3075,12 @@ spec: == self.status.controlPlaneTopology) || (has(self.status.controlPlaneTopology) && self.status.controlPlaneTopology == ''SingleReplica'' && self.spec.controlPlaneTopology == ''HighlyAvailable'')' + - message: transition sources must match the current status topology + rule: '!has(self.status) || !has(self.status.topologyTransitionStatus) || + self.status.topologyTransitionStatus.supportedTransitions.all(t, has(self.status.controlPlaneTopology) + && has(self.status.infrastructureTopology) && t.source.controlPlaneTopology + == self.status.controlPlaneTopology && t.source.infrastructureTopology + == self.status.infrastructureTopology)' served: true storage: true subresources: diff --git a/config/v1/zz_generated.deepcopy.go b/config/v1/zz_generated.deepcopy.go index 4b194b226a4..b62dd17e2ae 100644 --- a/config/v1/zz_generated.deepcopy.go +++ b/config/v1/zz_generated.deepcopy.go @@ -3820,6 +3820,11 @@ func (in *InfrastructureStatus) DeepCopyInto(out *InfrastructureStatus) { *out = new(PlatformStatus) (*in).DeepCopyInto(*out) } + if in.TopologyTransitionStatus != nil { + in, out := &in.TopologyTransitionStatus, &out.TopologyTransitionStatus + *out = new(TopologyTransitionStatus) + (*in).DeepCopyInto(*out) + } return } @@ -6848,6 +6853,97 @@ func (in *TokenUserValidationRule) DeepCopy() *TokenUserValidationRule { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TopologyState) DeepCopyInto(out *TopologyState) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TopologyState. +func (in *TopologyState) DeepCopy() *TopologyState { + if in == nil { + return nil + } + out := new(TopologyState) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TopologyTransition) DeepCopyInto(out *TopologyTransition) { + *out = *in + out.Source = in.Source + out.Target = in.Target + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TopologyTransition. +func (in *TopologyTransition) DeepCopy() *TopologyTransition { + if in == nil { + return nil + } + out := new(TopologyTransition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TopologyTransitionProgress) DeepCopyInto(out *TopologyTransitionProgress) { + *out = *in + if in.StartedTime != nil { + in, out := &in.StartedTime, &out.StartedTime + *out = (*in).DeepCopy() + } + if in.CompletionTime != nil { + in, out := &in.CompletionTime, &out.CompletionTime + *out = (*in).DeepCopy() + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TopologyTransitionProgress. +func (in *TopologyTransitionProgress) DeepCopy() *TopologyTransitionProgress { + if in == nil { + return nil + } + out := new(TopologyTransitionProgress) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TopologyTransitionStatus) DeepCopyInto(out *TopologyTransitionStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.SupportedTransitions != nil { + in, out := &in.SupportedTransitions, &out.SupportedTransitions + *out = make([]TopologyTransition, len(*in)) + copy(*out, *in) + } + if in.CurrentTransition != nil { + in, out := &in.CurrentTransition, &out.CurrentTransition + *out = new(TopologyTransitionProgress) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TopologyTransitionStatus. +func (in *TopologyTransitionStatus) DeepCopy() *TopologyTransitionStatus { + if in == nil { + return nil + } + out := new(TopologyTransitionStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Update) DeepCopyInto(out *Update) { *out = *in diff --git a/config/v1/zz_generated.featuregated-crd-manifests/infrastructures.config.openshift.io/MutableTopology.yaml b/config/v1/zz_generated.featuregated-crd-manifests/infrastructures.config.openshift.io/MutableTopology.yaml index 446505413cb..bfac3c65bc1 100644 --- a/config/v1/zz_generated.featuregated-crd-manifests/infrastructures.config.openshift.io/MutableTopology.yaml +++ b/config/v1/zz_generated.featuregated-crd-manifests/infrastructures.config.openshift.io/MutableTopology.yaml @@ -2431,6 +2431,225 @@ spec: type: string type: object type: object + topologyTransitionStatus: + description: |- + topologyTransitionStatus reports available topology transitions and current progress, if any. + It is omitted until the topology controller evaluates transitions. + properties: + conditions: + description: |- + conditions reports whether supported transitions have been evaluated. + TopologyTransitionsEvaluated is Unknown before evaluation, True when evaluation + succeeds (even if no transitions are supported), and False when evaluation fails. + An absent condition means evaluation has not completed. + At most one condition is present. + 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 + maxItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentTransition: + description: currentTransition is omitted until a topology transition + starts. + properties: + completionTime: + description: completionTime is when the transition was fully + applied. It is omitted while a transition is being applied. + format: date-time + type: string + message: + description: |- + message is human-readable information about the reason for the current state. + It must be between 1 and 2048 characters long. + maxLength: 2048 + minLength: 1 + type: string + reason: + description: |- + reason indicates why current state is as reported. + It must be between 1 and 128 characters long. + maxLength: 128 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the transition + was started. When omitted, the start time is not available. + format: date-time + type: string + state: + description: |- + state indicates the current state of a triggered transition. + Valid values are "Completed" when the transition was successfully applied, + "Partial" when it was not completely applied or is still in progress, and + "Failed" when it failed to apply. + enum: + - Completed + - Partial + - Failed + type: string + required: + - message + - reason + - state + type: object + supportedTransitions: + description: |- + supportedTransitions represents the transitions that are valid for this cluster. + An empty list means that no transitions are currently supported from the current topology. + At most one transition is supported currently (SNO to HA Compact) + items: + properties: + message: + description: |- + message is a human-readable explanation, primarily for Unavailable + transitions (e.g. a concise summary of the failing preconditions). It is for + humans only and must not be parsed. It may be truncated by the controller. + When omitted, no human-readable explanation is available for the transition. + When set, it must be between 1 and 2048 characters long. + maxLength: 2048 + minLength: 1 + type: string + reason: + description: |- + reason is a CamelCase machine-readable explanation of the availability, e.g. + PreflightCheckFailed. The set of reasons is diagnostic and not exhaustive. + When omitted, no machine-readable explanation is available. + Must start with an uppercase letter and contain only alphanumeric characters, + and must be between 1 and 128 characters long. + maxLength: 128 + minLength: 1 + type: string + x-kubernetes-validations: + - message: reason must be CamelCase, matching ^[A-Z][A-Za-z0-9]*$ + rule: self.matches('^[A-Z][A-Za-z0-9]*$') + source: + description: |- + source is the control-plane and infrastructure topology this transition starts + from. It must equal the current topology in the corresponding status fields. + source is required. + properties: + controlPlaneTopology: + description: |- + controlPlaneTopology is the topology of the control-plane nodes. Valid values + are SingleReplica and HighlyAvailable. When set to SingleReplica, operators + avoid spending resources for high availability. When set to HighlyAvailable, + operators configure high availability as much as possible. + controlPlaneTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + infrastructureTopology: + description: |- + infrastructureTopology is the topology of infrastructure services. Valid + values are SingleReplica and HighlyAvailable. When set to SingleReplica, + operators avoid spending resources for high availability. When set to + HighlyAvailable, operators configure high availability as much as possible. + infrastructureTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + required: + - controlPlaneTopology + - infrastructureTopology + type: object + target: + description: |- + target is the control-plane and infrastructure topology this transition would + move to. target is required. + properties: + controlPlaneTopology: + description: |- + controlPlaneTopology is the topology of the control-plane nodes. Valid values + are SingleReplica and HighlyAvailable. When set to SingleReplica, operators + avoid spending resources for high availability. When set to HighlyAvailable, + operators configure high availability as much as possible. + controlPlaneTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + infrastructureTopology: + description: |- + infrastructureTopology is the topology of infrastructure services. Valid + values are SingleReplica and HighlyAvailable. When set to SingleReplica, + operators avoid spending resources for high availability. When set to + HighlyAvailable, operators configure high availability as much as possible. + infrastructureTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + required: + - controlPlaneTopology + - infrastructureTopology + type: object + required: + - source + - target + type: object + maxItems: 1 + type: array + x-kubernetes-list-type: atomic + required: + - supportedTransitions + type: object type: object required: - spec @@ -2444,6 +2663,12 @@ spec: == self.status.controlPlaneTopology) || (has(self.status.controlPlaneTopology) && self.status.controlPlaneTopology == ''SingleReplica'' && self.spec.controlPlaneTopology == ''HighlyAvailable'')' + - message: transition sources must match the current status topology + rule: '!has(self.status) || !has(self.status.topologyTransitionStatus) || + self.status.topologyTransitionStatus.supportedTransitions.all(t, has(self.status.controlPlaneTopology) + && has(self.status.infrastructureTopology) && t.source.controlPlaneTopology + == self.status.controlPlaneTopology && t.source.infrastructureTopology + == self.status.infrastructureTopology)' served: true storage: true subresources: diff --git a/config/v1/zz_generated.model_name.go b/config/v1/zz_generated.model_name.go index 043c03ef5ef..c6def4019e6 100644 --- a/config/v1/zz_generated.model_name.go +++ b/config/v1/zz_generated.model_name.go @@ -1455,6 +1455,26 @@ func (in TokenUserValidationRule) OpenAPIModelName() string { return "com.github.openshift.api.config.v1.TokenUserValidationRule" } +// OpenAPIModelName returns the OpenAPI model name for this type. +func (in TopologyState) OpenAPIModelName() string { + return "com.github.openshift.api.config.v1.TopologyState" +} + +// OpenAPIModelName returns the OpenAPI model name for this type. +func (in TopologyTransition) OpenAPIModelName() string { + return "com.github.openshift.api.config.v1.TopologyTransition" +} + +// OpenAPIModelName returns the OpenAPI model name for this type. +func (in TopologyTransitionProgress) OpenAPIModelName() string { + return "com.github.openshift.api.config.v1.TopologyTransitionProgress" +} + +// OpenAPIModelName returns the OpenAPI model name for this type. +func (in TopologyTransitionStatus) OpenAPIModelName() string { + return "com.github.openshift.api.config.v1.TopologyTransitionStatus" +} + // OpenAPIModelName returns the OpenAPI model name for this type. func (in Update) OpenAPIModelName() string { return "com.github.openshift.api.config.v1.Update" diff --git a/config/v1/zz_generated.swagger_doc_generated.go b/config/v1/zz_generated.swagger_doc_generated.go index 0f4605ef380..50bda32be5b 100644 --- a/config/v1/zz_generated.swagger_doc_generated.go +++ b/config/v1/zz_generated.swagger_doc_generated.go @@ -1881,16 +1881,17 @@ func (InfrastructureSpec) SwaggerDoc() map[string]string { } var map_InfrastructureStatus = map[string]string{ - "": "InfrastructureStatus describes the infrastructure the cluster is leveraging.", - "infrastructureName": "infrastructureName uniquely identifies a cluster with a human friendly name. Once set it should not be changed. Must be of max length 27 and must have only alphanumeric or hyphen characters.", - "platform": "platform is the underlying infrastructure provider for the cluster.\n\nDeprecated: Use platformStatus.type instead.", - "platformStatus": "platformStatus holds status information specific to the underlying infrastructure provider.", - "etcdDiscoveryDomain": "etcdDiscoveryDomain is the domain used to fetch the SRV records for discovering etcd servers and clients. For more info: https://github.com/etcd-io/etcd/blob/329be66e8b3f9e2e6af83c123ff89297e49ebd15/Documentation/op-guide/clustering.md#dns-discovery deprecated: as of 4.7, this field is no longer set or honored. It will be removed in a future release.", - "apiServerURL": "apiServerURL is a valid URI with scheme 'https', address and optionally a port (defaulting to 443). apiServerURL can be used by components like the web console to tell users where to find the Kubernetes API.", - "apiServerInternalURI": "apiServerInternalURL is a valid URI with scheme 'https', address and optionally a port (defaulting to 443). apiServerInternalURL can be used by components like kubelets, to contact the Kubernetes API server using the infrastructure provider rather than Kubernetes networking.", - "controlPlaneTopology": "controlPlaneTopology expresses the expectations for operands that normally run on control nodes. The default is 'HighlyAvailable', which represents the behavior operators have in a \"normal\" cluster. The 'SingleReplica' mode will be used in single-node deployments and the operators should not configure the operand for highly-available operation The 'External' mode indicates that the control plane is hosted externally to the cluster and that its components are not visible within the cluster. The 'HighlyAvailableArbiter' mode indicates that the control plane will consist of 2 control-plane nodes that run conventional services and 1 smaller sized arbiter node that runs a bare minimum of services to maintain quorum.", - "infrastructureTopology": "infrastructureTopology expresses the expectations for infrastructure services that do not run on control plane nodes, usually indicated by a node selector for a `role` value other than `master`. The default is 'HighlyAvailable', which represents the behavior operators have in a \"normal\" cluster. The 'SingleReplica' mode will be used in single-node deployments and the operators should not configure the operand for highly-available operation NOTE: External topology mode is not applicable for this field.", - "cpuPartitioning": "cpuPartitioning expresses if CPU partitioning is a currently enabled feature in the cluster. CPU Partitioning means that this cluster can support partitioning workloads to specific CPU Sets. Valid values are \"None\" and \"AllNodes\". When omitted, the default value is \"None\". The default value of \"None\" indicates that no nodes will be setup with CPU partitioning. The \"AllNodes\" value indicates that all nodes have been setup with CPU partitioning, and can then be further configured via the PerformanceProfile API.", + "": "InfrastructureStatus describes the infrastructure the cluster is leveraging.", + "infrastructureName": "infrastructureName uniquely identifies a cluster with a human friendly name. Once set it should not be changed. Must be of max length 27 and must have only alphanumeric or hyphen characters.", + "platform": "platform is the underlying infrastructure provider for the cluster.\n\nDeprecated: Use platformStatus.type instead.", + "platformStatus": "platformStatus holds status information specific to the underlying infrastructure provider.", + "etcdDiscoveryDomain": "etcdDiscoveryDomain is the domain used to fetch the SRV records for discovering etcd servers and clients. For more info: https://github.com/etcd-io/etcd/blob/329be66e8b3f9e2e6af83c123ff89297e49ebd15/Documentation/op-guide/clustering.md#dns-discovery deprecated: as of 4.7, this field is no longer set or honored. It will be removed in a future release.", + "apiServerURL": "apiServerURL is a valid URI with scheme 'https', address and optionally a port (defaulting to 443). apiServerURL can be used by components like the web console to tell users where to find the Kubernetes API.", + "apiServerInternalURI": "apiServerInternalURL is a valid URI with scheme 'https', address and optionally a port (defaulting to 443). apiServerInternalURL can be used by components like kubelets, to contact the Kubernetes API server using the infrastructure provider rather than Kubernetes networking.", + "controlPlaneTopology": "controlPlaneTopology expresses the expectations for operands that normally run on control nodes. The default is 'HighlyAvailable', which represents the behavior operators have in a \"normal\" cluster. The 'SingleReplica' mode will be used in single-node deployments and the operators should not configure the operand for highly-available operation The 'External' mode indicates that the control plane is hosted externally to the cluster and that its components are not visible within the cluster. The 'HighlyAvailableArbiter' mode indicates that the control plane will consist of 2 control-plane nodes that run conventional services and 1 smaller sized arbiter node that runs a bare minimum of services to maintain quorum.", + "infrastructureTopology": "infrastructureTopology expresses the expectations for infrastructure services that do not run on control plane nodes, usually indicated by a node selector for a `role` value other than `master`. The default is 'HighlyAvailable', which represents the behavior operators have in a \"normal\" cluster. The 'SingleReplica' mode will be used in single-node deployments and the operators should not configure the operand for highly-available operation NOTE: External topology mode is not applicable for this field.", + "topologyTransitionStatus": "topologyTransitionStatus reports available topology transitions and current progress, if any. It is omitted until the topology controller evaluates transitions.", + "cpuPartitioning": "cpuPartitioning expresses if CPU partitioning is a currently enabled feature in the cluster. CPU Partitioning means that this cluster can support partitioning workloads to specific CPU Sets. Valid values are \"None\" and \"AllNodes\". When omitted, the default value is \"None\". The default value of \"None\" indicates that no nodes will be setup with CPU partitioning. The \"AllNodes\" value indicates that all nodes have been setup with CPU partitioning, and can then be further configured via the PerformanceProfile API.", } func (InfrastructureStatus) SwaggerDoc() map[string]string { @@ -2270,6 +2271,50 @@ func (VSpherePlatformVCenterSpec) SwaggerDoc() map[string]string { return map_VSpherePlatformVCenterSpec } +var map_TopologyState = map[string]string{ + "": "TopologyState describes the control-plane and infrastructure topology at one end of a topology transition.", + "controlPlaneTopology": "controlPlaneTopology is the topology of the control-plane nodes. Valid values are SingleReplica and HighlyAvailable. When set to SingleReplica, operators avoid spending resources for high availability. When set to HighlyAvailable, operators configure high availability as much as possible. controlPlaneTopology is required.", + "infrastructureTopology": "infrastructureTopology is the topology of infrastructure services. Valid values are SingleReplica and HighlyAvailable. When set to SingleReplica, operators avoid spending resources for high availability. When set to HighlyAvailable, operators configure high availability as much as possible. infrastructureTopology is required.", +} + +func (TopologyState) SwaggerDoc() map[string]string { + return map_TopologyState +} + +var map_TopologyTransition = map[string]string{ + "source": "source is the control-plane and infrastructure topology this transition starts from. It must equal the current topology in the corresponding status fields. source is required.", + "target": "target is the control-plane and infrastructure topology this transition would move to. target is required.", + "reason": "reason is a CamelCase machine-readable explanation of the availability, e.g. PreflightCheckFailed. The set of reasons is diagnostic and not exhaustive. When omitted, no machine-readable explanation is available. Must start with an uppercase letter and contain only alphanumeric characters, and must be between 1 and 128 characters long.", + "message": "message is a human-readable explanation, primarily for Unavailable transitions (e.g. a concise summary of the failing preconditions). It is for humans only and must not be parsed. It may be truncated by the controller. When omitted, no human-readable explanation is available for the transition. When set, it must be between 1 and 2048 characters long.", +} + +func (TopologyTransition) SwaggerDoc() map[string]string { + return map_TopologyTransition +} + +var map_TopologyTransitionProgress = map[string]string{ + "": "TopologyTransitionProgress describes a topology transition that has started.", + "state": "state indicates the current state of a triggered transition. Valid values are \"Completed\" when the transition was successfully applied, \"Partial\" when it was not completely applied or is still in progress, and \"Failed\" when it failed to apply.", + "reason": "reason indicates why current state is as reported. It must be between 1 and 128 characters long.", + "message": "message is human-readable information about the reason for the current state. It must be between 1 and 2048 characters long.", + "startedTime": "startedTime is the time at which the transition was started. When omitted, the start time is not available.", + "completionTime": "completionTime is when the transition was fully applied. It is omitted while a transition is being applied.", +} + +func (TopologyTransitionProgress) SwaggerDoc() map[string]string { + return map_TopologyTransitionProgress +} + +var map_TopologyTransitionStatus = map[string]string{ + "conditions": "conditions reports whether supported transitions have been evaluated. TopologyTransitionsEvaluated is Unknown before evaluation, True when evaluation succeeds (even if no transitions are supported), and False when evaluation fails. An absent condition means evaluation has not completed. At most one condition is present.", + "supportedTransitions": "supportedTransitions represents the transitions that are valid for this cluster. An empty list means that no transitions are currently supported from the current topology. At most one transition is supported currently (SNO to HA Compact)", + "currentTransition": "currentTransition is omitted until a topology transition starts.", +} + +func (TopologyTransitionStatus) SwaggerDoc() map[string]string { + return map_TopologyTransitionStatus +} + var map_AWSIngressSpec = map[string]string{ "": "AWSIngressSpec holds the desired state of the Ingress for Amazon Web Services infrastructure provider. This only includes fields that can be modified in the cluster.", "type": "type allows user to set a load balancer type. When this field is set the default ingresscontroller will get created using the specified LBType. If this field is not set then the default ingress controller of LBType Classic will be created. Valid values are:\n\n* \"Classic\": A Classic Load Balancer that makes routing decisions at either\n the transport layer (TCP/SSL) or the application layer (HTTP/HTTPS). See\n the following for additional details:\n\n https://docs.aws.amazon.com/AmazonECS/latest/developerguide/load-balancer-types.html#clb\n\n* \"NLB\": A Network Load Balancer that makes routing decisions at the\n transport layer (TCP/SSL). See the following for additional details:\n\n https://docs.aws.amazon.com/AmazonECS/latest/developerguide/load-balancer-types.html#nlb", diff --git a/machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_controllerconfigs-Hypershift-CustomNoUpgrade.crd.yaml b/machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_controllerconfigs-Hypershift-CustomNoUpgrade.crd.yaml index 273851bb919..ed332d83282 100644 --- a/machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_controllerconfigs-Hypershift-CustomNoUpgrade.crd.yaml +++ b/machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_controllerconfigs-Hypershift-CustomNoUpgrade.crd.yaml @@ -3165,6 +3165,228 @@ spec: == ''Internal'' || (has(self.loadBalancer) && self.loadBalancer.type == ''UserManaged'')' type: object + topologyTransitionStatus: + description: |- + topologyTransitionStatus reports available topology transitions and current progress, if any. + It is omitted until the topology controller evaluates transitions. + properties: + conditions: + description: |- + conditions reports whether supported transitions have been evaluated. + TopologyTransitionsEvaluated is Unknown before evaluation, True when evaluation + succeeds (even if no transitions are supported), and False when evaluation fails. + An absent condition means evaluation has not completed. + At most one condition is present. + 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 + maxItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentTransition: + description: currentTransition is omitted until a topology + transition starts. + properties: + completionTime: + description: completionTime is when the transition + was fully applied. It is omitted while a transition + is being applied. + format: date-time + type: string + message: + description: |- + message is human-readable information about the reason for the current state. + It must be between 1 and 2048 characters long. + maxLength: 2048 + minLength: 1 + type: string + reason: + description: |- + reason indicates why current state is as reported. + It must be between 1 and 128 characters long. + maxLength: 128 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the + transition was started. When omitted, the start + time is not available. + format: date-time + type: string + state: + description: |- + state indicates the current state of a triggered transition. + Valid values are "Completed" when the transition was successfully applied, + "Partial" when it was not completely applied or is still in progress, and + "Failed" when it failed to apply. + enum: + - Completed + - Partial + - Failed + type: string + required: + - message + - reason + - state + type: object + supportedTransitions: + description: |- + supportedTransitions represents the transitions that are valid for this cluster. + An empty list means that no transitions are currently supported from the current topology. + At most one transition is supported currently (SNO to HA Compact) + items: + properties: + message: + description: |- + message is a human-readable explanation, primarily for Unavailable + transitions (e.g. a concise summary of the failing preconditions). It is for + humans only and must not be parsed. It may be truncated by the controller. + When omitted, no human-readable explanation is available for the transition. + When set, it must be between 1 and 2048 characters long. + maxLength: 2048 + minLength: 1 + type: string + reason: + description: |- + reason is a CamelCase machine-readable explanation of the availability, e.g. + PreflightCheckFailed. The set of reasons is diagnostic and not exhaustive. + When omitted, no machine-readable explanation is available. + Must start with an uppercase letter and contain only alphanumeric characters, + and must be between 1 and 128 characters long. + maxLength: 128 + minLength: 1 + type: string + x-kubernetes-validations: + - message: reason must be CamelCase, matching ^[A-Z][A-Za-z0-9]*$ + rule: self.matches('^[A-Z][A-Za-z0-9]*$') + source: + description: |- + source is the control-plane and infrastructure topology this transition starts + from. It must equal the current topology in the corresponding status fields. + source is required. + properties: + controlPlaneTopology: + description: |- + controlPlaneTopology is the topology of the control-plane nodes. Valid values + are SingleReplica and HighlyAvailable. When set to SingleReplica, operators + avoid spending resources for high availability. When set to HighlyAvailable, + operators configure high availability as much as possible. + controlPlaneTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + infrastructureTopology: + description: |- + infrastructureTopology is the topology of infrastructure services. Valid + values are SingleReplica and HighlyAvailable. When set to SingleReplica, + operators avoid spending resources for high availability. When set to + HighlyAvailable, operators configure high availability as much as possible. + infrastructureTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + required: + - controlPlaneTopology + - infrastructureTopology + type: object + target: + description: |- + target is the control-plane and infrastructure topology this transition would + move to. target is required. + properties: + controlPlaneTopology: + description: |- + controlPlaneTopology is the topology of the control-plane nodes. Valid values + are SingleReplica and HighlyAvailable. When set to SingleReplica, operators + avoid spending resources for high availability. When set to HighlyAvailable, + operators configure high availability as much as possible. + controlPlaneTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + infrastructureTopology: + description: |- + infrastructureTopology is the topology of infrastructure services. Valid + values are SingleReplica and HighlyAvailable. When set to SingleReplica, + operators avoid spending resources for high availability. When set to + HighlyAvailable, operators configure high availability as much as possible. + infrastructureTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + required: + - controlPlaneTopology + - infrastructureTopology + type: object + required: + - source + - target + type: object + maxItems: 1 + type: array + x-kubernetes-list-type: atomic + required: + - supportedTransitions + type: object type: object required: - spec @@ -3180,6 +3402,12 @@ spec: == self.status.controlPlaneTopology) || (has(self.status.controlPlaneTopology) && self.status.controlPlaneTopology == ''SingleReplica'' && self.spec.controlPlaneTopology == ''HighlyAvailable'')' + - message: transition sources must match the current status topology + rule: '!has(self.status) || !has(self.status.topologyTransitionStatus) + || self.status.topologyTransitionStatus.supportedTransitions.all(t, + has(self.status.controlPlaneTopology) && has(self.status.infrastructureTopology) + && t.source.controlPlaneTopology == self.status.controlPlaneTopology + && t.source.infrastructureTopology == self.status.infrastructureTopology)' internalRegistryPullSecret: description: |- internalRegistryPullSecret is the pull secret for the internal registry, used by diff --git a/machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_controllerconfigs-SelfManagedHA-CustomNoUpgrade.crd.yaml b/machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_controllerconfigs-SelfManagedHA-CustomNoUpgrade.crd.yaml index 8e1534879d6..857dc4dd67b 100644 --- a/machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_controllerconfigs-SelfManagedHA-CustomNoUpgrade.crd.yaml +++ b/machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_controllerconfigs-SelfManagedHA-CustomNoUpgrade.crd.yaml @@ -3165,6 +3165,228 @@ spec: == ''Internal'' || (has(self.loadBalancer) && self.loadBalancer.type == ''UserManaged'')' type: object + topologyTransitionStatus: + description: |- + topologyTransitionStatus reports available topology transitions and current progress, if any. + It is omitted until the topology controller evaluates transitions. + properties: + conditions: + description: |- + conditions reports whether supported transitions have been evaluated. + TopologyTransitionsEvaluated is Unknown before evaluation, True when evaluation + succeeds (even if no transitions are supported), and False when evaluation fails. + An absent condition means evaluation has not completed. + At most one condition is present. + 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 + maxItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentTransition: + description: currentTransition is omitted until a topology + transition starts. + properties: + completionTime: + description: completionTime is when the transition + was fully applied. It is omitted while a transition + is being applied. + format: date-time + type: string + message: + description: |- + message is human-readable information about the reason for the current state. + It must be between 1 and 2048 characters long. + maxLength: 2048 + minLength: 1 + type: string + reason: + description: |- + reason indicates why current state is as reported. + It must be between 1 and 128 characters long. + maxLength: 128 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the + transition was started. When omitted, the start + time is not available. + format: date-time + type: string + state: + description: |- + state indicates the current state of a triggered transition. + Valid values are "Completed" when the transition was successfully applied, + "Partial" when it was not completely applied or is still in progress, and + "Failed" when it failed to apply. + enum: + - Completed + - Partial + - Failed + type: string + required: + - message + - reason + - state + type: object + supportedTransitions: + description: |- + supportedTransitions represents the transitions that are valid for this cluster. + An empty list means that no transitions are currently supported from the current topology. + At most one transition is supported currently (SNO to HA Compact) + items: + properties: + message: + description: |- + message is a human-readable explanation, primarily for Unavailable + transitions (e.g. a concise summary of the failing preconditions). It is for + humans only and must not be parsed. It may be truncated by the controller. + When omitted, no human-readable explanation is available for the transition. + When set, it must be between 1 and 2048 characters long. + maxLength: 2048 + minLength: 1 + type: string + reason: + description: |- + reason is a CamelCase machine-readable explanation of the availability, e.g. + PreflightCheckFailed. The set of reasons is diagnostic and not exhaustive. + When omitted, no machine-readable explanation is available. + Must start with an uppercase letter and contain only alphanumeric characters, + and must be between 1 and 128 characters long. + maxLength: 128 + minLength: 1 + type: string + x-kubernetes-validations: + - message: reason must be CamelCase, matching ^[A-Z][A-Za-z0-9]*$ + rule: self.matches('^[A-Z][A-Za-z0-9]*$') + source: + description: |- + source is the control-plane and infrastructure topology this transition starts + from. It must equal the current topology in the corresponding status fields. + source is required. + properties: + controlPlaneTopology: + description: |- + controlPlaneTopology is the topology of the control-plane nodes. Valid values + are SingleReplica and HighlyAvailable. When set to SingleReplica, operators + avoid spending resources for high availability. When set to HighlyAvailable, + operators configure high availability as much as possible. + controlPlaneTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + infrastructureTopology: + description: |- + infrastructureTopology is the topology of infrastructure services. Valid + values are SingleReplica and HighlyAvailable. When set to SingleReplica, + operators avoid spending resources for high availability. When set to + HighlyAvailable, operators configure high availability as much as possible. + infrastructureTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + required: + - controlPlaneTopology + - infrastructureTopology + type: object + target: + description: |- + target is the control-plane and infrastructure topology this transition would + move to. target is required. + properties: + controlPlaneTopology: + description: |- + controlPlaneTopology is the topology of the control-plane nodes. Valid values + are SingleReplica and HighlyAvailable. When set to SingleReplica, operators + avoid spending resources for high availability. When set to HighlyAvailable, + operators configure high availability as much as possible. + controlPlaneTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + infrastructureTopology: + description: |- + infrastructureTopology is the topology of infrastructure services. Valid + values are SingleReplica and HighlyAvailable. When set to SingleReplica, + operators avoid spending resources for high availability. When set to + HighlyAvailable, operators configure high availability as much as possible. + infrastructureTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + required: + - controlPlaneTopology + - infrastructureTopology + type: object + required: + - source + - target + type: object + maxItems: 1 + type: array + x-kubernetes-list-type: atomic + required: + - supportedTransitions + type: object type: object required: - spec @@ -3180,6 +3402,12 @@ spec: == self.status.controlPlaneTopology) || (has(self.status.controlPlaneTopology) && self.status.controlPlaneTopology == ''SingleReplica'' && self.spec.controlPlaneTopology == ''HighlyAvailable'')' + - message: transition sources must match the current status topology + rule: '!has(self.status) || !has(self.status.topologyTransitionStatus) + || self.status.topologyTransitionStatus.supportedTransitions.all(t, + has(self.status.controlPlaneTopology) && has(self.status.infrastructureTopology) + && t.source.controlPlaneTopology == self.status.controlPlaneTopology + && t.source.infrastructureTopology == self.status.infrastructureTopology)' internalRegistryPullSecret: description: |- internalRegistryPullSecret is the pull secret for the internal registry, used by diff --git a/machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_controllerconfigs-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml b/machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_controllerconfigs-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml index fb3e18ca85e..b9f8845f633 100644 --- a/machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_controllerconfigs-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml +++ b/machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_controllerconfigs-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml @@ -3165,6 +3165,228 @@ spec: == ''Internal'' || (has(self.loadBalancer) && self.loadBalancer.type == ''UserManaged'')' type: object + topologyTransitionStatus: + description: |- + topologyTransitionStatus reports available topology transitions and current progress, if any. + It is omitted until the topology controller evaluates transitions. + properties: + conditions: + description: |- + conditions reports whether supported transitions have been evaluated. + TopologyTransitionsEvaluated is Unknown before evaluation, True when evaluation + succeeds (even if no transitions are supported), and False when evaluation fails. + An absent condition means evaluation has not completed. + At most one condition is present. + 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 + maxItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentTransition: + description: currentTransition is omitted until a topology + transition starts. + properties: + completionTime: + description: completionTime is when the transition + was fully applied. It is omitted while a transition + is being applied. + format: date-time + type: string + message: + description: |- + message is human-readable information about the reason for the current state. + It must be between 1 and 2048 characters long. + maxLength: 2048 + minLength: 1 + type: string + reason: + description: |- + reason indicates why current state is as reported. + It must be between 1 and 128 characters long. + maxLength: 128 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the + transition was started. When omitted, the start + time is not available. + format: date-time + type: string + state: + description: |- + state indicates the current state of a triggered transition. + Valid values are "Completed" when the transition was successfully applied, + "Partial" when it was not completely applied or is still in progress, and + "Failed" when it failed to apply. + enum: + - Completed + - Partial + - Failed + type: string + required: + - message + - reason + - state + type: object + supportedTransitions: + description: |- + supportedTransitions represents the transitions that are valid for this cluster. + An empty list means that no transitions are currently supported from the current topology. + At most one transition is supported currently (SNO to HA Compact) + items: + properties: + message: + description: |- + message is a human-readable explanation, primarily for Unavailable + transitions (e.g. a concise summary of the failing preconditions). It is for + humans only and must not be parsed. It may be truncated by the controller. + When omitted, no human-readable explanation is available for the transition. + When set, it must be between 1 and 2048 characters long. + maxLength: 2048 + minLength: 1 + type: string + reason: + description: |- + reason is a CamelCase machine-readable explanation of the availability, e.g. + PreflightCheckFailed. The set of reasons is diagnostic and not exhaustive. + When omitted, no machine-readable explanation is available. + Must start with an uppercase letter and contain only alphanumeric characters, + and must be between 1 and 128 characters long. + maxLength: 128 + minLength: 1 + type: string + x-kubernetes-validations: + - message: reason must be CamelCase, matching ^[A-Z][A-Za-z0-9]*$ + rule: self.matches('^[A-Z][A-Za-z0-9]*$') + source: + description: |- + source is the control-plane and infrastructure topology this transition starts + from. It must equal the current topology in the corresponding status fields. + source is required. + properties: + controlPlaneTopology: + description: |- + controlPlaneTopology is the topology of the control-plane nodes. Valid values + are SingleReplica and HighlyAvailable. When set to SingleReplica, operators + avoid spending resources for high availability. When set to HighlyAvailable, + operators configure high availability as much as possible. + controlPlaneTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + infrastructureTopology: + description: |- + infrastructureTopology is the topology of infrastructure services. Valid + values are SingleReplica and HighlyAvailable. When set to SingleReplica, + operators avoid spending resources for high availability. When set to + HighlyAvailable, operators configure high availability as much as possible. + infrastructureTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + required: + - controlPlaneTopology + - infrastructureTopology + type: object + target: + description: |- + target is the control-plane and infrastructure topology this transition would + move to. target is required. + properties: + controlPlaneTopology: + description: |- + controlPlaneTopology is the topology of the control-plane nodes. Valid values + are SingleReplica and HighlyAvailable. When set to SingleReplica, operators + avoid spending resources for high availability. When set to HighlyAvailable, + operators configure high availability as much as possible. + controlPlaneTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + infrastructureTopology: + description: |- + infrastructureTopology is the topology of infrastructure services. Valid + values are SingleReplica and HighlyAvailable. When set to SingleReplica, + operators avoid spending resources for high availability. When set to + HighlyAvailable, operators configure high availability as much as possible. + infrastructureTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + required: + - controlPlaneTopology + - infrastructureTopology + type: object + required: + - source + - target + type: object + maxItems: 1 + type: array + x-kubernetes-list-type: atomic + required: + - supportedTransitions + type: object type: object required: - spec @@ -3180,6 +3402,12 @@ spec: == self.status.controlPlaneTopology) || (has(self.status.controlPlaneTopology) && self.status.controlPlaneTopology == ''SingleReplica'' && self.spec.controlPlaneTopology == ''HighlyAvailable'')' + - message: transition sources must match the current status topology + rule: '!has(self.status) || !has(self.status.topologyTransitionStatus) + || self.status.topologyTransitionStatus.supportedTransitions.all(t, + has(self.status.controlPlaneTopology) && has(self.status.infrastructureTopology) + && t.source.controlPlaneTopology == self.status.controlPlaneTopology + && t.source.infrastructureTopology == self.status.infrastructureTopology)' internalRegistryPullSecret: description: |- internalRegistryPullSecret is the pull secret for the internal registry, used by diff --git a/machineconfiguration/v1/zz_generated.featuregated-crd-manifests/controllerconfigs.machineconfiguration.openshift.io/MutableTopology.yaml b/machineconfiguration/v1/zz_generated.featuregated-crd-manifests/controllerconfigs.machineconfiguration.openshift.io/MutableTopology.yaml index 3d7117d83f3..7a2e5f465b7 100644 --- a/machineconfiguration/v1/zz_generated.featuregated-crd-manifests/controllerconfigs.machineconfiguration.openshift.io/MutableTopology.yaml +++ b/machineconfiguration/v1/zz_generated.featuregated-crd-manifests/controllerconfigs.machineconfiguration.openshift.io/MutableTopology.yaml @@ -2738,6 +2738,228 @@ spec: type: string type: object type: object + topologyTransitionStatus: + description: |- + topologyTransitionStatus reports available topology transitions and current progress, if any. + It is omitted until the topology controller evaluates transitions. + properties: + conditions: + description: |- + conditions reports whether supported transitions have been evaluated. + TopologyTransitionsEvaluated is Unknown before evaluation, True when evaluation + succeeds (even if no transitions are supported), and False when evaluation fails. + An absent condition means evaluation has not completed. + At most one condition is present. + 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 + maxItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentTransition: + description: currentTransition is omitted until a topology + transition starts. + properties: + completionTime: + description: completionTime is when the transition + was fully applied. It is omitted while a transition + is being applied. + format: date-time + type: string + message: + description: |- + message is human-readable information about the reason for the current state. + It must be between 1 and 2048 characters long. + maxLength: 2048 + minLength: 1 + type: string + reason: + description: |- + reason indicates why current state is as reported. + It must be between 1 and 128 characters long. + maxLength: 128 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the + transition was started. When omitted, the start + time is not available. + format: date-time + type: string + state: + description: |- + state indicates the current state of a triggered transition. + Valid values are "Completed" when the transition was successfully applied, + "Partial" when it was not completely applied or is still in progress, and + "Failed" when it failed to apply. + enum: + - Completed + - Partial + - Failed + type: string + required: + - message + - reason + - state + type: object + supportedTransitions: + description: |- + supportedTransitions represents the transitions that are valid for this cluster. + An empty list means that no transitions are currently supported from the current topology. + At most one transition is supported currently (SNO to HA Compact) + items: + properties: + message: + description: |- + message is a human-readable explanation, primarily for Unavailable + transitions (e.g. a concise summary of the failing preconditions). It is for + humans only and must not be parsed. It may be truncated by the controller. + When omitted, no human-readable explanation is available for the transition. + When set, it must be between 1 and 2048 characters long. + maxLength: 2048 + minLength: 1 + type: string + reason: + description: |- + reason is a CamelCase machine-readable explanation of the availability, e.g. + PreflightCheckFailed. The set of reasons is diagnostic and not exhaustive. + When omitted, no machine-readable explanation is available. + Must start with an uppercase letter and contain only alphanumeric characters, + and must be between 1 and 128 characters long. + maxLength: 128 + minLength: 1 + type: string + x-kubernetes-validations: + - message: reason must be CamelCase, matching ^[A-Z][A-Za-z0-9]*$ + rule: self.matches('^[A-Z][A-Za-z0-9]*$') + source: + description: |- + source is the control-plane and infrastructure topology this transition starts + from. It must equal the current topology in the corresponding status fields. + source is required. + properties: + controlPlaneTopology: + description: |- + controlPlaneTopology is the topology of the control-plane nodes. Valid values + are SingleReplica and HighlyAvailable. When set to SingleReplica, operators + avoid spending resources for high availability. When set to HighlyAvailable, + operators configure high availability as much as possible. + controlPlaneTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + infrastructureTopology: + description: |- + infrastructureTopology is the topology of infrastructure services. Valid + values are SingleReplica and HighlyAvailable. When set to SingleReplica, + operators avoid spending resources for high availability. When set to + HighlyAvailable, operators configure high availability as much as possible. + infrastructureTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + required: + - controlPlaneTopology + - infrastructureTopology + type: object + target: + description: |- + target is the control-plane and infrastructure topology this transition would + move to. target is required. + properties: + controlPlaneTopology: + description: |- + controlPlaneTopology is the topology of the control-plane nodes. Valid values + are SingleReplica and HighlyAvailable. When set to SingleReplica, operators + avoid spending resources for high availability. When set to HighlyAvailable, + operators configure high availability as much as possible. + controlPlaneTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + infrastructureTopology: + description: |- + infrastructureTopology is the topology of infrastructure services. Valid + values are SingleReplica and HighlyAvailable. When set to SingleReplica, + operators avoid spending resources for high availability. When set to + HighlyAvailable, operators configure high availability as much as possible. + infrastructureTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + required: + - controlPlaneTopology + - infrastructureTopology + type: object + required: + - source + - target + type: object + maxItems: 1 + type: array + x-kubernetes-list-type: atomic + required: + - supportedTransitions + type: object type: object required: - spec @@ -2753,6 +2975,12 @@ spec: == self.status.controlPlaneTopology) || (has(self.status.controlPlaneTopology) && self.status.controlPlaneTopology == ''SingleReplica'' && self.spec.controlPlaneTopology == ''HighlyAvailable'')' + - message: transition sources must match the current status topology + rule: '!has(self.status) || !has(self.status.topologyTransitionStatus) + || self.status.topologyTransitionStatus.supportedTransitions.all(t, + has(self.status.controlPlaneTopology) && has(self.status.infrastructureTopology) + && t.source.controlPlaneTopology == self.status.controlPlaneTopology + && t.source.infrastructureTopology == self.status.infrastructureTopology)' internalRegistryPullSecret: description: |- internalRegistryPullSecret is the pull secret for the internal registry, used by diff --git a/openapi/generated_openapi/zz_generated.openapi.go b/openapi/generated_openapi/zz_generated.openapi.go index 16f4728a9ae..0a48401775f 100644 --- a/openapi/generated_openapi/zz_generated.openapi.go +++ b/openapi/generated_openapi/zz_generated.openapi.go @@ -492,6 +492,10 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA configv1.TokenIssuer{}.OpenAPIModelName(): schema_openshift_api_config_v1_TokenIssuer(ref), configv1.TokenRequiredClaim{}.OpenAPIModelName(): schema_openshift_api_config_v1_TokenRequiredClaim(ref), configv1.TokenUserValidationRule{}.OpenAPIModelName(): schema_openshift_api_config_v1_TokenUserValidationRule(ref), + configv1.TopologyState{}.OpenAPIModelName(): schema_openshift_api_config_v1_TopologyState(ref), + configv1.TopologyTransition{}.OpenAPIModelName(): schema_openshift_api_config_v1_TopologyTransition(ref), + configv1.TopologyTransitionProgress{}.OpenAPIModelName(): schema_openshift_api_config_v1_TopologyTransitionProgress(ref), + configv1.TopologyTransitionStatus{}.OpenAPIModelName(): schema_openshift_api_config_v1_TopologyTransitionStatus(ref), configv1.Update{}.OpenAPIModelName(): schema_openshift_api_config_v1_Update(ref), configv1.UpdateHistory{}.OpenAPIModelName(): schema_openshift_api_config_v1_UpdateHistory(ref), configv1.UsernameClaimMapping{}.OpenAPIModelName(): schema_openshift_api_config_v1_UsernameClaimMapping(ref), @@ -16401,6 +16405,12 @@ func schema_openshift_api_config_v1_InfrastructureStatus(ref common.ReferenceCal Format: "", }, }, + "topologyTransitionStatus": { + SchemaProps: spec.SchemaProps{ + Description: "topologyTransitionStatus reports available topology transitions and current progress, if any. It is omitted until the topology controller evaluates transitions.", + Ref: ref(configv1.TopologyTransitionStatus{}.OpenAPIModelName()), + }, + }, "cpuPartitioning": { SchemaProps: spec.SchemaProps{ Description: "cpuPartitioning expresses if CPU partitioning is a currently enabled feature in the cluster. CPU Partitioning means that this cluster can support partitioning workloads to specific CPU Sets. Valid values are \"None\" and \"AllNodes\". When omitted, the default value is \"None\". The default value of \"None\" indicates that no nodes will be setup with CPU partitioning. The \"AllNodes\" value indicates that all nodes have been setup with CPU partitioning, and can then be further configured via the PerformanceProfile API.", @@ -16413,7 +16423,7 @@ func schema_openshift_api_config_v1_InfrastructureStatus(ref common.ReferenceCal }, }, Dependencies: []string{ - configv1.PlatformStatus{}.OpenAPIModelName()}, + configv1.PlatformStatus{}.OpenAPIModelName(), configv1.TopologyTransitionStatus{}.OpenAPIModelName()}, } } @@ -22218,6 +22228,188 @@ func schema_openshift_api_config_v1_TokenUserValidationRule(ref common.Reference } } +func schema_openshift_api_config_v1_TopologyState(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TopologyState describes the control-plane and infrastructure topology at one end of a topology transition.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "controlPlaneTopology": { + SchemaProps: spec.SchemaProps{ + Description: "controlPlaneTopology is the topology of the control-plane nodes. Valid values are SingleReplica and HighlyAvailable. When set to SingleReplica, operators avoid spending resources for high availability. When set to HighlyAvailable, operators configure high availability as much as possible. controlPlaneTopology is required.", + Type: []string{"string"}, + Format: "", + }, + }, + "infrastructureTopology": { + SchemaProps: spec.SchemaProps{ + Description: "infrastructureTopology is the topology of infrastructure services. Valid values are SingleReplica and HighlyAvailable. When set to SingleReplica, operators avoid spending resources for high availability. When set to HighlyAvailable, operators configure high availability as much as possible. infrastructureTopology is required.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"controlPlaneTopology", "infrastructureTopology"}, + }, + }, + } +} + +func schema_openshift_api_config_v1_TopologyTransition(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "source": { + SchemaProps: spec.SchemaProps{ + Description: "source is the control-plane and infrastructure topology this transition starts from. It must equal the current topology in the corresponding status fields. source is required.", + Default: map[string]interface{}{}, + Ref: ref(configv1.TopologyState{}.OpenAPIModelName()), + }, + }, + "target": { + SchemaProps: spec.SchemaProps{ + Description: "target is the control-plane and infrastructure topology this transition would move to. target is required.", + Default: map[string]interface{}{}, + Ref: ref(configv1.TopologyState{}.OpenAPIModelName()), + }, + }, + "reason": { + SchemaProps: spec.SchemaProps{ + Description: "reason is a CamelCase machine-readable explanation of the availability, e.g. PreflightCheckFailed. The set of reasons is diagnostic and not exhaustive. When omitted, no machine-readable explanation is available. Must start with an uppercase letter and contain only alphanumeric characters, and must be between 1 and 128 characters long.", + Type: []string{"string"}, + Format: "", + }, + }, + "message": { + SchemaProps: spec.SchemaProps{ + Description: "message is a human-readable explanation, primarily for Unavailable transitions (e.g. a concise summary of the failing preconditions). It is for humans only and must not be parsed. It may be truncated by the controller. When omitted, no human-readable explanation is available for the transition. When set, it must be between 1 and 2048 characters long.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"source", "target"}, + }, + }, + Dependencies: []string{ + configv1.TopologyState{}.OpenAPIModelName()}, + } +} + +func schema_openshift_api_config_v1_TopologyTransitionProgress(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TopologyTransitionProgress describes a topology transition that has started.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "state": { + SchemaProps: spec.SchemaProps{ + Description: "state indicates the current state of a triggered transition. Valid values are \"Completed\" when the transition was successfully applied, \"Partial\" when it was not completely applied or is still in progress, and \"Failed\" when it failed to apply.", + Type: []string{"string"}, + Format: "", + }, + }, + "reason": { + SchemaProps: spec.SchemaProps{ + Description: "reason indicates why current state is as reported. It must be between 1 and 128 characters long.", + Type: []string{"string"}, + Format: "", + }, + }, + "message": { + SchemaProps: spec.SchemaProps{ + Description: "message is human-readable information about the reason for the current state. It must be between 1 and 2048 characters long.", + Type: []string{"string"}, + Format: "", + }, + }, + "startedTime": { + SchemaProps: spec.SchemaProps{ + Description: "startedTime is the time at which the transition was started. When omitted, the start time is not available.", + Ref: ref(metav1.Time{}.OpenAPIModelName()), + }, + }, + "completionTime": { + SchemaProps: spec.SchemaProps{ + Description: "completionTime is when the transition was fully applied. It is omitted while a transition is being applied.", + Ref: ref(metav1.Time{}.OpenAPIModelName()), + }, + }, + }, + Required: []string{"state", "reason", "message"}, + }, + }, + Dependencies: []string{ + metav1.Time{}.OpenAPIModelName()}, + } +} + +func schema_openshift_api_config_v1_TopologyTransitionStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "conditions": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "type", + }, + "x-kubernetes-list-type": "map", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "conditions reports whether supported transitions have been evaluated. TopologyTransitionsEvaluated is Unknown before evaluation, True when evaluation succeeds (even if no transitions are supported), and False when evaluation fails. An absent condition means evaluation has not completed. At most one condition is present.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref(metav1.Condition{}.OpenAPIModelName()), + }, + }, + }, + }, + }, + "supportedTransitions": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "supportedTransitions represents the transitions that are valid for this cluster. An empty list means that no transitions are currently supported from the current topology. At most one transition is supported currently (SNO to HA Compact)", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref(configv1.TopologyTransition{}.OpenAPIModelName()), + }, + }, + }, + }, + }, + "currentTransition": { + SchemaProps: spec.SchemaProps{ + Description: "currentTransition is omitted until a topology transition starts.", + Ref: ref(configv1.TopologyTransitionProgress{}.OpenAPIModelName()), + }, + }, + }, + Required: []string{"supportedTransitions"}, + }, + }, + Dependencies: []string{ + configv1.TopologyTransition{}.OpenAPIModelName(), configv1.TopologyTransitionProgress{}.OpenAPIModelName(), metav1.Condition{}.OpenAPIModelName()}, + } +} + func schema_openshift_api_config_v1_Update(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/openapi/openapi.json b/openapi/openapi.json index 99f806ce8fe..7d388efe39e 100644 --- a/openapi/openapi.json +++ b/openapi/openapi.json @@ -8602,6 +8602,10 @@ "platformStatus": { "description": "platformStatus holds status information specific to the underlying infrastructure provider.", "$ref": "#/definitions/com.github.openshift.api.config.v1.PlatformStatus" + }, + "topologyTransitionStatus": { + "description": "topologyTransitionStatus reports available topology transitions and current progress, if any. It is omitted until the topology controller evaluates transitions.", + "$ref": "#/definitions/com.github.openshift.api.config.v1.TopologyTransitionStatus" } } }, @@ -12009,6 +12013,115 @@ } } }, + "com.github.openshift.api.config.v1.TopologyState": { + "description": "TopologyState describes the control-plane and infrastructure topology at one end of a topology transition.", + "type": "object", + "required": [ + "controlPlaneTopology", + "infrastructureTopology" + ], + "properties": { + "controlPlaneTopology": { + "description": "controlPlaneTopology is the topology of the control-plane nodes. Valid values are SingleReplica and HighlyAvailable. When set to SingleReplica, operators avoid spending resources for high availability. When set to HighlyAvailable, operators configure high availability as much as possible. controlPlaneTopology is required.", + "type": "string" + }, + "infrastructureTopology": { + "description": "infrastructureTopology is the topology of infrastructure services. Valid values are SingleReplica and HighlyAvailable. When set to SingleReplica, operators avoid spending resources for high availability. When set to HighlyAvailable, operators configure high availability as much as possible. infrastructureTopology is required.", + "type": "string" + } + } + }, + "com.github.openshift.api.config.v1.TopologyTransition": { + "type": "object", + "required": [ + "source", + "target" + ], + "properties": { + "message": { + "description": "message is a human-readable explanation, primarily for Unavailable transitions (e.g. a concise summary of the failing preconditions). It is for humans only and must not be parsed. It may be truncated by the controller. When omitted, no human-readable explanation is available for the transition. When set, it must be between 1 and 2048 characters long.", + "type": "string" + }, + "reason": { + "description": "reason is a CamelCase machine-readable explanation of the availability, e.g. PreflightCheckFailed. The set of reasons is diagnostic and not exhaustive. When omitted, no machine-readable explanation is available. Must start with an uppercase letter and contain only alphanumeric characters, and must be between 1 and 128 characters long.", + "type": "string" + }, + "source": { + "description": "source is the control-plane and infrastructure topology this transition starts from. It must equal the current topology in the corresponding status fields. source is required.", + "default": {}, + "$ref": "#/definitions/com.github.openshift.api.config.v1.TopologyState" + }, + "target": { + "description": "target is the control-plane and infrastructure topology this transition would move to. target is required.", + "default": {}, + "$ref": "#/definitions/com.github.openshift.api.config.v1.TopologyState" + } + } + }, + "com.github.openshift.api.config.v1.TopologyTransitionProgress": { + "description": "TopologyTransitionProgress describes a topology transition that has started.", + "type": "object", + "required": [ + "state", + "reason", + "message" + ], + "properties": { + "completionTime": { + "description": "completionTime is when the transition was fully applied. It is omitted while a transition is being applied.", + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Time" + }, + "message": { + "description": "message is human-readable information about the reason for the current state. It must be between 1 and 2048 characters long.", + "type": "string" + }, + "reason": { + "description": "reason indicates why current state is as reported. It must be between 1 and 128 characters long.", + "type": "string" + }, + "startedTime": { + "description": "startedTime is the time at which the transition was started. When omitted, the start time is not available.", + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Time" + }, + "state": { + "description": "state indicates the current state of a triggered transition. Valid values are \"Completed\" when the transition was successfully applied, \"Partial\" when it was not completely applied or is still in progress, and \"Failed\" when it failed to apply.", + "type": "string" + } + } + }, + "com.github.openshift.api.config.v1.TopologyTransitionStatus": { + "type": "object", + "required": [ + "supportedTransitions" + ], + "properties": { + "conditions": { + "description": "conditions reports whether supported transitions have been evaluated. TopologyTransitionsEvaluated is Unknown before evaluation, True when evaluation succeeds (even if no transitions are supported), and False when evaluation fails. An absent condition means evaluation has not completed. At most one condition is present.", + "type": "array", + "items": { + "default": {}, + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Condition" + }, + "x-kubernetes-list-map-keys": [ + "type" + ], + "x-kubernetes-list-type": "map" + }, + "currentTransition": { + "description": "currentTransition is omitted until a topology transition starts.", + "$ref": "#/definitions/com.github.openshift.api.config.v1.TopologyTransitionProgress" + }, + "supportedTransitions": { + "description": "supportedTransitions represents the transitions that are valid for this cluster. An empty list means that no transitions are currently supported from the current topology. At most one transition is supported currently (SNO to HA Compact)", + "type": "array", + "items": { + "default": {}, + "$ref": "#/definitions/com.github.openshift.api.config.v1.TopologyTransition" + }, + "x-kubernetes-list-type": "atomic" + } + } + }, "com.github.openshift.api.config.v1.Update": { "description": "Update represents an administrator update request.", "type": "object", diff --git a/payload-manifests/crds/0000_10_config-operator_01_infrastructures-Hypershift-CustomNoUpgrade.crd.yaml b/payload-manifests/crds/0000_10_config-operator_01_infrastructures-Hypershift-CustomNoUpgrade.crd.yaml index 7a35e5fc0f7..fbc2483dda1 100644 --- a/payload-manifests/crds/0000_10_config-operator_01_infrastructures-Hypershift-CustomNoUpgrade.crd.yaml +++ b/payload-manifests/crds/0000_10_config-operator_01_infrastructures-Hypershift-CustomNoUpgrade.crd.yaml @@ -2843,6 +2843,225 @@ spec: rule: '!has(self.dnsRecordsType) || self.dnsRecordsType == ''Internal'' || (has(self.loadBalancer) && self.loadBalancer.type == ''UserManaged'')' type: object + topologyTransitionStatus: + description: |- + topologyTransitionStatus reports available topology transitions and current progress, if any. + It is omitted until the topology controller evaluates transitions. + properties: + conditions: + description: |- + conditions reports whether supported transitions have been evaluated. + TopologyTransitionsEvaluated is Unknown before evaluation, True when evaluation + succeeds (even if no transitions are supported), and False when evaluation fails. + An absent condition means evaluation has not completed. + At most one condition is present. + 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 + maxItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentTransition: + description: currentTransition is omitted until a topology transition + starts. + properties: + completionTime: + description: completionTime is when the transition was fully + applied. It is omitted while a transition is being applied. + format: date-time + type: string + message: + description: |- + message is human-readable information about the reason for the current state. + It must be between 1 and 2048 characters long. + maxLength: 2048 + minLength: 1 + type: string + reason: + description: |- + reason indicates why current state is as reported. + It must be between 1 and 128 characters long. + maxLength: 128 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the transition + was started. When omitted, the start time is not available. + format: date-time + type: string + state: + description: |- + state indicates the current state of a triggered transition. + Valid values are "Completed" when the transition was successfully applied, + "Partial" when it was not completely applied or is still in progress, and + "Failed" when it failed to apply. + enum: + - Completed + - Partial + - Failed + type: string + required: + - message + - reason + - state + type: object + supportedTransitions: + description: |- + supportedTransitions represents the transitions that are valid for this cluster. + An empty list means that no transitions are currently supported from the current topology. + At most one transition is supported currently (SNO to HA Compact) + items: + properties: + message: + description: |- + message is a human-readable explanation, primarily for Unavailable + transitions (e.g. a concise summary of the failing preconditions). It is for + humans only and must not be parsed. It may be truncated by the controller. + When omitted, no human-readable explanation is available for the transition. + When set, it must be between 1 and 2048 characters long. + maxLength: 2048 + minLength: 1 + type: string + reason: + description: |- + reason is a CamelCase machine-readable explanation of the availability, e.g. + PreflightCheckFailed. The set of reasons is diagnostic and not exhaustive. + When omitted, no machine-readable explanation is available. + Must start with an uppercase letter and contain only alphanumeric characters, + and must be between 1 and 128 characters long. + maxLength: 128 + minLength: 1 + type: string + x-kubernetes-validations: + - message: reason must be CamelCase, matching ^[A-Z][A-Za-z0-9]*$ + rule: self.matches('^[A-Z][A-Za-z0-9]*$') + source: + description: |- + source is the control-plane and infrastructure topology this transition starts + from. It must equal the current topology in the corresponding status fields. + source is required. + properties: + controlPlaneTopology: + description: |- + controlPlaneTopology is the topology of the control-plane nodes. Valid values + are SingleReplica and HighlyAvailable. When set to SingleReplica, operators + avoid spending resources for high availability. When set to HighlyAvailable, + operators configure high availability as much as possible. + controlPlaneTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + infrastructureTopology: + description: |- + infrastructureTopology is the topology of infrastructure services. Valid + values are SingleReplica and HighlyAvailable. When set to SingleReplica, + operators avoid spending resources for high availability. When set to + HighlyAvailable, operators configure high availability as much as possible. + infrastructureTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + required: + - controlPlaneTopology + - infrastructureTopology + type: object + target: + description: |- + target is the control-plane and infrastructure topology this transition would + move to. target is required. + properties: + controlPlaneTopology: + description: |- + controlPlaneTopology is the topology of the control-plane nodes. Valid values + are SingleReplica and HighlyAvailable. When set to SingleReplica, operators + avoid spending resources for high availability. When set to HighlyAvailable, + operators configure high availability as much as possible. + controlPlaneTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + infrastructureTopology: + description: |- + infrastructureTopology is the topology of infrastructure services. Valid + values are SingleReplica and HighlyAvailable. When set to SingleReplica, + operators avoid spending resources for high availability. When set to + HighlyAvailable, operators configure high availability as much as possible. + infrastructureTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + required: + - controlPlaneTopology + - infrastructureTopology + type: object + required: + - source + - target + type: object + maxItems: 1 + type: array + x-kubernetes-list-type: atomic + required: + - supportedTransitions + type: object type: object required: - spec @@ -2856,6 +3075,12 @@ spec: == self.status.controlPlaneTopology) || (has(self.status.controlPlaneTopology) && self.status.controlPlaneTopology == ''SingleReplica'' && self.spec.controlPlaneTopology == ''HighlyAvailable'')' + - message: transition sources must match the current status topology + rule: '!has(self.status) || !has(self.status.topologyTransitionStatus) || + self.status.topologyTransitionStatus.supportedTransitions.all(t, has(self.status.controlPlaneTopology) + && has(self.status.infrastructureTopology) && t.source.controlPlaneTopology + == self.status.controlPlaneTopology && t.source.infrastructureTopology + == self.status.infrastructureTopology)' served: true storage: true subresources: diff --git a/payload-manifests/crds/0000_10_config-operator_01_infrastructures-SelfManagedHA-CustomNoUpgrade.crd.yaml b/payload-manifests/crds/0000_10_config-operator_01_infrastructures-SelfManagedHA-CustomNoUpgrade.crd.yaml index bbeff9ec02e..bc231b00eac 100644 --- a/payload-manifests/crds/0000_10_config-operator_01_infrastructures-SelfManagedHA-CustomNoUpgrade.crd.yaml +++ b/payload-manifests/crds/0000_10_config-operator_01_infrastructures-SelfManagedHA-CustomNoUpgrade.crd.yaml @@ -2843,6 +2843,225 @@ spec: rule: '!has(self.dnsRecordsType) || self.dnsRecordsType == ''Internal'' || (has(self.loadBalancer) && self.loadBalancer.type == ''UserManaged'')' type: object + topologyTransitionStatus: + description: |- + topologyTransitionStatus reports available topology transitions and current progress, if any. + It is omitted until the topology controller evaluates transitions. + properties: + conditions: + description: |- + conditions reports whether supported transitions have been evaluated. + TopologyTransitionsEvaluated is Unknown before evaluation, True when evaluation + succeeds (even if no transitions are supported), and False when evaluation fails. + An absent condition means evaluation has not completed. + At most one condition is present. + 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 + maxItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentTransition: + description: currentTransition is omitted until a topology transition + starts. + properties: + completionTime: + description: completionTime is when the transition was fully + applied. It is omitted while a transition is being applied. + format: date-time + type: string + message: + description: |- + message is human-readable information about the reason for the current state. + It must be between 1 and 2048 characters long. + maxLength: 2048 + minLength: 1 + type: string + reason: + description: |- + reason indicates why current state is as reported. + It must be between 1 and 128 characters long. + maxLength: 128 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the transition + was started. When omitted, the start time is not available. + format: date-time + type: string + state: + description: |- + state indicates the current state of a triggered transition. + Valid values are "Completed" when the transition was successfully applied, + "Partial" when it was not completely applied or is still in progress, and + "Failed" when it failed to apply. + enum: + - Completed + - Partial + - Failed + type: string + required: + - message + - reason + - state + type: object + supportedTransitions: + description: |- + supportedTransitions represents the transitions that are valid for this cluster. + An empty list means that no transitions are currently supported from the current topology. + At most one transition is supported currently (SNO to HA Compact) + items: + properties: + message: + description: |- + message is a human-readable explanation, primarily for Unavailable + transitions (e.g. a concise summary of the failing preconditions). It is for + humans only and must not be parsed. It may be truncated by the controller. + When omitted, no human-readable explanation is available for the transition. + When set, it must be between 1 and 2048 characters long. + maxLength: 2048 + minLength: 1 + type: string + reason: + description: |- + reason is a CamelCase machine-readable explanation of the availability, e.g. + PreflightCheckFailed. The set of reasons is diagnostic and not exhaustive. + When omitted, no machine-readable explanation is available. + Must start with an uppercase letter and contain only alphanumeric characters, + and must be between 1 and 128 characters long. + maxLength: 128 + minLength: 1 + type: string + x-kubernetes-validations: + - message: reason must be CamelCase, matching ^[A-Z][A-Za-z0-9]*$ + rule: self.matches('^[A-Z][A-Za-z0-9]*$') + source: + description: |- + source is the control-plane and infrastructure topology this transition starts + from. It must equal the current topology in the corresponding status fields. + source is required. + properties: + controlPlaneTopology: + description: |- + controlPlaneTopology is the topology of the control-plane nodes. Valid values + are SingleReplica and HighlyAvailable. When set to SingleReplica, operators + avoid spending resources for high availability. When set to HighlyAvailable, + operators configure high availability as much as possible. + controlPlaneTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + infrastructureTopology: + description: |- + infrastructureTopology is the topology of infrastructure services. Valid + values are SingleReplica and HighlyAvailable. When set to SingleReplica, + operators avoid spending resources for high availability. When set to + HighlyAvailable, operators configure high availability as much as possible. + infrastructureTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + required: + - controlPlaneTopology + - infrastructureTopology + type: object + target: + description: |- + target is the control-plane and infrastructure topology this transition would + move to. target is required. + properties: + controlPlaneTopology: + description: |- + controlPlaneTopology is the topology of the control-plane nodes. Valid values + are SingleReplica and HighlyAvailable. When set to SingleReplica, operators + avoid spending resources for high availability. When set to HighlyAvailable, + operators configure high availability as much as possible. + controlPlaneTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + infrastructureTopology: + description: |- + infrastructureTopology is the topology of infrastructure services. Valid + values are SingleReplica and HighlyAvailable. When set to SingleReplica, + operators avoid spending resources for high availability. When set to + HighlyAvailable, operators configure high availability as much as possible. + infrastructureTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + required: + - controlPlaneTopology + - infrastructureTopology + type: object + required: + - source + - target + type: object + maxItems: 1 + type: array + x-kubernetes-list-type: atomic + required: + - supportedTransitions + type: object type: object required: - spec @@ -2856,6 +3075,12 @@ spec: == self.status.controlPlaneTopology) || (has(self.status.controlPlaneTopology) && self.status.controlPlaneTopology == ''SingleReplica'' && self.spec.controlPlaneTopology == ''HighlyAvailable'')' + - message: transition sources must match the current status topology + rule: '!has(self.status) || !has(self.status.topologyTransitionStatus) || + self.status.topologyTransitionStatus.supportedTransitions.all(t, has(self.status.controlPlaneTopology) + && has(self.status.infrastructureTopology) && t.source.controlPlaneTopology + == self.status.controlPlaneTopology && t.source.infrastructureTopology + == self.status.infrastructureTopology)' served: true storage: true subresources: diff --git a/payload-manifests/crds/0000_10_config-operator_01_infrastructures-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml b/payload-manifests/crds/0000_10_config-operator_01_infrastructures-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml index 0207127aa67..e3eb7cc5429 100644 --- a/payload-manifests/crds/0000_10_config-operator_01_infrastructures-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml +++ b/payload-manifests/crds/0000_10_config-operator_01_infrastructures-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml @@ -2843,6 +2843,225 @@ spec: rule: '!has(self.dnsRecordsType) || self.dnsRecordsType == ''Internal'' || (has(self.loadBalancer) && self.loadBalancer.type == ''UserManaged'')' type: object + topologyTransitionStatus: + description: |- + topologyTransitionStatus reports available topology transitions and current progress, if any. + It is omitted until the topology controller evaluates transitions. + properties: + conditions: + description: |- + conditions reports whether supported transitions have been evaluated. + TopologyTransitionsEvaluated is Unknown before evaluation, True when evaluation + succeeds (even if no transitions are supported), and False when evaluation fails. + An absent condition means evaluation has not completed. + At most one condition is present. + 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 + maxItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentTransition: + description: currentTransition is omitted until a topology transition + starts. + properties: + completionTime: + description: completionTime is when the transition was fully + applied. It is omitted while a transition is being applied. + format: date-time + type: string + message: + description: |- + message is human-readable information about the reason for the current state. + It must be between 1 and 2048 characters long. + maxLength: 2048 + minLength: 1 + type: string + reason: + description: |- + reason indicates why current state is as reported. + It must be between 1 and 128 characters long. + maxLength: 128 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the transition + was started. When omitted, the start time is not available. + format: date-time + type: string + state: + description: |- + state indicates the current state of a triggered transition. + Valid values are "Completed" when the transition was successfully applied, + "Partial" when it was not completely applied or is still in progress, and + "Failed" when it failed to apply. + enum: + - Completed + - Partial + - Failed + type: string + required: + - message + - reason + - state + type: object + supportedTransitions: + description: |- + supportedTransitions represents the transitions that are valid for this cluster. + An empty list means that no transitions are currently supported from the current topology. + At most one transition is supported currently (SNO to HA Compact) + items: + properties: + message: + description: |- + message is a human-readable explanation, primarily for Unavailable + transitions (e.g. a concise summary of the failing preconditions). It is for + humans only and must not be parsed. It may be truncated by the controller. + When omitted, no human-readable explanation is available for the transition. + When set, it must be between 1 and 2048 characters long. + maxLength: 2048 + minLength: 1 + type: string + reason: + description: |- + reason is a CamelCase machine-readable explanation of the availability, e.g. + PreflightCheckFailed. The set of reasons is diagnostic and not exhaustive. + When omitted, no machine-readable explanation is available. + Must start with an uppercase letter and contain only alphanumeric characters, + and must be between 1 and 128 characters long. + maxLength: 128 + minLength: 1 + type: string + x-kubernetes-validations: + - message: reason must be CamelCase, matching ^[A-Z][A-Za-z0-9]*$ + rule: self.matches('^[A-Z][A-Za-z0-9]*$') + source: + description: |- + source is the control-plane and infrastructure topology this transition starts + from. It must equal the current topology in the corresponding status fields. + source is required. + properties: + controlPlaneTopology: + description: |- + controlPlaneTopology is the topology of the control-plane nodes. Valid values + are SingleReplica and HighlyAvailable. When set to SingleReplica, operators + avoid spending resources for high availability. When set to HighlyAvailable, + operators configure high availability as much as possible. + controlPlaneTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + infrastructureTopology: + description: |- + infrastructureTopology is the topology of infrastructure services. Valid + values are SingleReplica and HighlyAvailable. When set to SingleReplica, + operators avoid spending resources for high availability. When set to + HighlyAvailable, operators configure high availability as much as possible. + infrastructureTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + required: + - controlPlaneTopology + - infrastructureTopology + type: object + target: + description: |- + target is the control-plane and infrastructure topology this transition would + move to. target is required. + properties: + controlPlaneTopology: + description: |- + controlPlaneTopology is the topology of the control-plane nodes. Valid values + are SingleReplica and HighlyAvailable. When set to SingleReplica, operators + avoid spending resources for high availability. When set to HighlyAvailable, + operators configure high availability as much as possible. + controlPlaneTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + infrastructureTopology: + description: |- + infrastructureTopology is the topology of infrastructure services. Valid + values are SingleReplica and HighlyAvailable. When set to SingleReplica, + operators avoid spending resources for high availability. When set to + HighlyAvailable, operators configure high availability as much as possible. + infrastructureTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + required: + - controlPlaneTopology + - infrastructureTopology + type: object + required: + - source + - target + type: object + maxItems: 1 + type: array + x-kubernetes-list-type: atomic + required: + - supportedTransitions + type: object type: object required: - spec @@ -2856,6 +3075,12 @@ spec: == self.status.controlPlaneTopology) || (has(self.status.controlPlaneTopology) && self.status.controlPlaneTopology == ''SingleReplica'' && self.spec.controlPlaneTopology == ''HighlyAvailable'')' + - message: transition sources must match the current status topology + rule: '!has(self.status) || !has(self.status.topologyTransitionStatus) || + self.status.topologyTransitionStatus.supportedTransitions.all(t, has(self.status.controlPlaneTopology) + && has(self.status.infrastructureTopology) && t.source.controlPlaneTopology + == self.status.controlPlaneTopology && t.source.infrastructureTopology + == self.status.infrastructureTopology)' served: true storage: true subresources: diff --git a/payload-manifests/crds/0000_80_machine-config_01_controllerconfigs-Hypershift-CustomNoUpgrade.crd.yaml b/payload-manifests/crds/0000_80_machine-config_01_controllerconfigs-Hypershift-CustomNoUpgrade.crd.yaml index 273851bb919..ed332d83282 100644 --- a/payload-manifests/crds/0000_80_machine-config_01_controllerconfigs-Hypershift-CustomNoUpgrade.crd.yaml +++ b/payload-manifests/crds/0000_80_machine-config_01_controllerconfigs-Hypershift-CustomNoUpgrade.crd.yaml @@ -3165,6 +3165,228 @@ spec: == ''Internal'' || (has(self.loadBalancer) && self.loadBalancer.type == ''UserManaged'')' type: object + topologyTransitionStatus: + description: |- + topologyTransitionStatus reports available topology transitions and current progress, if any. + It is omitted until the topology controller evaluates transitions. + properties: + conditions: + description: |- + conditions reports whether supported transitions have been evaluated. + TopologyTransitionsEvaluated is Unknown before evaluation, True when evaluation + succeeds (even if no transitions are supported), and False when evaluation fails. + An absent condition means evaluation has not completed. + At most one condition is present. + 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 + maxItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentTransition: + description: currentTransition is omitted until a topology + transition starts. + properties: + completionTime: + description: completionTime is when the transition + was fully applied. It is omitted while a transition + is being applied. + format: date-time + type: string + message: + description: |- + message is human-readable information about the reason for the current state. + It must be between 1 and 2048 characters long. + maxLength: 2048 + minLength: 1 + type: string + reason: + description: |- + reason indicates why current state is as reported. + It must be between 1 and 128 characters long. + maxLength: 128 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the + transition was started. When omitted, the start + time is not available. + format: date-time + type: string + state: + description: |- + state indicates the current state of a triggered transition. + Valid values are "Completed" when the transition was successfully applied, + "Partial" when it was not completely applied or is still in progress, and + "Failed" when it failed to apply. + enum: + - Completed + - Partial + - Failed + type: string + required: + - message + - reason + - state + type: object + supportedTransitions: + description: |- + supportedTransitions represents the transitions that are valid for this cluster. + An empty list means that no transitions are currently supported from the current topology. + At most one transition is supported currently (SNO to HA Compact) + items: + properties: + message: + description: |- + message is a human-readable explanation, primarily for Unavailable + transitions (e.g. a concise summary of the failing preconditions). It is for + humans only and must not be parsed. It may be truncated by the controller. + When omitted, no human-readable explanation is available for the transition. + When set, it must be between 1 and 2048 characters long. + maxLength: 2048 + minLength: 1 + type: string + reason: + description: |- + reason is a CamelCase machine-readable explanation of the availability, e.g. + PreflightCheckFailed. The set of reasons is diagnostic and not exhaustive. + When omitted, no machine-readable explanation is available. + Must start with an uppercase letter and contain only alphanumeric characters, + and must be between 1 and 128 characters long. + maxLength: 128 + minLength: 1 + type: string + x-kubernetes-validations: + - message: reason must be CamelCase, matching ^[A-Z][A-Za-z0-9]*$ + rule: self.matches('^[A-Z][A-Za-z0-9]*$') + source: + description: |- + source is the control-plane and infrastructure topology this transition starts + from. It must equal the current topology in the corresponding status fields. + source is required. + properties: + controlPlaneTopology: + description: |- + controlPlaneTopology is the topology of the control-plane nodes. Valid values + are SingleReplica and HighlyAvailable. When set to SingleReplica, operators + avoid spending resources for high availability. When set to HighlyAvailable, + operators configure high availability as much as possible. + controlPlaneTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + infrastructureTopology: + description: |- + infrastructureTopology is the topology of infrastructure services. Valid + values are SingleReplica and HighlyAvailable. When set to SingleReplica, + operators avoid spending resources for high availability. When set to + HighlyAvailable, operators configure high availability as much as possible. + infrastructureTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + required: + - controlPlaneTopology + - infrastructureTopology + type: object + target: + description: |- + target is the control-plane and infrastructure topology this transition would + move to. target is required. + properties: + controlPlaneTopology: + description: |- + controlPlaneTopology is the topology of the control-plane nodes. Valid values + are SingleReplica and HighlyAvailable. When set to SingleReplica, operators + avoid spending resources for high availability. When set to HighlyAvailable, + operators configure high availability as much as possible. + controlPlaneTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + infrastructureTopology: + description: |- + infrastructureTopology is the topology of infrastructure services. Valid + values are SingleReplica and HighlyAvailable. When set to SingleReplica, + operators avoid spending resources for high availability. When set to + HighlyAvailable, operators configure high availability as much as possible. + infrastructureTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + required: + - controlPlaneTopology + - infrastructureTopology + type: object + required: + - source + - target + type: object + maxItems: 1 + type: array + x-kubernetes-list-type: atomic + required: + - supportedTransitions + type: object type: object required: - spec @@ -3180,6 +3402,12 @@ spec: == self.status.controlPlaneTopology) || (has(self.status.controlPlaneTopology) && self.status.controlPlaneTopology == ''SingleReplica'' && self.spec.controlPlaneTopology == ''HighlyAvailable'')' + - message: transition sources must match the current status topology + rule: '!has(self.status) || !has(self.status.topologyTransitionStatus) + || self.status.topologyTransitionStatus.supportedTransitions.all(t, + has(self.status.controlPlaneTopology) && has(self.status.infrastructureTopology) + && t.source.controlPlaneTopology == self.status.controlPlaneTopology + && t.source.infrastructureTopology == self.status.infrastructureTopology)' internalRegistryPullSecret: description: |- internalRegistryPullSecret is the pull secret for the internal registry, used by diff --git a/payload-manifests/crds/0000_80_machine-config_01_controllerconfigs-SelfManagedHA-CustomNoUpgrade.crd.yaml b/payload-manifests/crds/0000_80_machine-config_01_controllerconfigs-SelfManagedHA-CustomNoUpgrade.crd.yaml index 8e1534879d6..857dc4dd67b 100644 --- a/payload-manifests/crds/0000_80_machine-config_01_controllerconfigs-SelfManagedHA-CustomNoUpgrade.crd.yaml +++ b/payload-manifests/crds/0000_80_machine-config_01_controllerconfigs-SelfManagedHA-CustomNoUpgrade.crd.yaml @@ -3165,6 +3165,228 @@ spec: == ''Internal'' || (has(self.loadBalancer) && self.loadBalancer.type == ''UserManaged'')' type: object + topologyTransitionStatus: + description: |- + topologyTransitionStatus reports available topology transitions and current progress, if any. + It is omitted until the topology controller evaluates transitions. + properties: + conditions: + description: |- + conditions reports whether supported transitions have been evaluated. + TopologyTransitionsEvaluated is Unknown before evaluation, True when evaluation + succeeds (even if no transitions are supported), and False when evaluation fails. + An absent condition means evaluation has not completed. + At most one condition is present. + 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 + maxItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentTransition: + description: currentTransition is omitted until a topology + transition starts. + properties: + completionTime: + description: completionTime is when the transition + was fully applied. It is omitted while a transition + is being applied. + format: date-time + type: string + message: + description: |- + message is human-readable information about the reason for the current state. + It must be between 1 and 2048 characters long. + maxLength: 2048 + minLength: 1 + type: string + reason: + description: |- + reason indicates why current state is as reported. + It must be between 1 and 128 characters long. + maxLength: 128 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the + transition was started. When omitted, the start + time is not available. + format: date-time + type: string + state: + description: |- + state indicates the current state of a triggered transition. + Valid values are "Completed" when the transition was successfully applied, + "Partial" when it was not completely applied or is still in progress, and + "Failed" when it failed to apply. + enum: + - Completed + - Partial + - Failed + type: string + required: + - message + - reason + - state + type: object + supportedTransitions: + description: |- + supportedTransitions represents the transitions that are valid for this cluster. + An empty list means that no transitions are currently supported from the current topology. + At most one transition is supported currently (SNO to HA Compact) + items: + properties: + message: + description: |- + message is a human-readable explanation, primarily for Unavailable + transitions (e.g. a concise summary of the failing preconditions). It is for + humans only and must not be parsed. It may be truncated by the controller. + When omitted, no human-readable explanation is available for the transition. + When set, it must be between 1 and 2048 characters long. + maxLength: 2048 + minLength: 1 + type: string + reason: + description: |- + reason is a CamelCase machine-readable explanation of the availability, e.g. + PreflightCheckFailed. The set of reasons is diagnostic and not exhaustive. + When omitted, no machine-readable explanation is available. + Must start with an uppercase letter and contain only alphanumeric characters, + and must be between 1 and 128 characters long. + maxLength: 128 + minLength: 1 + type: string + x-kubernetes-validations: + - message: reason must be CamelCase, matching ^[A-Z][A-Za-z0-9]*$ + rule: self.matches('^[A-Z][A-Za-z0-9]*$') + source: + description: |- + source is the control-plane and infrastructure topology this transition starts + from. It must equal the current topology in the corresponding status fields. + source is required. + properties: + controlPlaneTopology: + description: |- + controlPlaneTopology is the topology of the control-plane nodes. Valid values + are SingleReplica and HighlyAvailable. When set to SingleReplica, operators + avoid spending resources for high availability. When set to HighlyAvailable, + operators configure high availability as much as possible. + controlPlaneTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + infrastructureTopology: + description: |- + infrastructureTopology is the topology of infrastructure services. Valid + values are SingleReplica and HighlyAvailable. When set to SingleReplica, + operators avoid spending resources for high availability. When set to + HighlyAvailable, operators configure high availability as much as possible. + infrastructureTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + required: + - controlPlaneTopology + - infrastructureTopology + type: object + target: + description: |- + target is the control-plane and infrastructure topology this transition would + move to. target is required. + properties: + controlPlaneTopology: + description: |- + controlPlaneTopology is the topology of the control-plane nodes. Valid values + are SingleReplica and HighlyAvailable. When set to SingleReplica, operators + avoid spending resources for high availability. When set to HighlyAvailable, + operators configure high availability as much as possible. + controlPlaneTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + infrastructureTopology: + description: |- + infrastructureTopology is the topology of infrastructure services. Valid + values are SingleReplica and HighlyAvailable. When set to SingleReplica, + operators avoid spending resources for high availability. When set to + HighlyAvailable, operators configure high availability as much as possible. + infrastructureTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + required: + - controlPlaneTopology + - infrastructureTopology + type: object + required: + - source + - target + type: object + maxItems: 1 + type: array + x-kubernetes-list-type: atomic + required: + - supportedTransitions + type: object type: object required: - spec @@ -3180,6 +3402,12 @@ spec: == self.status.controlPlaneTopology) || (has(self.status.controlPlaneTopology) && self.status.controlPlaneTopology == ''SingleReplica'' && self.spec.controlPlaneTopology == ''HighlyAvailable'')' + - message: transition sources must match the current status topology + rule: '!has(self.status) || !has(self.status.topologyTransitionStatus) + || self.status.topologyTransitionStatus.supportedTransitions.all(t, + has(self.status.controlPlaneTopology) && has(self.status.infrastructureTopology) + && t.source.controlPlaneTopology == self.status.controlPlaneTopology + && t.source.infrastructureTopology == self.status.infrastructureTopology)' internalRegistryPullSecret: description: |- internalRegistryPullSecret is the pull secret for the internal registry, used by diff --git a/payload-manifests/crds/0000_80_machine-config_01_controllerconfigs-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml b/payload-manifests/crds/0000_80_machine-config_01_controllerconfigs-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml index fb3e18ca85e..b9f8845f633 100644 --- a/payload-manifests/crds/0000_80_machine-config_01_controllerconfigs-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml +++ b/payload-manifests/crds/0000_80_machine-config_01_controllerconfigs-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml @@ -3165,6 +3165,228 @@ spec: == ''Internal'' || (has(self.loadBalancer) && self.loadBalancer.type == ''UserManaged'')' type: object + topologyTransitionStatus: + description: |- + topologyTransitionStatus reports available topology transitions and current progress, if any. + It is omitted until the topology controller evaluates transitions. + properties: + conditions: + description: |- + conditions reports whether supported transitions have been evaluated. + TopologyTransitionsEvaluated is Unknown before evaluation, True when evaluation + succeeds (even if no transitions are supported), and False when evaluation fails. + An absent condition means evaluation has not completed. + At most one condition is present. + 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 + maxItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentTransition: + description: currentTransition is omitted until a topology + transition starts. + properties: + completionTime: + description: completionTime is when the transition + was fully applied. It is omitted while a transition + is being applied. + format: date-time + type: string + message: + description: |- + message is human-readable information about the reason for the current state. + It must be between 1 and 2048 characters long. + maxLength: 2048 + minLength: 1 + type: string + reason: + description: |- + reason indicates why current state is as reported. + It must be between 1 and 128 characters long. + maxLength: 128 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the + transition was started. When omitted, the start + time is not available. + format: date-time + type: string + state: + description: |- + state indicates the current state of a triggered transition. + Valid values are "Completed" when the transition was successfully applied, + "Partial" when it was not completely applied or is still in progress, and + "Failed" when it failed to apply. + enum: + - Completed + - Partial + - Failed + type: string + required: + - message + - reason + - state + type: object + supportedTransitions: + description: |- + supportedTransitions represents the transitions that are valid for this cluster. + An empty list means that no transitions are currently supported from the current topology. + At most one transition is supported currently (SNO to HA Compact) + items: + properties: + message: + description: |- + message is a human-readable explanation, primarily for Unavailable + transitions (e.g. a concise summary of the failing preconditions). It is for + humans only and must not be parsed. It may be truncated by the controller. + When omitted, no human-readable explanation is available for the transition. + When set, it must be between 1 and 2048 characters long. + maxLength: 2048 + minLength: 1 + type: string + reason: + description: |- + reason is a CamelCase machine-readable explanation of the availability, e.g. + PreflightCheckFailed. The set of reasons is diagnostic and not exhaustive. + When omitted, no machine-readable explanation is available. + Must start with an uppercase letter and contain only alphanumeric characters, + and must be between 1 and 128 characters long. + maxLength: 128 + minLength: 1 + type: string + x-kubernetes-validations: + - message: reason must be CamelCase, matching ^[A-Z][A-Za-z0-9]*$ + rule: self.matches('^[A-Z][A-Za-z0-9]*$') + source: + description: |- + source is the control-plane and infrastructure topology this transition starts + from. It must equal the current topology in the corresponding status fields. + source is required. + properties: + controlPlaneTopology: + description: |- + controlPlaneTopology is the topology of the control-plane nodes. Valid values + are SingleReplica and HighlyAvailable. When set to SingleReplica, operators + avoid spending resources for high availability. When set to HighlyAvailable, + operators configure high availability as much as possible. + controlPlaneTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + infrastructureTopology: + description: |- + infrastructureTopology is the topology of infrastructure services. Valid + values are SingleReplica and HighlyAvailable. When set to SingleReplica, + operators avoid spending resources for high availability. When set to + HighlyAvailable, operators configure high availability as much as possible. + infrastructureTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + required: + - controlPlaneTopology + - infrastructureTopology + type: object + target: + description: |- + target is the control-plane and infrastructure topology this transition would + move to. target is required. + properties: + controlPlaneTopology: + description: |- + controlPlaneTopology is the topology of the control-plane nodes. Valid values + are SingleReplica and HighlyAvailable. When set to SingleReplica, operators + avoid spending resources for high availability. When set to HighlyAvailable, + operators configure high availability as much as possible. + controlPlaneTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + infrastructureTopology: + description: |- + infrastructureTopology is the topology of infrastructure services. Valid + values are SingleReplica and HighlyAvailable. When set to SingleReplica, + operators avoid spending resources for high availability. When set to + HighlyAvailable, operators configure high availability as much as possible. + infrastructureTopology is required. + enum: + - SingleReplica + - HighlyAvailable + type: string + required: + - controlPlaneTopology + - infrastructureTopology + type: object + required: + - source + - target + type: object + maxItems: 1 + type: array + x-kubernetes-list-type: atomic + required: + - supportedTransitions + type: object type: object required: - spec @@ -3180,6 +3402,12 @@ spec: == self.status.controlPlaneTopology) || (has(self.status.controlPlaneTopology) && self.status.controlPlaneTopology == ''SingleReplica'' && self.spec.controlPlaneTopology == ''HighlyAvailable'')' + - message: transition sources must match the current status topology + rule: '!has(self.status) || !has(self.status.topologyTransitionStatus) + || self.status.topologyTransitionStatus.supportedTransitions.all(t, + has(self.status.controlPlaneTopology) && has(self.status.infrastructureTopology) + && t.source.controlPlaneTopology == self.status.controlPlaneTopology + && t.source.infrastructureTopology == self.status.infrastructureTopology)' internalRegistryPullSecret: description: |- internalRegistryPullSecret is the pull secret for the internal registry, used by