diff --git a/api/hypershift/v1beta1/controlplaneversion_types.go b/api/hypershift/v1beta1/controlplaneversion_types.go new file mode 100644 index 000000000000..14c0ed3fda94 --- /dev/null +++ b/api/hypershift/v1beta1/controlplaneversion_types.go @@ -0,0 +1,70 @@ +package v1beta1 + +import ( + configv1 "github.com/openshift/api/config/v1" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// ControlPlaneVersionStatus tracks the rollout state of management-side control plane components. +// It records the desired release, a pruned history of version transitions (newest first), and +// the last observed generation of the HostedControlPlane spec. +// +k8s:deepcopy-gen=true +type ControlPlaneVersionStatus struct { + // desired is the release version that the control plane is reconciling towards. + // It is derived from the HostedControlPlane release image fields. + // +required + Desired configv1.Release `json:"desired,omitempty,omitzero"` + + // history contains a list of versions applied to management-side control plane components. The newest entry is + // first in the list. Entries have state Completed when all ControlPlaneComponent resources report the target + // version with RolloutComplete=True. Entries have state Partial when the rollout is in progress or has failed. + // +optional + // +listType=atomic + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:MaxItems=100 + History []ControlPlaneUpdateHistory `json:"history,omitempty"` + + // observedGeneration reports which generation of the HostedControlPlane spec is being synced. + // +optional + // +kubebuilder:validation:Minimum=1 + // +kubebuilder:validation:Maximum=9007199254740992 + ObservedGeneration int64 `json:"observedGeneration,omitempty,omitzero"` +} + +// ControlPlaneUpdateHistory is a record of a single version transition for management-side +// control plane components. Each entry captures the target version, its release image, when +// the rollout started, and when (or whether) it completed. +// +k8s:deepcopy-gen=true +type ControlPlaneUpdateHistory struct { + // state reflects whether the update was fully applied. The Partial state + // indicates the update is not fully applied, while the Completed state + // indicates the update was successfully rolled out. + // +required + // +kubebuilder:validation:Enum=Completed;Partial + State configv1.UpdateState `json:"state"` + + // startedTime is the time at which the update was started. + // +required + StartedTime metav1.Time `json:"startedTime,omitempty,omitzero"` + + // completionTime is the time at which the update completed. It is set + // when all management-side components have reached the target version. + // It is not set while the update is in progress. + // +optional + CompletionTime metav1.Time `json:"completionTime,omitempty,omitzero"` + + // version is a semantic version string identifying the update version + // (e.g. "4.20.1"). + // +required + // +kubebuilder:validation:XValidation:rule=`self.matches('^\\d+\\.\\d+\\.\\d+.*')`,message="version must start with semantic version prefix x.y.z" + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=64 + Version string `json:"version"` + + // image is the release image pullspec used for this update. + // +required + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=447 + Image string `json:"image"` +} diff --git a/api/hypershift/v1beta1/hosted_controlplane.go b/api/hypershift/v1beta1/hosted_controlplane.go index b6236a0065c9..79af290bb4c9 100644 --- a/api/hypershift/v1beta1/hosted_controlplane.go +++ b/api/hypershift/v1beta1/hosted_controlplane.go @@ -349,6 +349,12 @@ type HostedControlPlaneStatus struct { // +kubebuilder:validation:MaxLength=255 OAuthCallbackURLTemplate string `json:"oauthCallbackURLTemplate,omitempty"` + // controlPlaneVersion tracks the rollout status of the control plane + // components running on the management cluster, independently from + // the data-plane version reported in the version field. + // +optional + ControlPlaneVersion ControlPlaneVersionStatus `json:"controlPlaneVersion,omitzero"` + // versionStatus is the status of the release version applied by the // hosted control plane operator. // +optional diff --git a/api/hypershift/v1beta1/hostedcluster_types.go b/api/hypershift/v1beta1/hostedcluster_types.go index dfaf052fd5f6..412823635aa3 100644 --- a/api/hypershift/v1beta1/hostedcluster_types.go +++ b/api/hypershift/v1beta1/hostedcluster_types.go @@ -1735,6 +1735,12 @@ type HostedClusterStatus struct { // +kubebuilder:validation:MaxItems=100 Conditions []metav1.Condition `json:"conditions,omitempty"` + // controlPlaneVersion tracks the rollout status of the control plane + // components running on the management cluster, independently from + // the data-plane version reported in the version field. + // +optional + ControlPlaneVersion ControlPlaneVersionStatus `json:"controlPlaneVersion,omitzero"` + // version is the status of the release version applied to the // HostedCluster. // +optional @@ -1947,11 +1953,14 @@ type OperatorConfiguration struct { // +kubebuilder:storageversion // +kubebuilder:subresource:status // +kubebuilder:printcolumn:name="Version",type="string",JSONPath=".status.version.history[?(@.state==\"Completed\")].version",description="Version" +// +kubebuilder:printcolumn:name="CP Version",type="string",JSONPath=".status.controlPlaneVersion.history[?(@.state==\"Completed\")].version",description="Control Plane Version" // +kubebuilder:printcolumn:name="KubeConfig",type="string",JSONPath=".status.kubeconfig.name",description="KubeConfig Secret" // +kubebuilder:printcolumn:name="Progress",type="string",JSONPath=".status.version.history[?(@.state!=\"\")].state",description="Progress" // +kubebuilder:printcolumn:name="Available",type="string",JSONPath=".status.conditions[?(@.type==\"Available\")].status",description="Available" // +kubebuilder:printcolumn:name="Progressing",type="string",JSONPath=".status.conditions[?(@.type==\"Progressing\")].status",description="Progressing" // +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.conditions[?(@.type==\"Available\")].message",description="Message" +// +kubebuilder:printcolumn:name="CP Progress",type="string",JSONPath=".status.controlPlaneVersion.history[0].state",description="Control Plane Progress",priority=1 +// +kubebuilder:printcolumn:name="DP Progress",type="string",JSONPath=".status.version.history[0].state",description="Data Plane Progress",priority=1 type HostedCluster struct { metav1.TypeMeta `json:",inline"` // metadata is the metadata for the HostedCluster. diff --git a/api/hypershift/v1beta1/zz_generated.deepcopy.go b/api/hypershift/v1beta1/zz_generated.deepcopy.go index 41a13b0ab84e..cd7523fac676 100644 --- a/api/hypershift/v1beta1/zz_generated.deepcopy.go +++ b/api/hypershift/v1beta1/zz_generated.deepcopy.go @@ -1290,6 +1290,46 @@ func (in *ControlPlaneManagedIdentities) DeepCopy() *ControlPlaneManagedIdentiti return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ControlPlaneUpdateHistory) DeepCopyInto(out *ControlPlaneUpdateHistory) { + *out = *in + in.StartedTime.DeepCopyInto(&out.StartedTime) + in.CompletionTime.DeepCopyInto(&out.CompletionTime) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControlPlaneUpdateHistory. +func (in *ControlPlaneUpdateHistory) DeepCopy() *ControlPlaneUpdateHistory { + if in == nil { + return nil + } + out := new(ControlPlaneUpdateHistory) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ControlPlaneVersionStatus) DeepCopyInto(out *ControlPlaneVersionStatus) { + *out = *in + in.Desired.DeepCopyInto(&out.Desired) + if in.History != nil { + in, out := &in.History, &out.History + *out = make([]ControlPlaneUpdateHistory, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControlPlaneVersionStatus. +func (in *ControlPlaneVersionStatus) DeepCopy() *ControlPlaneVersionStatus { + if in == nil { + return nil + } + out := new(ControlPlaneVersionStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DNSSpec) DeepCopyInto(out *DNSSpec) { *out = *in @@ -1618,6 +1658,7 @@ func (in *HostedClusterStatus) DeepCopyInto(out *HostedClusterStatus) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + in.ControlPlaneVersion.DeepCopyInto(&out.ControlPlaneVersion) if in.Version != nil { in, out := &in.Version, &out.Version *out = new(ClusterVersionStatus) @@ -1843,6 +1884,7 @@ func (in *HostedControlPlaneStatus) DeepCopyInto(out *HostedControlPlaneStatus) **out = **in } out.ControlPlaneEndpoint = in.ControlPlaneEndpoint + in.ControlPlaneVersion.DeepCopyInto(&out.ControlPlaneVersion) if in.VersionStatus != nil { in, out := &in.VersionStatus, &out.VersionStatus *out = new(ClusterVersionStatus) diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests.yaml index 42f072849951..97df08a90653 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests.yaml @@ -115,6 +115,10 @@ hostedclusters.hypershift.openshift.io: jsonPath: .status.version.history[?(@.state=="Completed")].version name: Version type: string + - description: Control Plane Version + jsonPath: .status.controlPlaneVersion.history[?(@.state=="Completed")].version + name: CP Version + type: string - description: KubeConfig Secret jsonPath: .status.kubeconfig.name name: KubeConfig @@ -135,6 +139,16 @@ hostedclusters.hypershift.openshift.io: jsonPath: .status.conditions[?(@.type=="Available")].message name: Message type: string + - description: Control Plane Progress + jsonPath: .status.controlPlaneVersion.history[0].state + name: CP Progress + priority: 1 + type: string + - description: Data Plane Progress + jsonPath: .status.version.history[0].state + name: DP Progress + priority: 1 + type: string Scope: Namespaced ShortNames: - hc diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AAA_ungated.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AAA_ungated.yaml index 71a84de7b239..2f084e31ac57 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AAA_ungated.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AAA_ungated.yaml @@ -21,6 +21,10 @@ spec: jsonPath: .status.version.history[?(@.state=="Completed")].version name: Version type: string + - description: Control Plane Version + jsonPath: .status.controlPlaneVersion.history[?(@.state=="Completed")].version + name: CP Version + type: string - description: KubeConfig Secret jsonPath: .status.kubeconfig.name name: KubeConfig @@ -41,6 +45,16 @@ spec: jsonPath: .status.conditions[?(@.type=="Available")].message name: Message type: string + - description: Control Plane Progress + jsonPath: .status.controlPlaneVersion.history[0].state + name: CP Progress + priority: 1 + type: string + - description: Data Plane Progress + jsonPath: .status.version.history[0].state + name: DP Progress + priority: 1 + type: string name: v1beta1 schema: openAPIV3Schema: @@ -5401,6 +5415,117 @@ spec: - host - port type: object + controlPlaneVersion: + description: |- + controlPlaneVersion tracks the rollout status of the control plane + components running on the management cluster, independently from + the data-plane version reported in the version field. + properties: + desired: + description: |- + desired is the release version that the control plane is reconciling towards. + It is derived from the HostedControlPlane release image fields. + properties: + channels: + description: |- + channels is the set of Cincinnati channels to which the release + currently belongs. + items: + type: string + type: array + x-kubernetes-list-type: set + image: + description: |- + image is a container image location that contains the update. When this + field is part of spec, image is optional if version is specified and the + availableUpdates field contains a matching version. + type: string + url: + description: |- + url contains information about this release. This URL is set by + the 'url' metadata property on a release or the metadata returned by + the update API and should be displayed as a link in user + interfaces. The URL field may not be set for test or nightly + releases. + type: string + version: + description: |- + version is a semantic version identifying the update version. When this + field is part of spec, version is optional if image is specified. + type: string + required: + - image + - version + type: object + history: + description: |- + history contains a list of versions applied to management-side control plane components. The newest entry is + first in the list. Entries have state Completed when all ControlPlaneComponent resources report the target + version with RolloutComplete=True. Entries have state Partial when the rollout is in progress or has failed. + items: + description: |- + ControlPlaneUpdateHistory is a record of a single version transition for management-side + control plane components. Each entry captures the target version, its release image, when + the rollout started, and when (or whether) it completed. + properties: + completionTime: + description: |- + completionTime is the time at which the update completed. It is set + when all management-side components have reached the target version. + It is not set while the update is in progress. + format: date-time + type: string + image: + description: image is the release image pullspec used for + this update. + maxLength: 447 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the update + was started. + format: date-time + type: string + state: + description: |- + state reflects whether the update was fully applied. The Partial state + indicates the update is not fully applied, while the Completed state + indicates the update was successfully rolled out. + enum: + - Completed + - Partial + type: string + version: + description: |- + version is a semantic version string identifying the update version + (e.g. "4.20.1"). + maxLength: 64 + minLength: 1 + type: string + x-kubernetes-validations: + - message: version must start with semantic version prefix + x.y.z + rule: self.matches('^\\d+\\.\\d+\\.\\d+.*') + required: + - image + - startedTime + - state + - version + type: object + maxItems: 100 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + observedGeneration: + description: observedGeneration reports which generation of the + HostedControlPlane spec is being synced. + format: int64 + maximum: 9007199254740992 + minimum: 1 + type: integer + required: + - desired + type: object customKubeconfig: description: |- customKubeconfig is a local secret reference to the external custom kubeconfig. diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AutoNodeKarpenter.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AutoNodeKarpenter.yaml index dd24338fb503..1f52b3e1abf3 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AutoNodeKarpenter.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AutoNodeKarpenter.yaml @@ -21,6 +21,10 @@ spec: jsonPath: .status.version.history[?(@.state=="Completed")].version name: Version type: string + - description: Control Plane Version + jsonPath: .status.controlPlaneVersion.history[?(@.state=="Completed")].version + name: CP Version + type: string - description: KubeConfig Secret jsonPath: .status.kubeconfig.name name: KubeConfig @@ -41,6 +45,16 @@ spec: jsonPath: .status.conditions[?(@.type=="Available")].message name: Message type: string + - description: Control Plane Progress + jsonPath: .status.controlPlaneVersion.history[0].state + name: CP Progress + priority: 1 + type: string + - description: Data Plane Progress + jsonPath: .status.version.history[0].state + name: DP Progress + priority: 1 + type: string name: v1beta1 schema: openAPIV3Schema: @@ -5431,6 +5445,117 @@ spec: - host - port type: object + controlPlaneVersion: + description: |- + controlPlaneVersion tracks the rollout status of the control plane + components running on the management cluster, independently from + the data-plane version reported in the version field. + properties: + desired: + description: |- + desired is the release version that the control plane is reconciling towards. + It is derived from the HostedControlPlane release image fields. + properties: + channels: + description: |- + channels is the set of Cincinnati channels to which the release + currently belongs. + items: + type: string + type: array + x-kubernetes-list-type: set + image: + description: |- + image is a container image location that contains the update. When this + field is part of spec, image is optional if version is specified and the + availableUpdates field contains a matching version. + type: string + url: + description: |- + url contains information about this release. This URL is set by + the 'url' metadata property on a release or the metadata returned by + the update API and should be displayed as a link in user + interfaces. The URL field may not be set for test or nightly + releases. + type: string + version: + description: |- + version is a semantic version identifying the update version. When this + field is part of spec, version is optional if image is specified. + type: string + required: + - image + - version + type: object + history: + description: |- + history contains a list of versions applied to management-side control plane components. The newest entry is + first in the list. Entries have state Completed when all ControlPlaneComponent resources report the target + version with RolloutComplete=True. Entries have state Partial when the rollout is in progress or has failed. + items: + description: |- + ControlPlaneUpdateHistory is a record of a single version transition for management-side + control plane components. Each entry captures the target version, its release image, when + the rollout started, and when (or whether) it completed. + properties: + completionTime: + description: |- + completionTime is the time at which the update completed. It is set + when all management-side components have reached the target version. + It is not set while the update is in progress. + format: date-time + type: string + image: + description: image is the release image pullspec used for + this update. + maxLength: 447 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the update + was started. + format: date-time + type: string + state: + description: |- + state reflects whether the update was fully applied. The Partial state + indicates the update is not fully applied, while the Completed state + indicates the update was successfully rolled out. + enum: + - Completed + - Partial + type: string + version: + description: |- + version is a semantic version string identifying the update version + (e.g. "4.20.1"). + maxLength: 64 + minLength: 1 + type: string + x-kubernetes-validations: + - message: version must start with semantic version prefix + x.y.z + rule: self.matches('^\\d+\\.\\d+\\.\\d+.*') + required: + - image + - startedTime + - state + - version + type: object + maxItems: 100 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + observedGeneration: + description: observedGeneration reports which generation of the + HostedControlPlane spec is being synced. + format: int64 + maximum: 9007199254740992 + minimum: 1 + type: integer + required: + - desired + type: object customKubeconfig: description: |- customKubeconfig is a local secret reference to the external custom kubeconfig. diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml index 3ce3ec6bb6ce..b5b0cd292456 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml @@ -21,6 +21,10 @@ spec: jsonPath: .status.version.history[?(@.state=="Completed")].version name: Version type: string + - description: Control Plane Version + jsonPath: .status.controlPlaneVersion.history[?(@.state=="Completed")].version + name: CP Version + type: string - description: KubeConfig Secret jsonPath: .status.kubeconfig.name name: KubeConfig @@ -41,6 +45,16 @@ spec: jsonPath: .status.conditions[?(@.type=="Available")].message name: Message type: string + - description: Control Plane Progress + jsonPath: .status.controlPlaneVersion.history[0].state + name: CP Progress + priority: 1 + type: string + - description: Data Plane Progress + jsonPath: .status.version.history[0].state + name: DP Progress + priority: 1 + type: string name: v1beta1 schema: openAPIV3Schema: @@ -5404,6 +5418,117 @@ spec: - host - port type: object + controlPlaneVersion: + description: |- + controlPlaneVersion tracks the rollout status of the control plane + components running on the management cluster, independently from + the data-plane version reported in the version field. + properties: + desired: + description: |- + desired is the release version that the control plane is reconciling towards. + It is derived from the HostedControlPlane release image fields. + properties: + channels: + description: |- + channels is the set of Cincinnati channels to which the release + currently belongs. + items: + type: string + type: array + x-kubernetes-list-type: set + image: + description: |- + image is a container image location that contains the update. When this + field is part of spec, image is optional if version is specified and the + availableUpdates field contains a matching version. + type: string + url: + description: |- + url contains information about this release. This URL is set by + the 'url' metadata property on a release or the metadata returned by + the update API and should be displayed as a link in user + interfaces. The URL field may not be set for test or nightly + releases. + type: string + version: + description: |- + version is a semantic version identifying the update version. When this + field is part of spec, version is optional if image is specified. + type: string + required: + - image + - version + type: object + history: + description: |- + history contains a list of versions applied to management-side control plane components. The newest entry is + first in the list. Entries have state Completed when all ControlPlaneComponent resources report the target + version with RolloutComplete=True. Entries have state Partial when the rollout is in progress or has failed. + items: + description: |- + ControlPlaneUpdateHistory is a record of a single version transition for management-side + control plane components. Each entry captures the target version, its release image, when + the rollout started, and when (or whether) it completed. + properties: + completionTime: + description: |- + completionTime is the time at which the update completed. It is set + when all management-side components have reached the target version. + It is not set while the update is in progress. + format: date-time + type: string + image: + description: image is the release image pullspec used for + this update. + maxLength: 447 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the update + was started. + format: date-time + type: string + state: + description: |- + state reflects whether the update was fully applied. The Partial state + indicates the update is not fully applied, while the Completed state + indicates the update was successfully rolled out. + enum: + - Completed + - Partial + type: string + version: + description: |- + version is a semantic version string identifying the update version + (e.g. "4.20.1"). + maxLength: 64 + minLength: 1 + type: string + x-kubernetes-validations: + - message: version must start with semantic version prefix + x.y.z + rule: self.matches('^\\d+\\.\\d+\\.\\d+.*') + required: + - image + - startedTime + - state + - version + type: object + maxItems: 100 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + observedGeneration: + description: observedGeneration reports which generation of the + HostedControlPlane spec is being synced. + format: int64 + maximum: 9007199254740992 + minimum: 1 + type: integer + required: + - desired + type: object customKubeconfig: description: |- customKubeconfig is a local secret reference to the external custom kubeconfig. diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/DynamicResourceAllocation.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/DynamicResourceAllocation.yaml index 55272732075f..a86204ed868c 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/DynamicResourceAllocation.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/DynamicResourceAllocation.yaml @@ -21,6 +21,10 @@ spec: jsonPath: .status.version.history[?(@.state=="Completed")].version name: Version type: string + - description: Control Plane Version + jsonPath: .status.controlPlaneVersion.history[?(@.state=="Completed")].version + name: CP Version + type: string - description: KubeConfig Secret jsonPath: .status.kubeconfig.name name: KubeConfig @@ -41,6 +45,16 @@ spec: jsonPath: .status.conditions[?(@.type=="Available")].message name: Message type: string + - description: Control Plane Progress + jsonPath: .status.controlPlaneVersion.history[0].state + name: CP Progress + priority: 1 + type: string + - description: Data Plane Progress + jsonPath: .status.version.history[0].state + name: DP Progress + priority: 1 + type: string name: v1beta1 schema: openAPIV3Schema: @@ -5405,6 +5419,117 @@ spec: - host - port type: object + controlPlaneVersion: + description: |- + controlPlaneVersion tracks the rollout status of the control plane + components running on the management cluster, independently from + the data-plane version reported in the version field. + properties: + desired: + description: |- + desired is the release version that the control plane is reconciling towards. + It is derived from the HostedControlPlane release image fields. + properties: + channels: + description: |- + channels is the set of Cincinnati channels to which the release + currently belongs. + items: + type: string + type: array + x-kubernetes-list-type: set + image: + description: |- + image is a container image location that contains the update. When this + field is part of spec, image is optional if version is specified and the + availableUpdates field contains a matching version. + type: string + url: + description: |- + url contains information about this release. This URL is set by + the 'url' metadata property on a release or the metadata returned by + the update API and should be displayed as a link in user + interfaces. The URL field may not be set for test or nightly + releases. + type: string + version: + description: |- + version is a semantic version identifying the update version. When this + field is part of spec, version is optional if image is specified. + type: string + required: + - image + - version + type: object + history: + description: |- + history contains a list of versions applied to management-side control plane components. The newest entry is + first in the list. Entries have state Completed when all ControlPlaneComponent resources report the target + version with RolloutComplete=True. Entries have state Partial when the rollout is in progress or has failed. + items: + description: |- + ControlPlaneUpdateHistory is a record of a single version transition for management-side + control plane components. Each entry captures the target version, its release image, when + the rollout started, and when (or whether) it completed. + properties: + completionTime: + description: |- + completionTime is the time at which the update completed. It is set + when all management-side components have reached the target version. + It is not set while the update is in progress. + format: date-time + type: string + image: + description: image is the release image pullspec used for + this update. + maxLength: 447 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the update + was started. + format: date-time + type: string + state: + description: |- + state reflects whether the update was fully applied. The Partial state + indicates the update is not fully applied, while the Completed state + indicates the update was successfully rolled out. + enum: + - Completed + - Partial + type: string + version: + description: |- + version is a semantic version string identifying the update version + (e.g. "4.20.1"). + maxLength: 64 + minLength: 1 + type: string + x-kubernetes-validations: + - message: version must start with semantic version prefix + x.y.z + rule: self.matches('^\\d+\\.\\d+\\.\\d+.*') + required: + - image + - startedTime + - state + - version + type: object + maxItems: 100 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + observedGeneration: + description: observedGeneration reports which generation of the + HostedControlPlane spec is being synced. + format: int64 + maximum: 9007199254740992 + minimum: 1 + type: integer + required: + - desired + type: object customKubeconfig: description: |- customKubeconfig is a local secret reference to the external custom kubeconfig. diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDC.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDC.yaml index 7f1d3862b725..1f56e3ff5faa 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDC.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDC.yaml @@ -21,6 +21,10 @@ spec: jsonPath: .status.version.history[?(@.state=="Completed")].version name: Version type: string + - description: Control Plane Version + jsonPath: .status.controlPlaneVersion.history[?(@.state=="Completed")].version + name: CP Version + type: string - description: KubeConfig Secret jsonPath: .status.kubeconfig.name name: KubeConfig @@ -41,6 +45,16 @@ spec: jsonPath: .status.conditions[?(@.type=="Available")].message name: Message type: string + - description: Control Plane Progress + jsonPath: .status.controlPlaneVersion.history[0].state + name: CP Progress + priority: 1 + type: string + - description: Data Plane Progress + jsonPath: .status.version.history[0].state + name: DP Progress + priority: 1 + type: string name: v1beta1 schema: openAPIV3Schema: @@ -5720,6 +5734,117 @@ spec: - host - port type: object + controlPlaneVersion: + description: |- + controlPlaneVersion tracks the rollout status of the control plane + components running on the management cluster, independently from + the data-plane version reported in the version field. + properties: + desired: + description: |- + desired is the release version that the control plane is reconciling towards. + It is derived from the HostedControlPlane release image fields. + properties: + channels: + description: |- + channels is the set of Cincinnati channels to which the release + currently belongs. + items: + type: string + type: array + x-kubernetes-list-type: set + image: + description: |- + image is a container image location that contains the update. When this + field is part of spec, image is optional if version is specified and the + availableUpdates field contains a matching version. + type: string + url: + description: |- + url contains information about this release. This URL is set by + the 'url' metadata property on a release or the metadata returned by + the update API and should be displayed as a link in user + interfaces. The URL field may not be set for test or nightly + releases. + type: string + version: + description: |- + version is a semantic version identifying the update version. When this + field is part of spec, version is optional if image is specified. + type: string + required: + - image + - version + type: object + history: + description: |- + history contains a list of versions applied to management-side control plane components. The newest entry is + first in the list. Entries have state Completed when all ControlPlaneComponent resources report the target + version with RolloutComplete=True. Entries have state Partial when the rollout is in progress or has failed. + items: + description: |- + ControlPlaneUpdateHistory is a record of a single version transition for management-side + control plane components. Each entry captures the target version, its release image, when + the rollout started, and when (or whether) it completed. + properties: + completionTime: + description: |- + completionTime is the time at which the update completed. It is set + when all management-side components have reached the target version. + It is not set while the update is in progress. + format: date-time + type: string + image: + description: image is the release image pullspec used for + this update. + maxLength: 447 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the update + was started. + format: date-time + type: string + state: + description: |- + state reflects whether the update was fully applied. The Partial state + indicates the update is not fully applied, while the Completed state + indicates the update was successfully rolled out. + enum: + - Completed + - Partial + type: string + version: + description: |- + version is a semantic version string identifying the update version + (e.g. "4.20.1"). + maxLength: 64 + minLength: 1 + type: string + x-kubernetes-validations: + - message: version must start with semantic version prefix + x.y.z + rule: self.matches('^\\d+\\.\\d+\\.\\d+.*') + required: + - image + - startedTime + - state + - version + type: object + maxItems: 100 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + observedGeneration: + description: observedGeneration reports which generation of the + HostedControlPlane spec is being synced. + format: int64 + maximum: 9007199254740992 + minimum: 1 + type: integer + required: + - desired + type: object customKubeconfig: description: |- customKubeconfig is a local secret reference to the external custom kubeconfig. diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml index c57abe7c8511..2b2968f4dc0f 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml @@ -21,6 +21,10 @@ spec: jsonPath: .status.version.history[?(@.state=="Completed")].version name: Version type: string + - description: Control Plane Version + jsonPath: .status.controlPlaneVersion.history[?(@.state=="Completed")].version + name: CP Version + type: string - description: KubeConfig Secret jsonPath: .status.kubeconfig.name name: KubeConfig @@ -41,6 +45,16 @@ spec: jsonPath: .status.conditions[?(@.type=="Available")].message name: Message type: string + - description: Control Plane Progress + jsonPath: .status.controlPlaneVersion.history[0].state + name: CP Progress + priority: 1 + type: string + - description: Data Plane Progress + jsonPath: .status.version.history[0].state + name: DP Progress + priority: 1 + type: string name: v1beta1 schema: openAPIV3Schema: @@ -5874,6 +5888,117 @@ spec: - host - port type: object + controlPlaneVersion: + description: |- + controlPlaneVersion tracks the rollout status of the control plane + components running on the management cluster, independently from + the data-plane version reported in the version field. + properties: + desired: + description: |- + desired is the release version that the control plane is reconciling towards. + It is derived from the HostedControlPlane release image fields. + properties: + channels: + description: |- + channels is the set of Cincinnati channels to which the release + currently belongs. + items: + type: string + type: array + x-kubernetes-list-type: set + image: + description: |- + image is a container image location that contains the update. When this + field is part of spec, image is optional if version is specified and the + availableUpdates field contains a matching version. + type: string + url: + description: |- + url contains information about this release. This URL is set by + the 'url' metadata property on a release or the metadata returned by + the update API and should be displayed as a link in user + interfaces. The URL field may not be set for test or nightly + releases. + type: string + version: + description: |- + version is a semantic version identifying the update version. When this + field is part of spec, version is optional if image is specified. + type: string + required: + - image + - version + type: object + history: + description: |- + history contains a list of versions applied to management-side control plane components. The newest entry is + first in the list. Entries have state Completed when all ControlPlaneComponent resources report the target + version with RolloutComplete=True. Entries have state Partial when the rollout is in progress or has failed. + items: + description: |- + ControlPlaneUpdateHistory is a record of a single version transition for management-side + control plane components. Each entry captures the target version, its release image, when + the rollout started, and when (or whether) it completed. + properties: + completionTime: + description: |- + completionTime is the time at which the update completed. It is set + when all management-side components have reached the target version. + It is not set while the update is in progress. + format: date-time + type: string + image: + description: image is the release image pullspec used for + this update. + maxLength: 447 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the update + was started. + format: date-time + type: string + state: + description: |- + state reflects whether the update was fully applied. The Partial state + indicates the update is not fully applied, while the Completed state + indicates the update was successfully rolled out. + enum: + - Completed + - Partial + type: string + version: + description: |- + version is a semantic version string identifying the update version + (e.g. "4.20.1"). + maxLength: 64 + minLength: 1 + type: string + x-kubernetes-validations: + - message: version must start with semantic version prefix + x.y.z + rule: self.matches('^\\d+\\.\\d+\\.\\d+.*') + required: + - image + - startedTime + - state + - version + type: object + maxItems: 100 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + observedGeneration: + description: observedGeneration reports which generation of the + HostedControlPlane spec is being synced. + format: int64 + maximum: 9007199254740992 + minimum: 1 + type: integer + required: + - desired + type: object customKubeconfig: description: |- customKubeconfig is a local secret reference to the external custom kubeconfig. diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ImageStreamImportMode.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ImageStreamImportMode.yaml index 3b00295bc637..aec253b445e1 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ImageStreamImportMode.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ImageStreamImportMode.yaml @@ -21,6 +21,10 @@ spec: jsonPath: .status.version.history[?(@.state=="Completed")].version name: Version type: string + - description: Control Plane Version + jsonPath: .status.controlPlaneVersion.history[?(@.state=="Completed")].version + name: CP Version + type: string - description: KubeConfig Secret jsonPath: .status.kubeconfig.name name: KubeConfig @@ -41,6 +45,16 @@ spec: jsonPath: .status.conditions[?(@.type=="Available")].message name: Message type: string + - description: Control Plane Progress + jsonPath: .status.controlPlaneVersion.history[0].state + name: CP Progress + priority: 1 + type: string + - description: Data Plane Progress + jsonPath: .status.version.history[0].state + name: DP Progress + priority: 1 + type: string name: v1beta1 schema: openAPIV3Schema: @@ -5402,6 +5416,128 @@ spec: - host - port type: object + controlPlaneVersion: + description: |- + controlPlaneVersion tracks the rollout status of the control plane + components running on the management cluster, independently from + the data-plane version reported in the version field. + properties: + desired: + description: |- + desired is the release version that the control plane is reconciling towards. + It is derived from the HostedControlPlane release image fields. + properties: + architecture: + description: |- + architecture is an optional field that indicates the + value of the cluster architecture. In this context cluster + architecture means either a single architecture or a multi + architecture. + Valid values are 'Multi' and empty. + enum: + - Multi + - "" + type: string + channels: + description: |- + channels is the set of Cincinnati channels to which the release + currently belongs. + items: + type: string + type: array + x-kubernetes-list-type: set + image: + description: |- + image is a container image location that contains the update. When this + field is part of spec, image is optional if version is specified and the + availableUpdates field contains a matching version. + type: string + url: + description: |- + url contains information about this release. This URL is set by + the 'url' metadata property on a release or the metadata returned by + the update API and should be displayed as a link in user + interfaces. The URL field may not be set for test or nightly + releases. + type: string + version: + description: |- + version is a semantic version identifying the update version. When this + field is part of spec, version is optional if image is specified. + type: string + required: + - image + - version + type: object + history: + description: |- + history contains a list of versions applied to management-side control plane components. The newest entry is + first in the list. Entries have state Completed when all ControlPlaneComponent resources report the target + version with RolloutComplete=True. Entries have state Partial when the rollout is in progress or has failed. + items: + description: |- + ControlPlaneUpdateHistory is a record of a single version transition for management-side + control plane components. Each entry captures the target version, its release image, when + the rollout started, and when (or whether) it completed. + properties: + completionTime: + description: |- + completionTime is the time at which the update completed. It is set + when all management-side components have reached the target version. + It is not set while the update is in progress. + format: date-time + type: string + image: + description: image is the release image pullspec used for + this update. + maxLength: 447 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the update + was started. + format: date-time + type: string + state: + description: |- + state reflects whether the update was fully applied. The Partial state + indicates the update is not fully applied, while the Completed state + indicates the update was successfully rolled out. + enum: + - Completed + - Partial + type: string + version: + description: |- + version is a semantic version string identifying the update version + (e.g. "4.20.1"). + maxLength: 64 + minLength: 1 + type: string + x-kubernetes-validations: + - message: version must start with semantic version prefix + x.y.z + rule: self.matches('^\\d+\\.\\d+\\.\\d+.*') + required: + - image + - startedTime + - state + - version + type: object + maxItems: 100 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + observedGeneration: + description: observedGeneration reports which generation of the + HostedControlPlane spec is being synced. + format: int64 + maximum: 9007199254740992 + minimum: 1 + type: integer + required: + - desired + type: object customKubeconfig: description: |- customKubeconfig is a local secret reference to the external custom kubeconfig. diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/KMSEncryptionProvider.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/KMSEncryptionProvider.yaml index fc84f57bbabf..a8d926a4c67c 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/KMSEncryptionProvider.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/KMSEncryptionProvider.yaml @@ -21,6 +21,10 @@ spec: jsonPath: .status.version.history[?(@.state=="Completed")].version name: Version type: string + - description: Control Plane Version + jsonPath: .status.controlPlaneVersion.history[?(@.state=="Completed")].version + name: CP Version + type: string - description: KubeConfig Secret jsonPath: .status.kubeconfig.name name: KubeConfig @@ -41,6 +45,16 @@ spec: jsonPath: .status.conditions[?(@.type=="Available")].message name: Message type: string + - description: Control Plane Progress + jsonPath: .status.controlPlaneVersion.history[0].state + name: CP Progress + priority: 1 + type: string + - description: Data Plane Progress + jsonPath: .status.version.history[0].state + name: DP Progress + priority: 1 + type: string name: v1beta1 schema: openAPIV3Schema: @@ -5460,6 +5474,117 @@ spec: - host - port type: object + controlPlaneVersion: + description: |- + controlPlaneVersion tracks the rollout status of the control plane + components running on the management cluster, independently from + the data-plane version reported in the version field. + properties: + desired: + description: |- + desired is the release version that the control plane is reconciling towards. + It is derived from the HostedControlPlane release image fields. + properties: + channels: + description: |- + channels is the set of Cincinnati channels to which the release + currently belongs. + items: + type: string + type: array + x-kubernetes-list-type: set + image: + description: |- + image is a container image location that contains the update. When this + field is part of spec, image is optional if version is specified and the + availableUpdates field contains a matching version. + type: string + url: + description: |- + url contains information about this release. This URL is set by + the 'url' metadata property on a release or the metadata returned by + the update API and should be displayed as a link in user + interfaces. The URL field may not be set for test or nightly + releases. + type: string + version: + description: |- + version is a semantic version identifying the update version. When this + field is part of spec, version is optional if image is specified. + type: string + required: + - image + - version + type: object + history: + description: |- + history contains a list of versions applied to management-side control plane components. The newest entry is + first in the list. Entries have state Completed when all ControlPlaneComponent resources report the target + version with RolloutComplete=True. Entries have state Partial when the rollout is in progress or has failed. + items: + description: |- + ControlPlaneUpdateHistory is a record of a single version transition for management-side + control plane components. Each entry captures the target version, its release image, when + the rollout started, and when (or whether) it completed. + properties: + completionTime: + description: |- + completionTime is the time at which the update completed. It is set + when all management-side components have reached the target version. + It is not set while the update is in progress. + format: date-time + type: string + image: + description: image is the release image pullspec used for + this update. + maxLength: 447 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the update + was started. + format: date-time + type: string + state: + description: |- + state reflects whether the update was fully applied. The Partial state + indicates the update is not fully applied, while the Completed state + indicates the update was successfully rolled out. + enum: + - Completed + - Partial + type: string + version: + description: |- + version is a semantic version string identifying the update version + (e.g. "4.20.1"). + maxLength: 64 + minLength: 1 + type: string + x-kubernetes-validations: + - message: version must start with semantic version prefix + x.y.z + rule: self.matches('^\\d+\\.\\d+\\.\\d+.*') + required: + - image + - startedTime + - state + - version + type: object + maxItems: 100 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + observedGeneration: + description: observedGeneration reports which generation of the + HostedControlPlane spec is being synced. + format: int64 + maximum: 9007199254740992 + minimum: 1 + type: integer + required: + - desired + type: object customKubeconfig: description: |- customKubeconfig is a local secret reference to the external custom kubeconfig. diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/NetworkDiagnosticsConfig.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/NetworkDiagnosticsConfig.yaml index 10544990643e..ea066a0f4354 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/NetworkDiagnosticsConfig.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/NetworkDiagnosticsConfig.yaml @@ -21,6 +21,10 @@ spec: jsonPath: .status.version.history[?(@.state=="Completed")].version name: Version type: string + - description: Control Plane Version + jsonPath: .status.controlPlaneVersion.history[?(@.state=="Completed")].version + name: CP Version + type: string - description: KubeConfig Secret jsonPath: .status.kubeconfig.name name: KubeConfig @@ -41,6 +45,16 @@ spec: jsonPath: .status.conditions[?(@.type=="Available")].message name: Message type: string + - description: Control Plane Progress + jsonPath: .status.controlPlaneVersion.history[0].state + name: CP Progress + priority: 1 + type: string + - description: Data Plane Progress + jsonPath: .status.version.history[0].state + name: DP Progress + priority: 1 + type: string name: v1beta1 schema: openAPIV3Schema: @@ -5536,6 +5550,117 @@ spec: - host - port type: object + controlPlaneVersion: + description: |- + controlPlaneVersion tracks the rollout status of the control plane + components running on the management cluster, independently from + the data-plane version reported in the version field. + properties: + desired: + description: |- + desired is the release version that the control plane is reconciling towards. + It is derived from the HostedControlPlane release image fields. + properties: + channels: + description: |- + channels is the set of Cincinnati channels to which the release + currently belongs. + items: + type: string + type: array + x-kubernetes-list-type: set + image: + description: |- + image is a container image location that contains the update. When this + field is part of spec, image is optional if version is specified and the + availableUpdates field contains a matching version. + type: string + url: + description: |- + url contains information about this release. This URL is set by + the 'url' metadata property on a release or the metadata returned by + the update API and should be displayed as a link in user + interfaces. The URL field may not be set for test or nightly + releases. + type: string + version: + description: |- + version is a semantic version identifying the update version. When this + field is part of spec, version is optional if image is specified. + type: string + required: + - image + - version + type: object + history: + description: |- + history contains a list of versions applied to management-side control plane components. The newest entry is + first in the list. Entries have state Completed when all ControlPlaneComponent resources report the target + version with RolloutComplete=True. Entries have state Partial when the rollout is in progress or has failed. + items: + description: |- + ControlPlaneUpdateHistory is a record of a single version transition for management-side + control plane components. Each entry captures the target version, its release image, when + the rollout started, and when (or whether) it completed. + properties: + completionTime: + description: |- + completionTime is the time at which the update completed. It is set + when all management-side components have reached the target version. + It is not set while the update is in progress. + format: date-time + type: string + image: + description: image is the release image pullspec used for + this update. + maxLength: 447 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the update + was started. + format: date-time + type: string + state: + description: |- + state reflects whether the update was fully applied. The Partial state + indicates the update is not fully applied, while the Completed state + indicates the update was successfully rolled out. + enum: + - Completed + - Partial + type: string + version: + description: |- + version is a semantic version string identifying the update version + (e.g. "4.20.1"). + maxLength: 64 + minLength: 1 + type: string + x-kubernetes-validations: + - message: version must start with semantic version prefix + x.y.z + rule: self.matches('^\\d+\\.\\d+\\.\\d+.*') + required: + - image + - startedTime + - state + - version + type: object + maxItems: 100 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + observedGeneration: + description: observedGeneration reports which generation of the + HostedControlPlane spec is being synced. + format: int64 + maximum: 9007199254740992 + minimum: 1 + type: integer + required: + - desired + type: object customKubeconfig: description: |- customKubeconfig is a local secret reference to the external custom kubeconfig. diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/OpenStack.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/OpenStack.yaml index c88fceca3bd7..fe217d0490ea 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/OpenStack.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/OpenStack.yaml @@ -21,6 +21,10 @@ spec: jsonPath: .status.version.history[?(@.state=="Completed")].version name: Version type: string + - description: Control Plane Version + jsonPath: .status.controlPlaneVersion.history[?(@.state=="Completed")].version + name: CP Version + type: string - description: KubeConfig Secret jsonPath: .status.kubeconfig.name name: KubeConfig @@ -41,6 +45,16 @@ spec: jsonPath: .status.conditions[?(@.type=="Available")].message name: Message type: string + - description: Control Plane Progress + jsonPath: .status.controlPlaneVersion.history[0].state + name: CP Progress + priority: 1 + type: string + - description: Data Plane Progress + jsonPath: .status.version.history[0].state + name: DP Progress + priority: 1 + type: string name: v1beta1 schema: openAPIV3Schema: @@ -5934,6 +5948,117 @@ spec: - host - port type: object + controlPlaneVersion: + description: |- + controlPlaneVersion tracks the rollout status of the control plane + components running on the management cluster, independently from + the data-plane version reported in the version field. + properties: + desired: + description: |- + desired is the release version that the control plane is reconciling towards. + It is derived from the HostedControlPlane release image fields. + properties: + channels: + description: |- + channels is the set of Cincinnati channels to which the release + currently belongs. + items: + type: string + type: array + x-kubernetes-list-type: set + image: + description: |- + image is a container image location that contains the update. When this + field is part of spec, image is optional if version is specified and the + availableUpdates field contains a matching version. + type: string + url: + description: |- + url contains information about this release. This URL is set by + the 'url' metadata property on a release or the metadata returned by + the update API and should be displayed as a link in user + interfaces. The URL field may not be set for test or nightly + releases. + type: string + version: + description: |- + version is a semantic version identifying the update version. When this + field is part of spec, version is optional if image is specified. + type: string + required: + - image + - version + type: object + history: + description: |- + history contains a list of versions applied to management-side control plane components. The newest entry is + first in the list. Entries have state Completed when all ControlPlaneComponent resources report the target + version with RolloutComplete=True. Entries have state Partial when the rollout is in progress or has failed. + items: + description: |- + ControlPlaneUpdateHistory is a record of a single version transition for management-side + control plane components. Each entry captures the target version, its release image, when + the rollout started, and when (or whether) it completed. + properties: + completionTime: + description: |- + completionTime is the time at which the update completed. It is set + when all management-side components have reached the target version. + It is not set while the update is in progress. + format: date-time + type: string + image: + description: image is the release image pullspec used for + this update. + maxLength: 447 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the update + was started. + format: date-time + type: string + state: + description: |- + state reflects whether the update was fully applied. The Partial state + indicates the update is not fully applied, while the Completed state + indicates the update was successfully rolled out. + enum: + - Completed + - Partial + type: string + version: + description: |- + version is a semantic version string identifying the update version + (e.g. "4.20.1"). + maxLength: 64 + minLength: 1 + type: string + x-kubernetes-validations: + - message: version must start with semantic version prefix + x.y.z + rule: self.matches('^\\d+\\.\\d+\\.\\d+.*') + required: + - image + - startedTime + - state + - version + type: object + maxItems: 100 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + observedGeneration: + description: observedGeneration reports which generation of the + HostedControlPlane spec is being synced. + format: int64 + maximum: 9007199254740992 + minimum: 1 + type: integer + required: + - desired + type: object customKubeconfig: description: |- customKubeconfig is a local secret reference to the external custom kubeconfig. diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AAA_ungated.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AAA_ungated.yaml index fd93aede8a88..ecba64e3d00d 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AAA_ungated.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AAA_ungated.yaml @@ -5221,6 +5221,117 @@ spec: - host - port type: object + controlPlaneVersion: + description: |- + controlPlaneVersion tracks the rollout status of the control plane + components running on the management cluster, independently from + the data-plane version reported in the version field. + properties: + desired: + description: |- + desired is the release version that the control plane is reconciling towards. + It is derived from the HostedControlPlane release image fields. + properties: + channels: + description: |- + channels is the set of Cincinnati channels to which the release + currently belongs. + items: + type: string + type: array + x-kubernetes-list-type: set + image: + description: |- + image is a container image location that contains the update. When this + field is part of spec, image is optional if version is specified and the + availableUpdates field contains a matching version. + type: string + url: + description: |- + url contains information about this release. This URL is set by + the 'url' metadata property on a release or the metadata returned by + the update API and should be displayed as a link in user + interfaces. The URL field may not be set for test or nightly + releases. + type: string + version: + description: |- + version is a semantic version identifying the update version. When this + field is part of spec, version is optional if image is specified. + type: string + required: + - image + - version + type: object + history: + description: |- + history contains a list of versions applied to management-side control plane components. The newest entry is + first in the list. Entries have state Completed when all ControlPlaneComponent resources report the target + version with RolloutComplete=True. Entries have state Partial when the rollout is in progress or has failed. + items: + description: |- + ControlPlaneUpdateHistory is a record of a single version transition for management-side + control plane components. Each entry captures the target version, its release image, when + the rollout started, and when (or whether) it completed. + properties: + completionTime: + description: |- + completionTime is the time at which the update completed. It is set + when all management-side components have reached the target version. + It is not set while the update is in progress. + format: date-time + type: string + image: + description: image is the release image pullspec used for + this update. + maxLength: 447 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the update + was started. + format: date-time + type: string + state: + description: |- + state reflects whether the update was fully applied. The Partial state + indicates the update is not fully applied, while the Completed state + indicates the update was successfully rolled out. + enum: + - Completed + - Partial + type: string + version: + description: |- + version is a semantic version string identifying the update version + (e.g. "4.20.1"). + maxLength: 64 + minLength: 1 + type: string + x-kubernetes-validations: + - message: version must start with semantic version prefix + x.y.z + rule: self.matches('^\\d+\\.\\d+\\.\\d+.*') + required: + - image + - startedTime + - state + - version + type: object + maxItems: 100 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + observedGeneration: + description: observedGeneration reports which generation of the + HostedControlPlane spec is being synced. + format: int64 + maximum: 9007199254740992 + minimum: 1 + type: integer + required: + - desired + type: object customKubeconfig: description: |- customKubeconfig references an external custom kubeconfig secret. diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AutoNodeKarpenter.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AutoNodeKarpenter.yaml index c3cb29232d01..c49bb77e4945 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AutoNodeKarpenter.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AutoNodeKarpenter.yaml @@ -5251,6 +5251,117 @@ spec: - host - port type: object + controlPlaneVersion: + description: |- + controlPlaneVersion tracks the rollout status of the control plane + components running on the management cluster, independently from + the data-plane version reported in the version field. + properties: + desired: + description: |- + desired is the release version that the control plane is reconciling towards. + It is derived from the HostedControlPlane release image fields. + properties: + channels: + description: |- + channels is the set of Cincinnati channels to which the release + currently belongs. + items: + type: string + type: array + x-kubernetes-list-type: set + image: + description: |- + image is a container image location that contains the update. When this + field is part of spec, image is optional if version is specified and the + availableUpdates field contains a matching version. + type: string + url: + description: |- + url contains information about this release. This URL is set by + the 'url' metadata property on a release or the metadata returned by + the update API and should be displayed as a link in user + interfaces. The URL field may not be set for test or nightly + releases. + type: string + version: + description: |- + version is a semantic version identifying the update version. When this + field is part of spec, version is optional if image is specified. + type: string + required: + - image + - version + type: object + history: + description: |- + history contains a list of versions applied to management-side control plane components. The newest entry is + first in the list. Entries have state Completed when all ControlPlaneComponent resources report the target + version with RolloutComplete=True. Entries have state Partial when the rollout is in progress or has failed. + items: + description: |- + ControlPlaneUpdateHistory is a record of a single version transition for management-side + control plane components. Each entry captures the target version, its release image, when + the rollout started, and when (or whether) it completed. + properties: + completionTime: + description: |- + completionTime is the time at which the update completed. It is set + when all management-side components have reached the target version. + It is not set while the update is in progress. + format: date-time + type: string + image: + description: image is the release image pullspec used for + this update. + maxLength: 447 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the update + was started. + format: date-time + type: string + state: + description: |- + state reflects whether the update was fully applied. The Partial state + indicates the update is not fully applied, while the Completed state + indicates the update was successfully rolled out. + enum: + - Completed + - Partial + type: string + version: + description: |- + version is a semantic version string identifying the update version + (e.g. "4.20.1"). + maxLength: 64 + minLength: 1 + type: string + x-kubernetes-validations: + - message: version must start with semantic version prefix + x.y.z + rule: self.matches('^\\d+\\.\\d+\\.\\d+.*') + required: + - image + - startedTime + - state + - version + type: object + maxItems: 100 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + observedGeneration: + description: observedGeneration reports which generation of the + HostedControlPlane spec is being synced. + format: int64 + maximum: 9007199254740992 + minimum: 1 + type: integer + required: + - desired + type: object customKubeconfig: description: |- customKubeconfig references an external custom kubeconfig secret. diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml index 685d464f9d99..03a3de65fb23 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml @@ -5224,6 +5224,117 @@ spec: - host - port type: object + controlPlaneVersion: + description: |- + controlPlaneVersion tracks the rollout status of the control plane + components running on the management cluster, independently from + the data-plane version reported in the version field. + properties: + desired: + description: |- + desired is the release version that the control plane is reconciling towards. + It is derived from the HostedControlPlane release image fields. + properties: + channels: + description: |- + channels is the set of Cincinnati channels to which the release + currently belongs. + items: + type: string + type: array + x-kubernetes-list-type: set + image: + description: |- + image is a container image location that contains the update. When this + field is part of spec, image is optional if version is specified and the + availableUpdates field contains a matching version. + type: string + url: + description: |- + url contains information about this release. This URL is set by + the 'url' metadata property on a release or the metadata returned by + the update API and should be displayed as a link in user + interfaces. The URL field may not be set for test or nightly + releases. + type: string + version: + description: |- + version is a semantic version identifying the update version. When this + field is part of spec, version is optional if image is specified. + type: string + required: + - image + - version + type: object + history: + description: |- + history contains a list of versions applied to management-side control plane components. The newest entry is + first in the list. Entries have state Completed when all ControlPlaneComponent resources report the target + version with RolloutComplete=True. Entries have state Partial when the rollout is in progress or has failed. + items: + description: |- + ControlPlaneUpdateHistory is a record of a single version transition for management-side + control plane components. Each entry captures the target version, its release image, when + the rollout started, and when (or whether) it completed. + properties: + completionTime: + description: |- + completionTime is the time at which the update completed. It is set + when all management-side components have reached the target version. + It is not set while the update is in progress. + format: date-time + type: string + image: + description: image is the release image pullspec used for + this update. + maxLength: 447 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the update + was started. + format: date-time + type: string + state: + description: |- + state reflects whether the update was fully applied. The Partial state + indicates the update is not fully applied, while the Completed state + indicates the update was successfully rolled out. + enum: + - Completed + - Partial + type: string + version: + description: |- + version is a semantic version string identifying the update version + (e.g. "4.20.1"). + maxLength: 64 + minLength: 1 + type: string + x-kubernetes-validations: + - message: version must start with semantic version prefix + x.y.z + rule: self.matches('^\\d+\\.\\d+\\.\\d+.*') + required: + - image + - startedTime + - state + - version + type: object + maxItems: 100 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + observedGeneration: + description: observedGeneration reports which generation of the + HostedControlPlane spec is being synced. + format: int64 + maximum: 9007199254740992 + minimum: 1 + type: integer + required: + - desired + type: object customKubeconfig: description: |- customKubeconfig references an external custom kubeconfig secret. diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/DynamicResourceAllocation.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/DynamicResourceAllocation.yaml index 10a653bdd53c..9960a1ecafde 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/DynamicResourceAllocation.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/DynamicResourceAllocation.yaml @@ -5225,6 +5225,117 @@ spec: - host - port type: object + controlPlaneVersion: + description: |- + controlPlaneVersion tracks the rollout status of the control plane + components running on the management cluster, independently from + the data-plane version reported in the version field. + properties: + desired: + description: |- + desired is the release version that the control plane is reconciling towards. + It is derived from the HostedControlPlane release image fields. + properties: + channels: + description: |- + channels is the set of Cincinnati channels to which the release + currently belongs. + items: + type: string + type: array + x-kubernetes-list-type: set + image: + description: |- + image is a container image location that contains the update. When this + field is part of spec, image is optional if version is specified and the + availableUpdates field contains a matching version. + type: string + url: + description: |- + url contains information about this release. This URL is set by + the 'url' metadata property on a release or the metadata returned by + the update API and should be displayed as a link in user + interfaces. The URL field may not be set for test or nightly + releases. + type: string + version: + description: |- + version is a semantic version identifying the update version. When this + field is part of spec, version is optional if image is specified. + type: string + required: + - image + - version + type: object + history: + description: |- + history contains a list of versions applied to management-side control plane components. The newest entry is + first in the list. Entries have state Completed when all ControlPlaneComponent resources report the target + version with RolloutComplete=True. Entries have state Partial when the rollout is in progress or has failed. + items: + description: |- + ControlPlaneUpdateHistory is a record of a single version transition for management-side + control plane components. Each entry captures the target version, its release image, when + the rollout started, and when (or whether) it completed. + properties: + completionTime: + description: |- + completionTime is the time at which the update completed. It is set + when all management-side components have reached the target version. + It is not set while the update is in progress. + format: date-time + type: string + image: + description: image is the release image pullspec used for + this update. + maxLength: 447 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the update + was started. + format: date-time + type: string + state: + description: |- + state reflects whether the update was fully applied. The Partial state + indicates the update is not fully applied, while the Completed state + indicates the update was successfully rolled out. + enum: + - Completed + - Partial + type: string + version: + description: |- + version is a semantic version string identifying the update version + (e.g. "4.20.1"). + maxLength: 64 + minLength: 1 + type: string + x-kubernetes-validations: + - message: version must start with semantic version prefix + x.y.z + rule: self.matches('^\\d+\\.\\d+\\.\\d+.*') + required: + - image + - startedTime + - state + - version + type: object + maxItems: 100 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + observedGeneration: + description: observedGeneration reports which generation of the + HostedControlPlane spec is being synced. + format: int64 + maximum: 9007199254740992 + minimum: 1 + type: integer + required: + - desired + type: object customKubeconfig: description: |- customKubeconfig references an external custom kubeconfig secret. diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDC.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDC.yaml index 604452b11a89..95dd4aae72e4 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDC.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDC.yaml @@ -5540,6 +5540,117 @@ spec: - host - port type: object + controlPlaneVersion: + description: |- + controlPlaneVersion tracks the rollout status of the control plane + components running on the management cluster, independently from + the data-plane version reported in the version field. + properties: + desired: + description: |- + desired is the release version that the control plane is reconciling towards. + It is derived from the HostedControlPlane release image fields. + properties: + channels: + description: |- + channels is the set of Cincinnati channels to which the release + currently belongs. + items: + type: string + type: array + x-kubernetes-list-type: set + image: + description: |- + image is a container image location that contains the update. When this + field is part of spec, image is optional if version is specified and the + availableUpdates field contains a matching version. + type: string + url: + description: |- + url contains information about this release. This URL is set by + the 'url' metadata property on a release or the metadata returned by + the update API and should be displayed as a link in user + interfaces. The URL field may not be set for test or nightly + releases. + type: string + version: + description: |- + version is a semantic version identifying the update version. When this + field is part of spec, version is optional if image is specified. + type: string + required: + - image + - version + type: object + history: + description: |- + history contains a list of versions applied to management-side control plane components. The newest entry is + first in the list. Entries have state Completed when all ControlPlaneComponent resources report the target + version with RolloutComplete=True. Entries have state Partial when the rollout is in progress or has failed. + items: + description: |- + ControlPlaneUpdateHistory is a record of a single version transition for management-side + control plane components. Each entry captures the target version, its release image, when + the rollout started, and when (or whether) it completed. + properties: + completionTime: + description: |- + completionTime is the time at which the update completed. It is set + when all management-side components have reached the target version. + It is not set while the update is in progress. + format: date-time + type: string + image: + description: image is the release image pullspec used for + this update. + maxLength: 447 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the update + was started. + format: date-time + type: string + state: + description: |- + state reflects whether the update was fully applied. The Partial state + indicates the update is not fully applied, while the Completed state + indicates the update was successfully rolled out. + enum: + - Completed + - Partial + type: string + version: + description: |- + version is a semantic version string identifying the update version + (e.g. "4.20.1"). + maxLength: 64 + minLength: 1 + type: string + x-kubernetes-validations: + - message: version must start with semantic version prefix + x.y.z + rule: self.matches('^\\d+\\.\\d+\\.\\d+.*') + required: + - image + - startedTime + - state + - version + type: object + maxItems: 100 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + observedGeneration: + description: observedGeneration reports which generation of the + HostedControlPlane spec is being synced. + format: int64 + maximum: 9007199254740992 + minimum: 1 + type: integer + required: + - desired + type: object customKubeconfig: description: |- customKubeconfig references an external custom kubeconfig secret. diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml index cdcc55ea84db..d5c004664e25 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml @@ -5694,6 +5694,117 @@ spec: - host - port type: object + controlPlaneVersion: + description: |- + controlPlaneVersion tracks the rollout status of the control plane + components running on the management cluster, independently from + the data-plane version reported in the version field. + properties: + desired: + description: |- + desired is the release version that the control plane is reconciling towards. + It is derived from the HostedControlPlane release image fields. + properties: + channels: + description: |- + channels is the set of Cincinnati channels to which the release + currently belongs. + items: + type: string + type: array + x-kubernetes-list-type: set + image: + description: |- + image is a container image location that contains the update. When this + field is part of spec, image is optional if version is specified and the + availableUpdates field contains a matching version. + type: string + url: + description: |- + url contains information about this release. This URL is set by + the 'url' metadata property on a release or the metadata returned by + the update API and should be displayed as a link in user + interfaces. The URL field may not be set for test or nightly + releases. + type: string + version: + description: |- + version is a semantic version identifying the update version. When this + field is part of spec, version is optional if image is specified. + type: string + required: + - image + - version + type: object + history: + description: |- + history contains a list of versions applied to management-side control plane components. The newest entry is + first in the list. Entries have state Completed when all ControlPlaneComponent resources report the target + version with RolloutComplete=True. Entries have state Partial when the rollout is in progress or has failed. + items: + description: |- + ControlPlaneUpdateHistory is a record of a single version transition for management-side + control plane components. Each entry captures the target version, its release image, when + the rollout started, and when (or whether) it completed. + properties: + completionTime: + description: |- + completionTime is the time at which the update completed. It is set + when all management-side components have reached the target version. + It is not set while the update is in progress. + format: date-time + type: string + image: + description: image is the release image pullspec used for + this update. + maxLength: 447 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the update + was started. + format: date-time + type: string + state: + description: |- + state reflects whether the update was fully applied. The Partial state + indicates the update is not fully applied, while the Completed state + indicates the update was successfully rolled out. + enum: + - Completed + - Partial + type: string + version: + description: |- + version is a semantic version string identifying the update version + (e.g. "4.20.1"). + maxLength: 64 + minLength: 1 + type: string + x-kubernetes-validations: + - message: version must start with semantic version prefix + x.y.z + rule: self.matches('^\\d+\\.\\d+\\.\\d+.*') + required: + - image + - startedTime + - state + - version + type: object + maxItems: 100 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + observedGeneration: + description: observedGeneration reports which generation of the + HostedControlPlane spec is being synced. + format: int64 + maximum: 9007199254740992 + minimum: 1 + type: integer + required: + - desired + type: object customKubeconfig: description: |- customKubeconfig references an external custom kubeconfig secret. diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ImageStreamImportMode.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ImageStreamImportMode.yaml index f9cb4c7f4604..98b79f3db104 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ImageStreamImportMode.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ImageStreamImportMode.yaml @@ -5222,6 +5222,128 @@ spec: - host - port type: object + controlPlaneVersion: + description: |- + controlPlaneVersion tracks the rollout status of the control plane + components running on the management cluster, independently from + the data-plane version reported in the version field. + properties: + desired: + description: |- + desired is the release version that the control plane is reconciling towards. + It is derived from the HostedControlPlane release image fields. + properties: + architecture: + description: |- + architecture is an optional field that indicates the + value of the cluster architecture. In this context cluster + architecture means either a single architecture or a multi + architecture. + Valid values are 'Multi' and empty. + enum: + - Multi + - "" + type: string + channels: + description: |- + channels is the set of Cincinnati channels to which the release + currently belongs. + items: + type: string + type: array + x-kubernetes-list-type: set + image: + description: |- + image is a container image location that contains the update. When this + field is part of spec, image is optional if version is specified and the + availableUpdates field contains a matching version. + type: string + url: + description: |- + url contains information about this release. This URL is set by + the 'url' metadata property on a release or the metadata returned by + the update API and should be displayed as a link in user + interfaces. The URL field may not be set for test or nightly + releases. + type: string + version: + description: |- + version is a semantic version identifying the update version. When this + field is part of spec, version is optional if image is specified. + type: string + required: + - image + - version + type: object + history: + description: |- + history contains a list of versions applied to management-side control plane components. The newest entry is + first in the list. Entries have state Completed when all ControlPlaneComponent resources report the target + version with RolloutComplete=True. Entries have state Partial when the rollout is in progress or has failed. + items: + description: |- + ControlPlaneUpdateHistory is a record of a single version transition for management-side + control plane components. Each entry captures the target version, its release image, when + the rollout started, and when (or whether) it completed. + properties: + completionTime: + description: |- + completionTime is the time at which the update completed. It is set + when all management-side components have reached the target version. + It is not set while the update is in progress. + format: date-time + type: string + image: + description: image is the release image pullspec used for + this update. + maxLength: 447 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the update + was started. + format: date-time + type: string + state: + description: |- + state reflects whether the update was fully applied. The Partial state + indicates the update is not fully applied, while the Completed state + indicates the update was successfully rolled out. + enum: + - Completed + - Partial + type: string + version: + description: |- + version is a semantic version string identifying the update version + (e.g. "4.20.1"). + maxLength: 64 + minLength: 1 + type: string + x-kubernetes-validations: + - message: version must start with semantic version prefix + x.y.z + rule: self.matches('^\\d+\\.\\d+\\.\\d+.*') + required: + - image + - startedTime + - state + - version + type: object + maxItems: 100 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + observedGeneration: + description: observedGeneration reports which generation of the + HostedControlPlane spec is being synced. + format: int64 + maximum: 9007199254740992 + minimum: 1 + type: integer + required: + - desired + type: object customKubeconfig: description: |- customKubeconfig references an external custom kubeconfig secret. diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/KMSEncryptionProvider.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/KMSEncryptionProvider.yaml index 20d6eb275a04..31148df87608 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/KMSEncryptionProvider.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/KMSEncryptionProvider.yaml @@ -5280,6 +5280,117 @@ spec: - host - port type: object + controlPlaneVersion: + description: |- + controlPlaneVersion tracks the rollout status of the control plane + components running on the management cluster, independently from + the data-plane version reported in the version field. + properties: + desired: + description: |- + desired is the release version that the control plane is reconciling towards. + It is derived from the HostedControlPlane release image fields. + properties: + channels: + description: |- + channels is the set of Cincinnati channels to which the release + currently belongs. + items: + type: string + type: array + x-kubernetes-list-type: set + image: + description: |- + image is a container image location that contains the update. When this + field is part of spec, image is optional if version is specified and the + availableUpdates field contains a matching version. + type: string + url: + description: |- + url contains information about this release. This URL is set by + the 'url' metadata property on a release or the metadata returned by + the update API and should be displayed as a link in user + interfaces. The URL field may not be set for test or nightly + releases. + type: string + version: + description: |- + version is a semantic version identifying the update version. When this + field is part of spec, version is optional if image is specified. + type: string + required: + - image + - version + type: object + history: + description: |- + history contains a list of versions applied to management-side control plane components. The newest entry is + first in the list. Entries have state Completed when all ControlPlaneComponent resources report the target + version with RolloutComplete=True. Entries have state Partial when the rollout is in progress or has failed. + items: + description: |- + ControlPlaneUpdateHistory is a record of a single version transition for management-side + control plane components. Each entry captures the target version, its release image, when + the rollout started, and when (or whether) it completed. + properties: + completionTime: + description: |- + completionTime is the time at which the update completed. It is set + when all management-side components have reached the target version. + It is not set while the update is in progress. + format: date-time + type: string + image: + description: image is the release image pullspec used for + this update. + maxLength: 447 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the update + was started. + format: date-time + type: string + state: + description: |- + state reflects whether the update was fully applied. The Partial state + indicates the update is not fully applied, while the Completed state + indicates the update was successfully rolled out. + enum: + - Completed + - Partial + type: string + version: + description: |- + version is a semantic version string identifying the update version + (e.g. "4.20.1"). + maxLength: 64 + minLength: 1 + type: string + x-kubernetes-validations: + - message: version must start with semantic version prefix + x.y.z + rule: self.matches('^\\d+\\.\\d+\\.\\d+.*') + required: + - image + - startedTime + - state + - version + type: object + maxItems: 100 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + observedGeneration: + description: observedGeneration reports which generation of the + HostedControlPlane spec is being synced. + format: int64 + maximum: 9007199254740992 + minimum: 1 + type: integer + required: + - desired + type: object customKubeconfig: description: |- customKubeconfig references an external custom kubeconfig secret. diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/NetworkDiagnosticsConfig.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/NetworkDiagnosticsConfig.yaml index b0b98271d964..d30e2bf3ea22 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/NetworkDiagnosticsConfig.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/NetworkDiagnosticsConfig.yaml @@ -5356,6 +5356,117 @@ spec: - host - port type: object + controlPlaneVersion: + description: |- + controlPlaneVersion tracks the rollout status of the control plane + components running on the management cluster, independently from + the data-plane version reported in the version field. + properties: + desired: + description: |- + desired is the release version that the control plane is reconciling towards. + It is derived from the HostedControlPlane release image fields. + properties: + channels: + description: |- + channels is the set of Cincinnati channels to which the release + currently belongs. + items: + type: string + type: array + x-kubernetes-list-type: set + image: + description: |- + image is a container image location that contains the update. When this + field is part of spec, image is optional if version is specified and the + availableUpdates field contains a matching version. + type: string + url: + description: |- + url contains information about this release. This URL is set by + the 'url' metadata property on a release or the metadata returned by + the update API and should be displayed as a link in user + interfaces. The URL field may not be set for test or nightly + releases. + type: string + version: + description: |- + version is a semantic version identifying the update version. When this + field is part of spec, version is optional if image is specified. + type: string + required: + - image + - version + type: object + history: + description: |- + history contains a list of versions applied to management-side control plane components. The newest entry is + first in the list. Entries have state Completed when all ControlPlaneComponent resources report the target + version with RolloutComplete=True. Entries have state Partial when the rollout is in progress or has failed. + items: + description: |- + ControlPlaneUpdateHistory is a record of a single version transition for management-side + control plane components. Each entry captures the target version, its release image, when + the rollout started, and when (or whether) it completed. + properties: + completionTime: + description: |- + completionTime is the time at which the update completed. It is set + when all management-side components have reached the target version. + It is not set while the update is in progress. + format: date-time + type: string + image: + description: image is the release image pullspec used for + this update. + maxLength: 447 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the update + was started. + format: date-time + type: string + state: + description: |- + state reflects whether the update was fully applied. The Partial state + indicates the update is not fully applied, while the Completed state + indicates the update was successfully rolled out. + enum: + - Completed + - Partial + type: string + version: + description: |- + version is a semantic version string identifying the update version + (e.g. "4.20.1"). + maxLength: 64 + minLength: 1 + type: string + x-kubernetes-validations: + - message: version must start with semantic version prefix + x.y.z + rule: self.matches('^\\d+\\.\\d+\\.\\d+.*') + required: + - image + - startedTime + - state + - version + type: object + maxItems: 100 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + observedGeneration: + description: observedGeneration reports which generation of the + HostedControlPlane spec is being synced. + format: int64 + maximum: 9007199254740992 + minimum: 1 + type: integer + required: + - desired + type: object customKubeconfig: description: |- customKubeconfig references an external custom kubeconfig secret. diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/OpenStack.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/OpenStack.yaml index cad0937b64ec..6446feddc417 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/OpenStack.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/OpenStack.yaml @@ -5754,6 +5754,117 @@ spec: - host - port type: object + controlPlaneVersion: + description: |- + controlPlaneVersion tracks the rollout status of the control plane + components running on the management cluster, independently from + the data-plane version reported in the version field. + properties: + desired: + description: |- + desired is the release version that the control plane is reconciling towards. + It is derived from the HostedControlPlane release image fields. + properties: + channels: + description: |- + channels is the set of Cincinnati channels to which the release + currently belongs. + items: + type: string + type: array + x-kubernetes-list-type: set + image: + description: |- + image is a container image location that contains the update. When this + field is part of spec, image is optional if version is specified and the + availableUpdates field contains a matching version. + type: string + url: + description: |- + url contains information about this release. This URL is set by + the 'url' metadata property on a release or the metadata returned by + the update API and should be displayed as a link in user + interfaces. The URL field may not be set for test or nightly + releases. + type: string + version: + description: |- + version is a semantic version identifying the update version. When this + field is part of spec, version is optional if image is specified. + type: string + required: + - image + - version + type: object + history: + description: |- + history contains a list of versions applied to management-side control plane components. The newest entry is + first in the list. Entries have state Completed when all ControlPlaneComponent resources report the target + version with RolloutComplete=True. Entries have state Partial when the rollout is in progress or has failed. + items: + description: |- + ControlPlaneUpdateHistory is a record of a single version transition for management-side + control plane components. Each entry captures the target version, its release image, when + the rollout started, and when (or whether) it completed. + properties: + completionTime: + description: |- + completionTime is the time at which the update completed. It is set + when all management-side components have reached the target version. + It is not set while the update is in progress. + format: date-time + type: string + image: + description: image is the release image pullspec used for + this update. + maxLength: 447 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the update + was started. + format: date-time + type: string + state: + description: |- + state reflects whether the update was fully applied. The Partial state + indicates the update is not fully applied, while the Completed state + indicates the update was successfully rolled out. + enum: + - Completed + - Partial + type: string + version: + description: |- + version is a semantic version string identifying the update version + (e.g. "4.20.1"). + maxLength: 64 + minLength: 1 + type: string + x-kubernetes-validations: + - message: version must start with semantic version prefix + x.y.z + rule: self.matches('^\\d+\\.\\d+\\.\\d+.*') + required: + - image + - startedTime + - state + - version + type: object + maxItems: 100 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + observedGeneration: + description: observedGeneration reports which generation of the + HostedControlPlane spec is being synced. + format: int64 + maximum: 9007199254740992 + minimum: 1 + type: integer + required: + - desired + type: object customKubeconfig: description: |- customKubeconfig references an external custom kubeconfig secret. diff --git a/client/applyconfiguration/hypershift/v1beta1/controlplaneupdatehistory.go b/client/applyconfiguration/hypershift/v1beta1/controlplaneupdatehistory.go new file mode 100644 index 000000000000..4c8e80285169 --- /dev/null +++ b/client/applyconfiguration/hypershift/v1beta1/controlplaneupdatehistory.go @@ -0,0 +1,79 @@ +/* + + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1beta1 + +import ( + v1 "github.com/openshift/api/config/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// ControlPlaneUpdateHistoryApplyConfiguration represents a declarative configuration of the ControlPlaneUpdateHistory type for use +// with apply. +type ControlPlaneUpdateHistoryApplyConfiguration struct { + State *v1.UpdateState `json:"state,omitempty"` + StartedTime *metav1.Time `json:"startedTime,omitempty"` + CompletionTime *metav1.Time `json:"completionTime,omitempty"` + Version *string `json:"version,omitempty"` + Image *string `json:"image,omitempty"` +} + +// ControlPlaneUpdateHistoryApplyConfiguration constructs a declarative configuration of the ControlPlaneUpdateHistory type for use with +// apply. +func ControlPlaneUpdateHistory() *ControlPlaneUpdateHistoryApplyConfiguration { + return &ControlPlaneUpdateHistoryApplyConfiguration{} +} + +// WithState sets the State field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the State field is set to the value of the last call. +func (b *ControlPlaneUpdateHistoryApplyConfiguration) WithState(value v1.UpdateState) *ControlPlaneUpdateHistoryApplyConfiguration { + b.State = &value + return b +} + +// WithStartedTime sets the StartedTime field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the StartedTime field is set to the value of the last call. +func (b *ControlPlaneUpdateHistoryApplyConfiguration) WithStartedTime(value metav1.Time) *ControlPlaneUpdateHistoryApplyConfiguration { + b.StartedTime = &value + return b +} + +// WithCompletionTime sets the CompletionTime field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CompletionTime field is set to the value of the last call. +func (b *ControlPlaneUpdateHistoryApplyConfiguration) WithCompletionTime(value metav1.Time) *ControlPlaneUpdateHistoryApplyConfiguration { + b.CompletionTime = &value + return b +} + +// WithVersion sets the Version field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Version field is set to the value of the last call. +func (b *ControlPlaneUpdateHistoryApplyConfiguration) WithVersion(value string) *ControlPlaneUpdateHistoryApplyConfiguration { + b.Version = &value + return b +} + +// WithImage sets the Image field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Image field is set to the value of the last call. +func (b *ControlPlaneUpdateHistoryApplyConfiguration) WithImage(value string) *ControlPlaneUpdateHistoryApplyConfiguration { + b.Image = &value + return b +} diff --git a/client/applyconfiguration/hypershift/v1beta1/controlplaneversionstatus.go b/client/applyconfiguration/hypershift/v1beta1/controlplaneversionstatus.go new file mode 100644 index 000000000000..c0d66c9cba12 --- /dev/null +++ b/client/applyconfiguration/hypershift/v1beta1/controlplaneversionstatus.go @@ -0,0 +1,65 @@ +/* + + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1beta1 + +import ( + v1 "github.com/openshift/api/config/v1" +) + +// ControlPlaneVersionStatusApplyConfiguration represents a declarative configuration of the ControlPlaneVersionStatus type for use +// with apply. +type ControlPlaneVersionStatusApplyConfiguration struct { + Desired *v1.Release `json:"desired,omitempty"` + History []ControlPlaneUpdateHistoryApplyConfiguration `json:"history,omitempty"` + ObservedGeneration *int64 `json:"observedGeneration,omitempty"` +} + +// ControlPlaneVersionStatusApplyConfiguration constructs a declarative configuration of the ControlPlaneVersionStatus type for use with +// apply. +func ControlPlaneVersionStatus() *ControlPlaneVersionStatusApplyConfiguration { + return &ControlPlaneVersionStatusApplyConfiguration{} +} + +// WithDesired sets the Desired field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Desired field is set to the value of the last call. +func (b *ControlPlaneVersionStatusApplyConfiguration) WithDesired(value v1.Release) *ControlPlaneVersionStatusApplyConfiguration { + b.Desired = &value + return b +} + +// WithHistory adds the given value to the History field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the History field. +func (b *ControlPlaneVersionStatusApplyConfiguration) WithHistory(values ...*ControlPlaneUpdateHistoryApplyConfiguration) *ControlPlaneVersionStatusApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithHistory") + } + b.History = append(b.History, *values[i]) + } + return b +} + +// WithObservedGeneration sets the ObservedGeneration field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ObservedGeneration field is set to the value of the last call. +func (b *ControlPlaneVersionStatusApplyConfiguration) WithObservedGeneration(value int64) *ControlPlaneVersionStatusApplyConfiguration { + b.ObservedGeneration = &value + return b +} diff --git a/client/applyconfiguration/hypershift/v1beta1/hostedclusterstatus.go b/client/applyconfiguration/hypershift/v1beta1/hostedclusterstatus.go index b0d0963155ff..618807a417a2 100644 --- a/client/applyconfiguration/hypershift/v1beta1/hostedclusterstatus.go +++ b/client/applyconfiguration/hypershift/v1beta1/hostedclusterstatus.go @@ -26,16 +26,17 @@ import ( // HostedClusterStatusApplyConfiguration represents a declarative configuration of the HostedClusterStatus type for use // with apply. type HostedClusterStatusApplyConfiguration struct { - Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` - Version *ClusterVersionStatusApplyConfiguration `json:"version,omitempty"` - KubeConfig *corev1.LocalObjectReference `json:"kubeconfig,omitempty"` - CustomKubeconfig *corev1.LocalObjectReference `json:"customKubeconfig,omitempty"` - KubeadminPassword *corev1.LocalObjectReference `json:"kubeadminPassword,omitempty"` - IgnitionEndpoint *string `json:"ignitionEndpoint,omitempty"` - ControlPlaneEndpoint *APIEndpointApplyConfiguration `json:"controlPlaneEndpoint,omitempty"` - OAuthCallbackURLTemplate *string `json:"oauthCallbackURLTemplate,omitempty"` - PayloadArch *hypershiftv1beta1.PayloadArchType `json:"payloadArch,omitempty"` - Platform *PlatformStatusApplyConfiguration `json:"platform,omitempty"` + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` + ControlPlaneVersion *ControlPlaneVersionStatusApplyConfiguration `json:"controlPlaneVersion,omitempty"` + Version *ClusterVersionStatusApplyConfiguration `json:"version,omitempty"` + KubeConfig *corev1.LocalObjectReference `json:"kubeconfig,omitempty"` + CustomKubeconfig *corev1.LocalObjectReference `json:"customKubeconfig,omitempty"` + KubeadminPassword *corev1.LocalObjectReference `json:"kubeadminPassword,omitempty"` + IgnitionEndpoint *string `json:"ignitionEndpoint,omitempty"` + ControlPlaneEndpoint *APIEndpointApplyConfiguration `json:"controlPlaneEndpoint,omitempty"` + OAuthCallbackURLTemplate *string `json:"oauthCallbackURLTemplate,omitempty"` + PayloadArch *hypershiftv1beta1.PayloadArchType `json:"payloadArch,omitempty"` + Platform *PlatformStatusApplyConfiguration `json:"platform,omitempty"` } // HostedClusterStatusApplyConfiguration constructs a declarative configuration of the HostedClusterStatus type for use with @@ -57,6 +58,14 @@ func (b *HostedClusterStatusApplyConfiguration) WithConditions(values ...*v1.Con return b } +// WithControlPlaneVersion sets the ControlPlaneVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ControlPlaneVersion field is set to the value of the last call. +func (b *HostedClusterStatusApplyConfiguration) WithControlPlaneVersion(value *ControlPlaneVersionStatusApplyConfiguration) *HostedClusterStatusApplyConfiguration { + b.ControlPlaneVersion = value + return b +} + // WithVersion sets the Version field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the Version field is set to the value of the last call. diff --git a/client/applyconfiguration/hypershift/v1beta1/hostedcontrolplanestatus.go b/client/applyconfiguration/hypershift/v1beta1/hostedcontrolplanestatus.go index f816d4d7de16..fe46554b7751 100644 --- a/client/applyconfiguration/hypershift/v1beta1/hostedcontrolplanestatus.go +++ b/client/applyconfiguration/hypershift/v1beta1/hostedcontrolplanestatus.go @@ -26,21 +26,22 @@ import ( // HostedControlPlaneStatusApplyConfiguration represents a declarative configuration of the HostedControlPlaneStatus type for use // with apply. type HostedControlPlaneStatusApplyConfiguration struct { - Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` - Ready *bool `json:"ready,omitempty"` - Initialized *bool `json:"initialized,omitempty"` - ExternalManagedControlPlane *bool `json:"externalManagedControlPlane,omitempty"` - ControlPlaneEndpoint *APIEndpointApplyConfiguration `json:"controlPlaneEndpoint,omitempty"` - OAuthCallbackURLTemplate *string `json:"oauthCallbackURLTemplate,omitempty"` - VersionStatus *ClusterVersionStatusApplyConfiguration `json:"versionStatus,omitempty"` - Version *string `json:"version,omitempty"` - ReleaseImage *string `json:"releaseImage,omitempty"` - LastReleaseImageTransitionTime *metav1.Time `json:"lastReleaseImageTransitionTime,omitempty"` - KubeConfig *KubeconfigSecretRefApplyConfiguration `json:"kubeConfig,omitempty"` - CustomKubeconfig *KubeconfigSecretRefApplyConfiguration `json:"customKubeconfig,omitempty"` - KubeadminPassword *corev1.LocalObjectReference `json:"kubeadminPassword,omitempty"` - Platform *PlatformStatusApplyConfiguration `json:"platform,omitempty"` - NodeCount *int `json:"nodeCount,omitempty"` + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` + Ready *bool `json:"ready,omitempty"` + Initialized *bool `json:"initialized,omitempty"` + ExternalManagedControlPlane *bool `json:"externalManagedControlPlane,omitempty"` + ControlPlaneEndpoint *APIEndpointApplyConfiguration `json:"controlPlaneEndpoint,omitempty"` + OAuthCallbackURLTemplate *string `json:"oauthCallbackURLTemplate,omitempty"` + ControlPlaneVersion *ControlPlaneVersionStatusApplyConfiguration `json:"controlPlaneVersion,omitempty"` + VersionStatus *ClusterVersionStatusApplyConfiguration `json:"versionStatus,omitempty"` + Version *string `json:"version,omitempty"` + ReleaseImage *string `json:"releaseImage,omitempty"` + LastReleaseImageTransitionTime *metav1.Time `json:"lastReleaseImageTransitionTime,omitempty"` + KubeConfig *KubeconfigSecretRefApplyConfiguration `json:"kubeConfig,omitempty"` + CustomKubeconfig *KubeconfigSecretRefApplyConfiguration `json:"customKubeconfig,omitempty"` + KubeadminPassword *corev1.LocalObjectReference `json:"kubeadminPassword,omitempty"` + Platform *PlatformStatusApplyConfiguration `json:"platform,omitempty"` + NodeCount *int `json:"nodeCount,omitempty"` } // HostedControlPlaneStatusApplyConfiguration constructs a declarative configuration of the HostedControlPlaneStatus type for use with @@ -102,6 +103,14 @@ func (b *HostedControlPlaneStatusApplyConfiguration) WithOAuthCallbackURLTemplat return b } +// WithControlPlaneVersion sets the ControlPlaneVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ControlPlaneVersion field is set to the value of the last call. +func (b *HostedControlPlaneStatusApplyConfiguration) WithControlPlaneVersion(value *ControlPlaneVersionStatusApplyConfiguration) *HostedControlPlaneStatusApplyConfiguration { + b.ControlPlaneVersion = value + return b +} + // WithVersionStatus sets the VersionStatus field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the VersionStatus field is set to the value of the last call. diff --git a/client/applyconfiguration/utils.go b/client/applyconfiguration/utils.go index b670f9efab1d..4019ae2de3e2 100644 --- a/client/applyconfiguration/utils.go +++ b/client/applyconfiguration/utils.go @@ -131,6 +131,10 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &hypershiftv1beta1.ClusterVersionStatusApplyConfiguration{} case v1beta1.SchemeGroupVersion.WithKind("ControlPlaneManagedIdentities"): return &hypershiftv1beta1.ControlPlaneManagedIdentitiesApplyConfiguration{} + case v1beta1.SchemeGroupVersion.WithKind("ControlPlaneUpdateHistory"): + return &hypershiftv1beta1.ControlPlaneUpdateHistoryApplyConfiguration{} + case v1beta1.SchemeGroupVersion.WithKind("ControlPlaneVersionStatus"): + return &hypershiftv1beta1.ControlPlaneVersionStatusApplyConfiguration{} case v1beta1.SchemeGroupVersion.WithKind("DataPlaneManagedIdentities"): return &hypershiftv1beta1.DataPlaneManagedIdentitiesApplyConfiguration{} case v1beta1.SchemeGroupVersion.WithKind("Diagnostics"): diff --git a/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml b/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml index e463b835fac1..23030d91f0a5 100644 --- a/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml +++ b/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml @@ -24,6 +24,10 @@ spec: jsonPath: .status.version.history[?(@.state=="Completed")].version name: Version type: string + - description: Control Plane Version + jsonPath: .status.controlPlaneVersion.history[?(@.state=="Completed")].version + name: CP Version + type: string - description: KubeConfig Secret jsonPath: .status.kubeconfig.name name: KubeConfig @@ -44,6 +48,16 @@ spec: jsonPath: .status.conditions[?(@.type=="Available")].message name: Message type: string + - description: Control Plane Progress + jsonPath: .status.controlPlaneVersion.history[0].state + name: CP Progress + priority: 1 + type: string + - description: Data Plane Progress + jsonPath: .status.version.history[0].state + name: DP Progress + priority: 1 + type: string name: v1beta1 schema: openAPIV3Schema: @@ -6761,6 +6775,128 @@ spec: - host - port type: object + controlPlaneVersion: + description: |- + controlPlaneVersion tracks the rollout status of the control plane + components running on the management cluster, independently from + the data-plane version reported in the version field. + properties: + desired: + description: |- + desired is the release version that the control plane is reconciling towards. + It is derived from the HostedControlPlane release image fields. + properties: + architecture: + description: |- + architecture is an optional field that indicates the + value of the cluster architecture. In this context cluster + architecture means either a single architecture or a multi + architecture. + Valid values are 'Multi' and empty. + enum: + - Multi + - "" + type: string + channels: + description: |- + channels is the set of Cincinnati channels to which the release + currently belongs. + items: + type: string + type: array + x-kubernetes-list-type: set + image: + description: |- + image is a container image location that contains the update. When this + field is part of spec, image is optional if version is specified and the + availableUpdates field contains a matching version. + type: string + url: + description: |- + url contains information about this release. This URL is set by + the 'url' metadata property on a release or the metadata returned by + the update API and should be displayed as a link in user + interfaces. The URL field may not be set for test or nightly + releases. + type: string + version: + description: |- + version is a semantic version identifying the update version. When this + field is part of spec, version is optional if image is specified. + type: string + required: + - image + - version + type: object + history: + description: |- + history contains a list of versions applied to management-side control plane components. The newest entry is + first in the list. Entries have state Completed when all ControlPlaneComponent resources report the target + version with RolloutComplete=True. Entries have state Partial when the rollout is in progress or has failed. + items: + description: |- + ControlPlaneUpdateHistory is a record of a single version transition for management-side + control plane components. Each entry captures the target version, its release image, when + the rollout started, and when (or whether) it completed. + properties: + completionTime: + description: |- + completionTime is the time at which the update completed. It is set + when all management-side components have reached the target version. + It is not set while the update is in progress. + format: date-time + type: string + image: + description: image is the release image pullspec used for + this update. + maxLength: 447 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the update + was started. + format: date-time + type: string + state: + description: |- + state reflects whether the update was fully applied. The Partial state + indicates the update is not fully applied, while the Completed state + indicates the update was successfully rolled out. + enum: + - Completed + - Partial + type: string + version: + description: |- + version is a semantic version string identifying the update version + (e.g. "4.20.1"). + maxLength: 64 + minLength: 1 + type: string + x-kubernetes-validations: + - message: version must start with semantic version prefix + x.y.z + rule: self.matches('^\\d+\\.\\d+\\.\\d+.*') + required: + - image + - startedTime + - state + - version + type: object + maxItems: 100 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + observedGeneration: + description: observedGeneration reports which generation of the + HostedControlPlane spec is being synced. + format: int64 + maximum: 9007199254740992 + minimum: 1 + type: integer + required: + - desired + type: object customKubeconfig: description: |- customKubeconfig is a local secret reference to the external custom kubeconfig. diff --git a/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Default.crd.yaml b/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Default.crd.yaml index e1f6e073ecc6..59a0f90cb46b 100644 --- a/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Default.crd.yaml +++ b/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Default.crd.yaml @@ -24,6 +24,10 @@ spec: jsonPath: .status.version.history[?(@.state=="Completed")].version name: Version type: string + - description: Control Plane Version + jsonPath: .status.controlPlaneVersion.history[?(@.state=="Completed")].version + name: CP Version + type: string - description: KubeConfig Secret jsonPath: .status.kubeconfig.name name: KubeConfig @@ -44,6 +48,16 @@ spec: jsonPath: .status.conditions[?(@.type=="Available")].message name: Message type: string + - description: Control Plane Progress + jsonPath: .status.controlPlaneVersion.history[0].state + name: CP Progress + priority: 1 + type: string + - description: Data Plane Progress + jsonPath: .status.version.history[0].state + name: DP Progress + priority: 1 + type: string name: v1beta1 schema: openAPIV3Schema: @@ -6063,6 +6077,117 @@ spec: - host - port type: object + controlPlaneVersion: + description: |- + controlPlaneVersion tracks the rollout status of the control plane + components running on the management cluster, independently from + the data-plane version reported in the version field. + properties: + desired: + description: |- + desired is the release version that the control plane is reconciling towards. + It is derived from the HostedControlPlane release image fields. + properties: + channels: + description: |- + channels is the set of Cincinnati channels to which the release + currently belongs. + items: + type: string + type: array + x-kubernetes-list-type: set + image: + description: |- + image is a container image location that contains the update. When this + field is part of spec, image is optional if version is specified and the + availableUpdates field contains a matching version. + type: string + url: + description: |- + url contains information about this release. This URL is set by + the 'url' metadata property on a release or the metadata returned by + the update API and should be displayed as a link in user + interfaces. The URL field may not be set for test or nightly + releases. + type: string + version: + description: |- + version is a semantic version identifying the update version. When this + field is part of spec, version is optional if image is specified. + type: string + required: + - image + - version + type: object + history: + description: |- + history contains a list of versions applied to management-side control plane components. The newest entry is + first in the list. Entries have state Completed when all ControlPlaneComponent resources report the target + version with RolloutComplete=True. Entries have state Partial when the rollout is in progress or has failed. + items: + description: |- + ControlPlaneUpdateHistory is a record of a single version transition for management-side + control plane components. Each entry captures the target version, its release image, when + the rollout started, and when (or whether) it completed. + properties: + completionTime: + description: |- + completionTime is the time at which the update completed. It is set + when all management-side components have reached the target version. + It is not set while the update is in progress. + format: date-time + type: string + image: + description: image is the release image pullspec used for + this update. + maxLength: 447 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the update + was started. + format: date-time + type: string + state: + description: |- + state reflects whether the update was fully applied. The Partial state + indicates the update is not fully applied, while the Completed state + indicates the update was successfully rolled out. + enum: + - Completed + - Partial + type: string + version: + description: |- + version is a semantic version string identifying the update version + (e.g. "4.20.1"). + maxLength: 64 + minLength: 1 + type: string + x-kubernetes-validations: + - message: version must start with semantic version prefix + x.y.z + rule: self.matches('^\\d+\\.\\d+\\.\\d+.*') + required: + - image + - startedTime + - state + - version + type: object + maxItems: 100 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + observedGeneration: + description: observedGeneration reports which generation of the + HostedControlPlane spec is being synced. + format: int64 + maximum: 9007199254740992 + minimum: 1 + type: integer + required: + - desired + type: object customKubeconfig: description: |- customKubeconfig is a local secret reference to the external custom kubeconfig. diff --git a/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml b/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml index 4cb996802f55..d262e71c5202 100644 --- a/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml +++ b/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml @@ -24,6 +24,10 @@ spec: jsonPath: .status.version.history[?(@.state=="Completed")].version name: Version type: string + - description: Control Plane Version + jsonPath: .status.controlPlaneVersion.history[?(@.state=="Completed")].version + name: CP Version + type: string - description: KubeConfig Secret jsonPath: .status.kubeconfig.name name: KubeConfig @@ -44,6 +48,16 @@ spec: jsonPath: .status.conditions[?(@.type=="Available")].message name: Message type: string + - description: Control Plane Progress + jsonPath: .status.controlPlaneVersion.history[0].state + name: CP Progress + priority: 1 + type: string + - description: Data Plane Progress + jsonPath: .status.version.history[0].state + name: DP Progress + priority: 1 + type: string name: v1beta1 schema: openAPIV3Schema: @@ -6672,6 +6686,117 @@ spec: - host - port type: object + controlPlaneVersion: + description: |- + controlPlaneVersion tracks the rollout status of the control plane + components running on the management cluster, independently from + the data-plane version reported in the version field. + properties: + desired: + description: |- + desired is the release version that the control plane is reconciling towards. + It is derived from the HostedControlPlane release image fields. + properties: + channels: + description: |- + channels is the set of Cincinnati channels to which the release + currently belongs. + items: + type: string + type: array + x-kubernetes-list-type: set + image: + description: |- + image is a container image location that contains the update. When this + field is part of spec, image is optional if version is specified and the + availableUpdates field contains a matching version. + type: string + url: + description: |- + url contains information about this release. This URL is set by + the 'url' metadata property on a release or the metadata returned by + the update API and should be displayed as a link in user + interfaces. The URL field may not be set for test or nightly + releases. + type: string + version: + description: |- + version is a semantic version identifying the update version. When this + field is part of spec, version is optional if image is specified. + type: string + required: + - image + - version + type: object + history: + description: |- + history contains a list of versions applied to management-side control plane components. The newest entry is + first in the list. Entries have state Completed when all ControlPlaneComponent resources report the target + version with RolloutComplete=True. Entries have state Partial when the rollout is in progress or has failed. + items: + description: |- + ControlPlaneUpdateHistory is a record of a single version transition for management-side + control plane components. Each entry captures the target version, its release image, when + the rollout started, and when (or whether) it completed. + properties: + completionTime: + description: |- + completionTime is the time at which the update completed. It is set + when all management-side components have reached the target version. + It is not set while the update is in progress. + format: date-time + type: string + image: + description: image is the release image pullspec used for + this update. + maxLength: 447 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the update + was started. + format: date-time + type: string + state: + description: |- + state reflects whether the update was fully applied. The Partial state + indicates the update is not fully applied, while the Completed state + indicates the update was successfully rolled out. + enum: + - Completed + - Partial + type: string + version: + description: |- + version is a semantic version string identifying the update version + (e.g. "4.20.1"). + maxLength: 64 + minLength: 1 + type: string + x-kubernetes-validations: + - message: version must start with semantic version prefix + x.y.z + rule: self.matches('^\\d+\\.\\d+\\.\\d+.*') + required: + - image + - startedTime + - state + - version + type: object + maxItems: 100 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + observedGeneration: + description: observedGeneration reports which generation of the + HostedControlPlane spec is being synced. + format: int64 + maximum: 9007199254740992 + minimum: 1 + type: integer + required: + - desired + type: object customKubeconfig: description: |- customKubeconfig is a local secret reference to the external custom kubeconfig. diff --git a/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml b/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml index 332f30989d92..9bca89554167 100644 --- a/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml +++ b/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml @@ -6581,6 +6581,128 @@ spec: - host - port type: object + controlPlaneVersion: + description: |- + controlPlaneVersion tracks the rollout status of the control plane + components running on the management cluster, independently from + the data-plane version reported in the version field. + properties: + desired: + description: |- + desired is the release version that the control plane is reconciling towards. + It is derived from the HostedControlPlane release image fields. + properties: + architecture: + description: |- + architecture is an optional field that indicates the + value of the cluster architecture. In this context cluster + architecture means either a single architecture or a multi + architecture. + Valid values are 'Multi' and empty. + enum: + - Multi + - "" + type: string + channels: + description: |- + channels is the set of Cincinnati channels to which the release + currently belongs. + items: + type: string + type: array + x-kubernetes-list-type: set + image: + description: |- + image is a container image location that contains the update. When this + field is part of spec, image is optional if version is specified and the + availableUpdates field contains a matching version. + type: string + url: + description: |- + url contains information about this release. This URL is set by + the 'url' metadata property on a release or the metadata returned by + the update API and should be displayed as a link in user + interfaces. The URL field may not be set for test or nightly + releases. + type: string + version: + description: |- + version is a semantic version identifying the update version. When this + field is part of spec, version is optional if image is specified. + type: string + required: + - image + - version + type: object + history: + description: |- + history contains a list of versions applied to management-side control plane components. The newest entry is + first in the list. Entries have state Completed when all ControlPlaneComponent resources report the target + version with RolloutComplete=True. Entries have state Partial when the rollout is in progress or has failed. + items: + description: |- + ControlPlaneUpdateHistory is a record of a single version transition for management-side + control plane components. Each entry captures the target version, its release image, when + the rollout started, and when (or whether) it completed. + properties: + completionTime: + description: |- + completionTime is the time at which the update completed. It is set + when all management-side components have reached the target version. + It is not set while the update is in progress. + format: date-time + type: string + image: + description: image is the release image pullspec used for + this update. + maxLength: 447 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the update + was started. + format: date-time + type: string + state: + description: |- + state reflects whether the update was fully applied. The Partial state + indicates the update is not fully applied, while the Completed state + indicates the update was successfully rolled out. + enum: + - Completed + - Partial + type: string + version: + description: |- + version is a semantic version string identifying the update version + (e.g. "4.20.1"). + maxLength: 64 + minLength: 1 + type: string + x-kubernetes-validations: + - message: version must start with semantic version prefix + x.y.z + rule: self.matches('^\\d+\\.\\d+\\.\\d+.*') + required: + - image + - startedTime + - state + - version + type: object + maxItems: 100 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + observedGeneration: + description: observedGeneration reports which generation of the + HostedControlPlane spec is being synced. + format: int64 + maximum: 9007199254740992 + minimum: 1 + type: integer + required: + - desired + type: object customKubeconfig: description: |- customKubeconfig references an external custom kubeconfig secret. diff --git a/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Default.crd.yaml b/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Default.crd.yaml index ef4740e9cd23..08656b42635e 100644 --- a/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Default.crd.yaml +++ b/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Default.crd.yaml @@ -5883,6 +5883,117 @@ spec: - host - port type: object + controlPlaneVersion: + description: |- + controlPlaneVersion tracks the rollout status of the control plane + components running on the management cluster, independently from + the data-plane version reported in the version field. + properties: + desired: + description: |- + desired is the release version that the control plane is reconciling towards. + It is derived from the HostedControlPlane release image fields. + properties: + channels: + description: |- + channels is the set of Cincinnati channels to which the release + currently belongs. + items: + type: string + type: array + x-kubernetes-list-type: set + image: + description: |- + image is a container image location that contains the update. When this + field is part of spec, image is optional if version is specified and the + availableUpdates field contains a matching version. + type: string + url: + description: |- + url contains information about this release. This URL is set by + the 'url' metadata property on a release or the metadata returned by + the update API and should be displayed as a link in user + interfaces. The URL field may not be set for test or nightly + releases. + type: string + version: + description: |- + version is a semantic version identifying the update version. When this + field is part of spec, version is optional if image is specified. + type: string + required: + - image + - version + type: object + history: + description: |- + history contains a list of versions applied to management-side control plane components. The newest entry is + first in the list. Entries have state Completed when all ControlPlaneComponent resources report the target + version with RolloutComplete=True. Entries have state Partial when the rollout is in progress or has failed. + items: + description: |- + ControlPlaneUpdateHistory is a record of a single version transition for management-side + control plane components. Each entry captures the target version, its release image, when + the rollout started, and when (or whether) it completed. + properties: + completionTime: + description: |- + completionTime is the time at which the update completed. It is set + when all management-side components have reached the target version. + It is not set while the update is in progress. + format: date-time + type: string + image: + description: image is the release image pullspec used for + this update. + maxLength: 447 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the update + was started. + format: date-time + type: string + state: + description: |- + state reflects whether the update was fully applied. The Partial state + indicates the update is not fully applied, while the Completed state + indicates the update was successfully rolled out. + enum: + - Completed + - Partial + type: string + version: + description: |- + version is a semantic version string identifying the update version + (e.g. "4.20.1"). + maxLength: 64 + minLength: 1 + type: string + x-kubernetes-validations: + - message: version must start with semantic version prefix + x.y.z + rule: self.matches('^\\d+\\.\\d+\\.\\d+.*') + required: + - image + - startedTime + - state + - version + type: object + maxItems: 100 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + observedGeneration: + description: observedGeneration reports which generation of the + HostedControlPlane spec is being synced. + format: int64 + maximum: 9007199254740992 + minimum: 1 + type: integer + required: + - desired + type: object customKubeconfig: description: |- customKubeconfig references an external custom kubeconfig secret. diff --git a/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml b/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml index b19729c85a45..dec316134731 100644 --- a/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml +++ b/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml @@ -6492,6 +6492,117 @@ spec: - host - port type: object + controlPlaneVersion: + description: |- + controlPlaneVersion tracks the rollout status of the control plane + components running on the management cluster, independently from + the data-plane version reported in the version field. + properties: + desired: + description: |- + desired is the release version that the control plane is reconciling towards. + It is derived from the HostedControlPlane release image fields. + properties: + channels: + description: |- + channels is the set of Cincinnati channels to which the release + currently belongs. + items: + type: string + type: array + x-kubernetes-list-type: set + image: + description: |- + image is a container image location that contains the update. When this + field is part of spec, image is optional if version is specified and the + availableUpdates field contains a matching version. + type: string + url: + description: |- + url contains information about this release. This URL is set by + the 'url' metadata property on a release or the metadata returned by + the update API and should be displayed as a link in user + interfaces. The URL field may not be set for test or nightly + releases. + type: string + version: + description: |- + version is a semantic version identifying the update version. When this + field is part of spec, version is optional if image is specified. + type: string + required: + - image + - version + type: object + history: + description: |- + history contains a list of versions applied to management-side control plane components. The newest entry is + first in the list. Entries have state Completed when all ControlPlaneComponent resources report the target + version with RolloutComplete=True. Entries have state Partial when the rollout is in progress or has failed. + items: + description: |- + ControlPlaneUpdateHistory is a record of a single version transition for management-side + control plane components. Each entry captures the target version, its release image, when + the rollout started, and when (or whether) it completed. + properties: + completionTime: + description: |- + completionTime is the time at which the update completed. It is set + when all management-side components have reached the target version. + It is not set while the update is in progress. + format: date-time + type: string + image: + description: image is the release image pullspec used for + this update. + maxLength: 447 + minLength: 1 + type: string + startedTime: + description: startedTime is the time at which the update + was started. + format: date-time + type: string + state: + description: |- + state reflects whether the update was fully applied. The Partial state + indicates the update is not fully applied, while the Completed state + indicates the update was successfully rolled out. + enum: + - Completed + - Partial + type: string + version: + description: |- + version is a semantic version string identifying the update version + (e.g. "4.20.1"). + maxLength: 64 + minLength: 1 + type: string + x-kubernetes-validations: + - message: version must start with semantic version prefix + x.y.z + rule: self.matches('^\\d+\\.\\d+\\.\\d+.*') + required: + - image + - startedTime + - state + - version + type: object + maxItems: 100 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + observedGeneration: + description: observedGeneration reports which generation of the + HostedControlPlane spec is being synced. + format: int64 + maximum: 9007199254740992 + minimum: 1 + type: integer + required: + - desired + type: object customKubeconfig: description: |- customKubeconfig references an external custom kubeconfig secret. diff --git a/control-plane-operator/controllers/hostedcontrolplane/controlplaneversion.go b/control-plane-operator/controllers/hostedcontrolplane/controlplaneversion.go new file mode 100644 index 000000000000..13df9165bce2 --- /dev/null +++ b/control-plane-operator/controllers/hostedcontrolplane/controlplaneversion.go @@ -0,0 +1,362 @@ +package hostedcontrolplane + +import ( + "math" + "strings" + + hyperv1 "github.com/openshift/hypershift/api/hypershift/v1beta1" + + configv1 "github.com/openshift/api/config/v1" + + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/clock" +) + +// Pruning constants ported from CVO (pkg/cvo/status_history.go). +const ( + maxHistory = 100 + maxFinalEntryIndex = 4 + mostImportantWeight = 1000.0 + interestingWeight = 30.0 + partialMinorWeight = 20.0 + partialZStreamWeight = -20.0 + sliceIndexWeight = -1.01 +) + +// ensureControlPlaneVersionPartial ensures a Partial history entry exists for the +// desired version without updating observedGeneration. This is called on list +// failure so consumers know an upgrade was attempted, consistent with +// CVO's syncFailingStatus pattern. +func ensureControlPlaneVersionPartial( + hcp *hyperv1.HostedControlPlane, + clk clock.Clock, + releaseVersion string, + desiredImage string, +) hyperv1.ControlPlaneVersionStatus { + now := metav1.NewTime(clk.Now()) + + existing := hcp.Status.ControlPlaneVersion + desired := configv1.Release{Version: releaseVersion, Image: desiredImage} + if existing.Desired.Image == "" { + return hyperv1.ControlPlaneVersionStatus{ + Desired: desired, + History: []hyperv1.ControlPlaneUpdateHistory{ + { + State: configv1.PartialUpdate, + StartedTime: now, + Version: releaseVersion, + Image: desiredImage, + }, + }, + // Do not set observedGeneration — preserve nil to signal + // the generation was not successfully processed. + } + } + + result := existing.DeepCopy() + result.Desired = desired + // Preserve existing observedGeneration — do not update it. + + // There is no history yet, or the latest entry is for a different release + // than what we're now targeting + if len(result.History) == 0 || !mergeEqualVersions(&result.History[0], result.Desired) { + if len(result.History) > 0 && result.History[0].CompletionTime.IsZero() { + result.History[0].CompletionTime = now + } + entry := hyperv1.ControlPlaneUpdateHistory{ + State: configv1.PartialUpdate, + StartedTime: now, + Version: releaseVersion, + Image: desiredImage, + } + result.History = append([]hyperv1.ControlPlaneUpdateHistory{entry}, result.History...) + result.History = pruneHistory(result.History) + } + return *result +} + +// reconcileControlPlaneVersion aggregates ControlPlaneComponent status into +// hcp.Status.ControlPlaneVersion, implementing CVO mergeEqualVersions +// semantics for change detection, dual version+rollout completion checks, +// first-population behavior, and observedGeneration updates. +func reconcileControlPlaneVersion( + hcp *hyperv1.HostedControlPlane, + components []hyperv1.ControlPlaneComponent, + clk clock.Clock, + releaseVersion string, + desiredImage string, +) hyperv1.ControlPlaneVersionStatus { + now := metav1.NewTime(clk.Now()) + + existing := hcp.Status.ControlPlaneVersion + desired := configv1.Release{Version: releaseVersion, Image: desiredImage} + if existing.Desired.Image == "" { + // First population: create initial Partial entry. + return hyperv1.ControlPlaneVersionStatus{ + Desired: desired, + History: []hyperv1.ControlPlaneUpdateHistory{ + { + State: configv1.PartialUpdate, + StartedTime: now, + Version: releaseVersion, + Image: desiredImage, + }, + }, + ObservedGeneration: hcp.Generation, + } + } + + result := existing.DeepCopy() + result.Desired = desired + result.ObservedGeneration = hcp.Generation + + // Detect desired release change using CVO mergeEqualVersions semantics. + // If the current history entry does NOT merge with the new desired release, + // a new version transition has occurred. + if len(result.History) > 0 && !mergeEqualVersions(&result.History[0], desired) { + // Close out the previous entry by setting CompletionTime. + entry := &result.History[0] + if entry.CompletionTime.IsZero() { + entry.CompletionTime = now + } + // Prepend new Partial entry for the new desired release. + newEntry := hyperv1.ControlPlaneUpdateHistory{ + State: configv1.PartialUpdate, + StartedTime: now, + Version: releaseVersion, + Image: desiredImage, + } + result.History = append([]hyperv1.ControlPlaneUpdateHistory{newEntry}, result.History...) + result.History = pruneHistory(result.History) + return *result + } + + // No desired change — check completion. + // All components must report Status.Version == desired version AND RolloutComplete=True. + if len(result.History) > 0 && result.History[0].State == configv1.PartialUpdate { + if allComponentsAtVersion(components, releaseVersion) { + result.History[0].State = configv1.CompletedUpdate + result.History[0].CompletionTime = now + } + } + + result.History = pruneHistory(result.History) + return *result +} + +// mergeEqualVersions implements CVO's mergeEqualVersions semantics (pkg/cvo/status.go). +// It returns true if the current history entry and desired release refer to the same +// version, meaning no new history entry should be created. It also updates the current +// entry's version/image when the other side is empty, matching CVO behavior. +func mergeEqualVersions(current *hyperv1.ControlPlaneUpdateHistory, desired configv1.Release) bool { + if len(desired.Image) > 0 && desired.Image == current.Image { + if len(desired.Version) == 0 { + return true + } + if len(current.Version) == 0 || desired.Version == current.Version { + current.Version = desired.Version + return true + } + } + if len(desired.Version) > 0 && desired.Version == current.Version { + if len(current.Image) == 0 || desired.Image == current.Image { + current.Image = desired.Image + return true + } + } + return false +} + +// allComponentsAtVersion returns true when every component reports +// Status.Version == desiredVersion AND has the RolloutComplete condition +// set to True. Returns false when there are no components. +// Components with no Status.Version or a mismatching version are treated +// as not matching the desired version and keep the state Partial. +func allComponentsAtVersion(components []hyperv1.ControlPlaneComponent, desiredVersion string) bool { + if len(components) == 0 { + return false + } + for i := range components { + if components[i].Status.Version != desiredVersion { + return false + } + cond := meta.FindStatusCondition(components[i].Status.Conditions, string(hyperv1.ControlPlaneComponentRolloutComplete)) + if cond == nil || cond.Status != metav1.ConditionTrue { + return false + } + } + return true +} + +// pruneHistory caps the history at maxHistory entries by repeatedly removing +// the lowest-ranked entry, faithfully porting the CVO algorithm from +// pkg/cvo/status_history.go. +func pruneHistory(history []hyperv1.ControlPlaneUpdateHistory) []hyperv1.ControlPlaneUpdateHistory { + for len(history) > maxHistory { + history = pruneHistoryWithMax(history, maxHistory) + } + return history +} + +// pruneHistoryWithMax is the core pruning implementation. maxSize is configurable +// to ease unit testing with smaller history slices. +func pruneHistoryWithMax(history []hyperv1.ControlPlaneUpdateHistory, maxSize int) []hyperv1.ControlPlaneUpdateHistory { + if len(history) <= maxSize { + return history + } + mostRecentCompletedIdx := -1 + for i := range history { + if history[i].State == configv1.CompletedUpdate { + mostRecentCompletedIdx = i + break + } + } + + lowestRank := math.MaxFloat64 + var lowestRankIdx int + + for i := range history { + rank := 0.0 + if isTheInitialEntry(i, maxSize) || isAFinalEntry(i) || isTheMostRecentCompletedEntry(i, mostRecentCompletedIdx) { + rank = mostImportantWeight + } else if isTheFirstOrLastCompletedInAMinor(i, history, maxSize) { + rank += interestingWeight + } else if isPartialPortionOfMinorTransition(i, history, maxSize) { + rank += partialMinorWeight + } else if isPartialWithinAZStream(i, history, maxSize) { + rank += partialZStreamWeight + } + rank += sliceIndexWeight * float64(i) + + if rank < lowestRank { + lowestRank = rank + lowestRankIdx = i + } + } + + if lowestRankIdx == maxSize { + return history[:maxSize] + } + return append(history[:lowestRankIdx], history[lowestRankIdx+1:]...) +} + +// isTheInitialEntry returns true if the entry is the oldest entry (at the max history boundary). +func isTheInitialEntry(entryIndex, maxHistorySize int) bool { + return entryIndex == maxHistorySize +} + +// isAFinalEntry returns true if the entry is among the most recent entries. +func isAFinalEntry(entryIndex int) bool { + return entryIndex <= maxFinalEntryIndex +} + +// isTheMostRecentCompletedEntry returns true if the entry is the most recent completed entry. +func isTheMostRecentCompletedEntry(entryIndex, mostRecentCompletedEntryIndex int) bool { + return entryIndex == mostRecentCompletedEntryIndex +} + +// isTheFirstOrLastCompletedInAMinor returns true if the entry at idx is the first or last +// completed update for a given minor version. +func isTheFirstOrLastCompletedInAMinor(idx int, h []hyperv1.ControlPlaneUpdateHistory, maxSize int) bool { + if h[idx].State == configv1.PartialUpdate { + return false + } + if idx == 0 || idx == maxSize { + return true + } + nextOlder := findNextOlderCompleted(idx, h) + if nextOlder == idx || !sameMinorVersion(h[idx], h[nextOlder]) { + return true + } + nextNewer := findNextNewerCompleted(idx, h) + if nextNewer == idx || !sameMinorVersion(h[idx], h[nextNewer]) { + return true + } + return false +} + +// isPartialPortionOfMinorTransition returns true if the entry at idx is a partial update +// between completed updates that transition from one minor version to another. +func isPartialPortionOfMinorTransition(idx int, h []hyperv1.ControlPlaneUpdateHistory, maxSize int) bool { + if h[idx].State == configv1.CompletedUpdate || idx == 0 || idx == maxSize { + return false + } + prevIdx := findNextOlderCompleted(idx, h) + if prevIdx == idx { + return false + } + nextIdx := findNextNewerCompleted(idx, h) + if nextIdx == idx || sameMinorVersion(h[prevIdx], h[nextIdx]) { + return false + } + return true +} + +// isPartialWithinAZStream returns true if the entry at idx is a partial update between +// completed updates that transition from one z-stream version to another within the same minor. +func isPartialWithinAZStream(idx int, h []hyperv1.ControlPlaneUpdateHistory, maxSize int) bool { + if h[idx].State == configv1.CompletedUpdate || idx == 0 || idx == maxSize { + return false + } + prevIdx := findNextOlderCompleted(idx, h) + if prevIdx == idx { + return false + } + nextIdx := findNextNewerCompleted(idx, h) + if nextIdx == idx || sameZStreamVersion(h[prevIdx], h[nextIdx]) { + return false + } + return true +} + +// findNextOlderCompleted returns the index of the next older (higher index) completed entry. +// Returns idx if none found. +func findNextOlderCompleted(idx int, h []hyperv1.ControlPlaneUpdateHistory) int { + for i := idx + 1; i < len(h); i++ { + if h[i].State == configv1.CompletedUpdate { + return i + } + } + return idx +} + +// findNextNewerCompleted returns the index of the next newer (lower index) completed entry. +// Returns idx if none found. +func findNextNewerCompleted(idx int, h []hyperv1.ControlPlaneUpdateHistory) int { + for i := idx - 1; i >= 0; i-- { + if h[i].State == configv1.CompletedUpdate { + return i + } + } + return idx +} + +// sameMinorVersion returns true if both entries have the same minor version. +func sameMinorVersion(a, b hyperv1.ControlPlaneUpdateHistory) bool { + return getEffectiveMinor(a.Version) == getEffectiveMinor(b.Version) +} + +// sameZStreamVersion returns true if both entries have the same minor and micro version. +func sameZStreamVersion(a, b hyperv1.ControlPlaneUpdateHistory) bool { + return getEffectiveMinor(a.Version) == getEffectiveMinor(b.Version) && + getEffectiveMicro(a.Version) == getEffectiveMicro(b.Version) +} + +// getEffectiveMinor returns the minor component (y) from a version string x.y[.z]. +func getEffectiveMinor(version string) string { + splits := strings.Split(version, ".") + if len(splits) < 2 { + return "" + } + return splits[1] +} + +// getEffectiveMicro returns the micro/z-stream component (z) from a version string x.y.z. +func getEffectiveMicro(version string) string { + splits := strings.Split(version, ".") + if len(splits) < 3 { + return "" + } + return splits[2] +} diff --git a/control-plane-operator/controllers/hostedcontrolplane/controlplaneversion_pruning_test.go b/control-plane-operator/controllers/hostedcontrolplane/controlplaneversion_pruning_test.go new file mode 100644 index 000000000000..19629d62ff41 --- /dev/null +++ b/control-plane-operator/controllers/hostedcontrolplane/controlplaneversion_pruning_test.go @@ -0,0 +1,349 @@ +package hostedcontrolplane + +import ( + "fmt" + "reflect" + "testing" + + hyperv1 "github.com/openshift/hypershift/api/hypershift/v1beta1" + + configv1 "github.com/openshift/api/config/v1" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/google/go-cmp/cmp" +) + +// makeHistory creates a slice of ControlPlaneUpdateHistory entries for pruning tests. +// Entries are ordered newest-first (index 0 = most recent). Callers provide version +// strings in the form "4.17.2" and states (Completed or Partial). +func makeHistory(entries []struct { + version string + state configv1.UpdateState +}) []hyperv1.ControlPlaneUpdateHistory { + result := make([]hyperv1.ControlPlaneUpdateHistory, len(entries)) + for i, e := range entries { + h := hyperv1.ControlPlaneUpdateHistory{ + State: e.state, + StartedTime: metav1.Now(), + Version: e.version, + Image: fmt.Sprintf("quay.io/ocp/release:%s", e.version), + } + if e.state == configv1.CompletedUpdate { + now := metav1.Now() + h.CompletionTime = now + } + result[i] = h + } + return result +} + +// makeSimpleHistory creates a slice of ControlPlaneUpdateHistory with just state and version, +// matching the CVO test style where only State and Version matter for pruning logic. +func makeSimpleHistory(entries []struct { + state configv1.UpdateState + version string +}) []hyperv1.ControlPlaneUpdateHistory { + result := make([]hyperv1.ControlPlaneUpdateHistory, len(entries)) + for i, e := range entries { + result[i] = hyperv1.ControlPlaneUpdateHistory{ + State: e.state, + Version: e.version, + } + } + return result +} + +// historyVersions extracts state+version pairs for comparison, ignoring time fields. +func historyVersions(h []hyperv1.ControlPlaneUpdateHistory) []struct { + state configv1.UpdateState + version string +} { + result := make([]struct { + state configv1.UpdateState + version string + }, len(h)) + for i, e := range h { + result[i] = struct { + state configv1.UpdateState + version string + }{state: e.State, version: e.Version} + } + return result +} + +// testMaxHistory is the max history size used in the CVO-ported prune test cases. +// CVO tests use 10 (with 11-entry inputs) to keep test data small. +const testMaxHistory = 10 + +// TestPruneHistory ports CVO's Test_prune test cases. +func TestPruneHistory(t *testing.T) { + type entry = struct { + state configv1.UpdateState + version string + } + tests := []struct { + name string + history []entry + want []entry + }{ + { + name: "When a partial update exists within a minor transition, it should prune the z-stream partial", + history: []entry{ + {configv1.CompletedUpdate, "4.6.3"}, + {configv1.CompletedUpdate, "4.5.3"}, + {configv1.CompletedUpdate, "4.4.3"}, + {configv1.CompletedUpdate, "4.3.3"}, + {configv1.CompletedUpdate, "4.3.2"}, + {configv1.CompletedUpdate, "4.3.1"}, + {configv1.CompletedUpdate, "4.2.1"}, + {configv1.PartialUpdate, "4.1.4"}, + {configv1.PartialUpdate, "4.1.3"}, + {configv1.PartialUpdate, "4.1.2"}, + {configv1.CompletedUpdate, "4.1.1"}, + }, + want: []entry{ + {configv1.CompletedUpdate, "4.6.3"}, + {configv1.CompletedUpdate, "4.5.3"}, + {configv1.CompletedUpdate, "4.4.3"}, + {configv1.CompletedUpdate, "4.3.3"}, + {configv1.CompletedUpdate, "4.3.2"}, + {configv1.CompletedUpdate, "4.3.1"}, + {configv1.CompletedUpdate, "4.2.1"}, + {configv1.PartialUpdate, "4.1.4"}, + {configv1.PartialUpdate, "4.1.3"}, + {configv1.CompletedUpdate, "4.1.1"}, + }, + }, + { + name: "When a partial update exists within a z-stream transition, it should prune the z-stream partial", + history: []entry{ + {configv1.CompletedUpdate, "4.5.3"}, + {configv1.CompletedUpdate, "4.4.3"}, + {configv1.CompletedUpdate, "4.4.3"}, + {configv1.CompletedUpdate, "4.4.2"}, + {configv1.CompletedUpdate, "4.1.10"}, + {configv1.CompletedUpdate, "4.1.9"}, + {configv1.CompletedUpdate, "4.1.4"}, + {configv1.PartialUpdate, "4.1.3"}, + {configv1.CompletedUpdate, "4.1.2"}, + {configv1.PartialUpdate, "4.0.1"}, + {configv1.CompletedUpdate, "4.0.1"}, + }, + want: []entry{ + {configv1.CompletedUpdate, "4.5.3"}, + {configv1.CompletedUpdate, "4.4.3"}, + {configv1.CompletedUpdate, "4.4.3"}, + {configv1.CompletedUpdate, "4.4.2"}, + {configv1.CompletedUpdate, "4.1.10"}, + {configv1.CompletedUpdate, "4.1.9"}, + {configv1.CompletedUpdate, "4.1.4"}, + {configv1.CompletedUpdate, "4.1.2"}, + {configv1.PartialUpdate, "4.0.1"}, + {configv1.CompletedUpdate, "4.0.1"}, + }, + }, + { + name: "When all entries are completed across different minors, it should prune the oldest not in mostImportantWeight set", + history: []entry{ + {configv1.CompletedUpdate, "4.11.0"}, + {configv1.CompletedUpdate, "4.10.0"}, + {configv1.CompletedUpdate, "4.9.0"}, + {configv1.CompletedUpdate, "4.8.0"}, + {configv1.CompletedUpdate, "4.7.0"}, + {configv1.CompletedUpdate, "4.6.0"}, + {configv1.CompletedUpdate, "4.5.0"}, + {configv1.CompletedUpdate, "4.4.0"}, + {configv1.CompletedUpdate, "4.3.0"}, + {configv1.CompletedUpdate, "4.2.0"}, + {configv1.CompletedUpdate, "4.1.0"}, + }, + want: []entry{ + {configv1.CompletedUpdate, "4.11.0"}, + {configv1.CompletedUpdate, "4.10.0"}, + {configv1.CompletedUpdate, "4.9.0"}, + {configv1.CompletedUpdate, "4.8.0"}, + {configv1.CompletedUpdate, "4.7.0"}, + {configv1.CompletedUpdate, "4.6.0"}, + {configv1.CompletedUpdate, "4.5.0"}, + {configv1.CompletedUpdate, "4.4.0"}, + {configv1.CompletedUpdate, "4.3.0"}, + {configv1.CompletedUpdate, "4.1.0"}, + }, + }, + { + name: "When a partial exists not in mostImportantWeight set, it should prune only the partial", + history: []entry{ + {configv1.CompletedUpdate, "4.11.0"}, + {configv1.PartialUpdate, "4.10.0"}, + {configv1.CompletedUpdate, "4.9.0"}, + {configv1.CompletedUpdate, "4.8.0"}, + {configv1.CompletedUpdate, "4.7.0"}, + {configv1.PartialUpdate, "4.6.0"}, + {configv1.CompletedUpdate, "4.5.0"}, + {configv1.CompletedUpdate, "4.4.0"}, + {configv1.CompletedUpdate, "4.3.0"}, + {configv1.CompletedUpdate, "4.2.0"}, + {configv1.CompletedUpdate, "4.1.0"}, + }, + want: []entry{ + {configv1.CompletedUpdate, "4.11.0"}, + {configv1.PartialUpdate, "4.10.0"}, + {configv1.CompletedUpdate, "4.9.0"}, + {configv1.CompletedUpdate, "4.8.0"}, + {configv1.CompletedUpdate, "4.7.0"}, + {configv1.CompletedUpdate, "4.5.0"}, + {configv1.CompletedUpdate, "4.4.0"}, + {configv1.CompletedUpdate, "4.3.0"}, + {configv1.CompletedUpdate, "4.2.0"}, + {configv1.CompletedUpdate, "4.1.0"}, + }, + }, + { + name: "When both z-stream and minor partials exist, it should prune the z-stream partial over the minor partial", + history: []entry{ + {configv1.CompletedUpdate, "4.11.0"}, + {configv1.CompletedUpdate, "4.10.0"}, + {configv1.CompletedUpdate, "4.9.0"}, + {configv1.CompletedUpdate, "4.8.0"}, + {configv1.CompletedUpdate, "4.6.1"}, + {configv1.PartialUpdate, "4.6.1"}, + {configv1.CompletedUpdate, "4.6.0"}, + {configv1.CompletedUpdate, "4.4.0"}, + {configv1.PartialUpdate, "4.3.0"}, + {configv1.CompletedUpdate, "4.2.0"}, + {configv1.CompletedUpdate, "4.1.0"}, + }, + want: []entry{ + {configv1.CompletedUpdate, "4.11.0"}, + {configv1.CompletedUpdate, "4.10.0"}, + {configv1.CompletedUpdate, "4.9.0"}, + {configv1.CompletedUpdate, "4.8.0"}, + {configv1.CompletedUpdate, "4.6.1"}, + {configv1.CompletedUpdate, "4.6.0"}, + {configv1.CompletedUpdate, "4.4.0"}, + {configv1.PartialUpdate, "4.3.0"}, + {configv1.CompletedUpdate, "4.2.0"}, + {configv1.CompletedUpdate, "4.1.0"}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + input := makeSimpleHistory(tt.history) + got := pruneHistoryWithMax(input, testMaxHistory) + gotVersions := historyVersions(got) + if !reflect.DeepEqual(tt.want, gotVersions) { + t.Fatalf("unexpected result:\n%s", cmp.Diff(tt.want, gotVersions)) + } + }) + } +} + +// TestPruneHistory_UnderMaxHistoryUnchanged verifies that when history has fewer +// than maxHistory entries, pruning is a no-op. +func TestPruneHistory_UnderMaxHistoryUnchanged(t *testing.T) { + entries := make([]struct { + version string + state configv1.UpdateState + }, 50) + for i := 0; i < 50; i++ { + entries[i] = struct { + version string + state configv1.UpdateState + }{ + version: fmt.Sprintf("4.17.%d", 49-i), + state: configv1.CompletedUpdate, + } + } + history := makeHistory(entries) + + pruned := pruneHistory(history) + + if len(pruned) != 50 { + t.Errorf("When fewer than %d entries exist, it should not prune, got %d entries", maxHistory, len(pruned)) + } +} + +// TestPruneHistory_ExactlyMaxHistoryUnchanged verifies that when history has exactly +// maxHistory entries, pruning is a no-op. +func TestPruneHistory_ExactlyMaxHistoryUnchanged(t *testing.T) { + entries := make([]struct { + version string + state configv1.UpdateState + }, maxHistory) + for i := 0; i < maxHistory; i++ { + entries[i] = struct { + version string + state configv1.UpdateState + }{ + version: fmt.Sprintf("4.17.%d", 99-i), + state: configv1.CompletedUpdate, + } + } + history := makeHistory(entries) + + pruned := pruneHistory(history) + + if len(pruned) != maxHistory { + t.Errorf("When exactly %d entries exist, it should not prune, got %d entries", maxHistory, len(pruned)) + } +} + +// TestPruneHistory_CapAtMaxHistory verifies that when more than maxHistory entries +// exist, pruning reduces the list to exactly maxHistory. +func TestPruneHistory_CapAtMaxHistory(t *testing.T) { + entries := make([]struct { + version string + state configv1.UpdateState + }, 105) + for i := 0; i < 105; i++ { + entries[i] = struct { + version string + state configv1.UpdateState + }{ + version: fmt.Sprintf("4.17.%d", 104-i), + state: configv1.CompletedUpdate, + } + } + history := makeHistory(entries) + + pruned := pruneHistory(history) + + if len(pruned) != maxHistory { + t.Errorf("When more than maxHistory entries exist, it should prune to %d, got %d", maxHistory, len(pruned)) + } +} + +// TestPruneHistory_DeterministicResults verifies that the pruning algorithm +// produces deterministic results when called multiple times with the same input. +func TestPruneHistory_DeterministicResults(t *testing.T) { + entries := make([]struct { + version string + state configv1.UpdateState + }, 105) + for i := 0; i < 105; i++ { + entries[i] = struct { + version string + state configv1.UpdateState + }{ + version: fmt.Sprintf("4.17.%d", 104-i), + state: configv1.CompletedUpdate, + } + } + history := makeHistory(entries) + + pruned1 := pruneHistory(history) + pruned2 := pruneHistory(makeHistory(entries)) + + if len(pruned1) != len(pruned2) { + t.Fatalf("When pruning the same input twice, it should produce same length, got %d vs %d", + len(pruned1), len(pruned2)) + } + for i := range pruned1 { + if pruned1[i].Version != pruned2[i].Version { + t.Errorf("When pruning the same input twice, it should produce deterministic results at index %d: %s vs %s", + i, pruned1[i].Version, pruned2[i].Version) + } + } +} diff --git a/control-plane-operator/controllers/hostedcontrolplane/controlplaneversion_test.go b/control-plane-operator/controllers/hostedcontrolplane/controlplaneversion_test.go new file mode 100644 index 000000000000..3a2c8c28a5fe --- /dev/null +++ b/control-plane-operator/controllers/hostedcontrolplane/controlplaneversion_test.go @@ -0,0 +1,502 @@ +package hostedcontrolplane + +import ( + "testing" + "time" + + hyperv1 "github.com/openshift/hypershift/api/hypershift/v1beta1" + + configv1 "github.com/openshift/api/config/v1" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/clock" + testingclock "k8s.io/utils/clock/testing" +) + +// newHCP creates a minimal HostedControlPlane for testing. +func newHCP(releaseImage string, controlPlaneReleaseImage *string, generation int64) *hyperv1.HostedControlPlane { + hcp := &hyperv1.HostedControlPlane{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-hcp", + Namespace: "test-ns", + Generation: generation, + }, + Spec: hyperv1.HostedControlPlaneSpec{ + ReleaseImage: releaseImage, + }, + } + if controlPlaneReleaseImage != nil { + hcp.Spec.ControlPlaneReleaseImage = controlPlaneReleaseImage + } + return hcp +} + +// newComponent creates a ControlPlaneComponent with the given version and rollout status. +func newComponent(name, version string, rolloutComplete bool) hyperv1.ControlPlaneComponent { + conditions := []metav1.Condition{ + { + Type: string(hyperv1.ControlPlaneComponentAvailable), + Status: metav1.ConditionTrue, + LastTransitionTime: metav1.Now(), + }, + } + if rolloutComplete { + conditions = append(conditions, metav1.Condition{ + Type: string(hyperv1.ControlPlaneComponentRolloutComplete), + Status: metav1.ConditionTrue, + LastTransitionTime: metav1.Now(), + }) + } else { + conditions = append(conditions, metav1.Condition{ + Type: string(hyperv1.ControlPlaneComponentRolloutComplete), + Status: metav1.ConditionFalse, + LastTransitionTime: metav1.Now(), + }) + } + return hyperv1.ControlPlaneComponent{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: "test-ns", + }, + Status: hyperv1.ControlPlaneComponentStatus{ + Version: version, + Conditions: conditions, + }, + } +} + +func strPtr(s string) *string { return &s } + +// TestReconcileControlPlaneVersion_AllComponentsComplete verifies that +// When all ControlPlaneComponent resources report the target version with +// RolloutComplete=True, controlPlaneVersion.history[0].State transitions +// to Completed and completionTime is set. +func TestReconcileControlPlaneVersion_AllComponentsComplete(t *testing.T) { + fakeClock := testingclock.NewFakeClock(time.Date(2026, 3, 6, 12, 0, 0, 0, time.UTC)) + hcp := newHCP("quay.io/ocp/release@sha256:aaa", nil, 1) + hcp.Status.ControlPlaneVersion = hyperv1.ControlPlaneVersionStatus{ + Desired: configv1.Release{ + Version: "4.17.0", + Image: "quay.io/ocp/release@sha256:aaa", + }, + History: []hyperv1.ControlPlaneUpdateHistory{ + { + State: configv1.PartialUpdate, + StartedTime: metav1.NewTime(fakeClock.Now().Add(-10 * time.Minute)), + Version: "4.17.0", + Image: "quay.io/ocp/release@sha256:aaa", + }, + }, + ObservedGeneration: 1, + } + + components := []hyperv1.ControlPlaneComponent{ + newComponent("kube-apiserver", "4.17.0", true), + newComponent("kube-controller-manager", "4.17.0", true), + newComponent("openshift-apiserver", "4.17.0", true), + } + + result := reconcileControlPlaneVersion(hcp, components, fakeClock, "4.17.0", hcp.Spec.ReleaseImage) + + if result.History[0].State != configv1.CompletedUpdate { + t.Errorf("When all components are complete, it should transition to Completed, got %s", result.History[0].State) + } + if result.History[0].CompletionTime.IsZero() { + t.Error("When all components are complete, it should set completionTime") + } + if result.History[0].Version != "4.17.0" { + t.Errorf("When all components are complete, version should be 4.17.0, got %s", result.History[0].Version) + } + if result.History[0].Image != hcp.Spec.ReleaseImage { + t.Errorf("When all components are complete, image should be %s, got %s", hcp.Spec.ReleaseImage, result.History[0].Image) + } +} + +// TestReconcileControlPlaneVersion_NewDesiredRelease verifies that +// When the desired release changes (version bump), a new Partial history entry is prepended. +func TestReconcileControlPlaneVersion_NewDesiredRelease(t *testing.T) { + fakeClock := testingclock.NewFakeClock(time.Date(2026, 3, 6, 12, 0, 0, 0, time.UTC)) + hcp := newHCP("quay.io/ocp/release@sha256:bbb", nil, 2) + hcp.Status.ControlPlaneVersion = hyperv1.ControlPlaneVersionStatus{ + Desired: configv1.Release{ + Version: "4.17.0", + Image: "quay.io/ocp/release@sha256:aaa", + }, + History: []hyperv1.ControlPlaneUpdateHistory{ + { + State: configv1.CompletedUpdate, + StartedTime: metav1.NewTime(fakeClock.Now().Add(-1 * time.Hour)), + CompletionTime: metav1.NewTime(fakeClock.Now().Add(-30 * time.Minute)), + Version: "4.17.0", + Image: "quay.io/ocp/release@sha256:aaa", + }, + }, + ObservedGeneration: 1, + } + + // Components still report old version — they haven't rolled yet + components := []hyperv1.ControlPlaneComponent{ + newComponent("kube-apiserver", "4.17.0", true), + } + + result := reconcileControlPlaneVersion(hcp, components, fakeClock, "4.17.0", hcp.Spec.ReleaseImage) + + if len(result.History) < 2 { + t.Fatalf("When desired release changes, it should prepend new entry, got %d entries", len(result.History)) + } + if result.History[0].State != configv1.PartialUpdate { + t.Errorf("When desired release changes, it should prepend Partial entry, got %s", result.History[0].State) + } + if result.History[0].Image != "quay.io/ocp/release@sha256:bbb" { + t.Errorf("When desired release changes, it should use new image, got %s", result.History[0].Image) + } + // Version comes from aggregateComponentVersion which reports what components currently run + if result.History[0].Version != "4.17.0" { + t.Errorf("When desired release changes but components haven't rolled, it should record current version, got %s", result.History[0].Version) + } +} + +// TestReconcileControlPlaneVersion_ImageOnlyChange verifies that +// When the image digest changes but the semver is the same, a new Partial +// entry is prepended (CVE patch scenario). +func TestReconcileControlPlaneVersion_ImageOnlyChange(t *testing.T) { + fakeClock := testingclock.NewFakeClock(time.Date(2026, 3, 6, 12, 0, 0, 0, time.UTC)) + hcp := newHCP("quay.io/ocp/release@sha256:bbb", nil, 2) + hcp.Status.ControlPlaneVersion = hyperv1.ControlPlaneVersionStatus{ + Desired: configv1.Release{ + Version: "4.17.0", + Image: "quay.io/ocp/release@sha256:aaa", + }, + History: []hyperv1.ControlPlaneUpdateHistory{ + { + State: configv1.CompletedUpdate, + StartedTime: metav1.NewTime(fakeClock.Now().Add(-1 * time.Hour)), + CompletionTime: metav1.NewTime(fakeClock.Now().Add(-30 * time.Minute)), + Version: "4.17.0", + Image: "quay.io/ocp/release@sha256:aaa", + }, + }, + ObservedGeneration: 1, + } + + components := []hyperv1.ControlPlaneComponent{ + newComponent("kube-apiserver", "4.17.0", true), + } + + result := reconcileControlPlaneVersion(hcp, components, fakeClock, "4.17.0", hcp.Spec.ReleaseImage) + + if len(result.History) < 2 { + t.Fatalf("When image changes (same version), it should prepend new entry, got %d entries", len(result.History)) + } + if result.History[0].State != configv1.PartialUpdate { + t.Errorf("When image changes (same version), it should prepend Partial entry, got %s", result.History[0].State) + } + if result.History[0].Image != "quay.io/ocp/release@sha256:bbb" { + t.Errorf("When image changes (same version), it should use new image, got %s", result.History[0].Image) + } + if result.History[0].Version != "4.17.0" { + t.Errorf("When image changes (same version), version should remain 4.17.0, got %s", result.History[0].Version) + } +} + +// TestReconcileControlPlaneVersion_NewComponentMidUpgrade verifies that +// When a new ControlPlaneComponent is created mid-upgrade that hasn't reached +// the desired version, controlPlaneVersion remains Partial. +func TestReconcileControlPlaneVersion_NewComponentMidUpgrade(t *testing.T) { + fakeClock := testingclock.NewFakeClock(time.Date(2026, 3, 6, 12, 0, 0, 0, time.UTC)) + hcp := newHCP("quay.io/ocp/release@sha256:aaa", nil, 1) + hcp.Status.ControlPlaneVersion = hyperv1.ControlPlaneVersionStatus{ + Desired: configv1.Release{ + Version: "4.17.0", + Image: "quay.io/ocp/release@sha256:aaa", + }, + History: []hyperv1.ControlPlaneUpdateHistory{ + { + State: configv1.PartialUpdate, + StartedTime: metav1.NewTime(fakeClock.Now().Add(-5 * time.Minute)), + Version: "4.17.0", + Image: "quay.io/ocp/release@sha256:aaa", + }, + }, + ObservedGeneration: 1, + } + + components := []hyperv1.ControlPlaneComponent{ + newComponent("kube-apiserver", "4.17.0", true), + newComponent("kube-controller-manager", "4.17.0", true), + newComponent("new-component", "4.16.0", false), // mid-upgrade, not at desired version + } + + result := reconcileControlPlaneVersion(hcp, components, fakeClock, "4.17.0", hcp.Spec.ReleaseImage) + + if result.History[0].State != configv1.PartialUpdate { + t.Errorf("When a component mid-upgrade hasn't reached desired version, it should remain Partial, got %s", result.History[0].State) + } + if !result.History[0].CompletionTime.IsZero() { + t.Error("When a component mid-upgrade hasn't reached desired version, it should not set completionTime") + } + if result.History[0].Version != "4.17.0" { + t.Errorf("When a component mid-upgrade hasn't reached desired version, history version should remain 4.17.0, got %s", result.History[0].Version) + } +} + +// TestReconcileControlPlaneVersion_FirstPopulation verifies that +// When controlPlaneVersion is first populated on an existing cluster with all +// components at the desired version, history initializes with Partial on the +// first reconciliation, then transitions to Completed on the second. +func TestReconcileControlPlaneVersion_FirstPopulation(t *testing.T) { + fakeClock := testingclock.NewFakeClock(time.Date(2026, 3, 6, 12, 0, 0, 0, time.UTC)) + hcp := newHCP("quay.io/ocp/release@sha256:aaa", nil, 1) + // No existing ControlPlaneVersion status (first population) + + components := []hyperv1.ControlPlaneComponent{ + newComponent("kube-apiserver", "4.17.0", true), + newComponent("kube-controller-manager", "4.17.0", true), + } + + // First reconciliation: should create Partial entry + result := reconcileControlPlaneVersion(hcp, components, fakeClock, "4.17.0", hcp.Spec.ReleaseImage) + + if len(result.History) != 1 { + t.Fatalf("When first populated, it should create 1 history entry, got %d", len(result.History)) + } + if result.History[0].State != configv1.PartialUpdate { + t.Errorf("When first populated, it should initialize with Partial, got %s", result.History[0].State) + } + if result.History[0].Version != "4.17.0" { + t.Errorf("When first populated, version should be 4.17.0, got %s", result.History[0].Version) + } + if result.History[0].Image != hcp.Spec.ReleaseImage { + t.Errorf("When first populated, image should be %s, got %s", hcp.Spec.ReleaseImage, result.History[0].Image) + } + + // Second reconciliation: should transition to Completed + hcp.Status.ControlPlaneVersion = result + fakeClock.Step(1 * time.Minute) + result2 := reconcileControlPlaneVersion(hcp, components, fakeClock, "4.17.0", hcp.Spec.ReleaseImage) + + if result2.History[0].State != configv1.CompletedUpdate { + t.Errorf("When first populated and all components ready, second reconcile should transition to Completed, got %s", result2.History[0].State) + } + if result2.History[0].CompletionTime.IsZero() { + t.Error("When first populated and all components ready, second reconcile should set completionTime") + } +} + +// TestReconcileControlPlaneVersion_ControlPlaneReleaseImage verifies that +// When HCP.Spec.ControlPlaneReleaseImage is set, controlPlaneVersion.desired +// reflects ControlPlaneReleaseImage, not Spec.ReleaseImage. +func TestReconcileControlPlaneVersion_ControlPlaneReleaseImage(t *testing.T) { + fakeClock := testingclock.NewFakeClock(time.Date(2026, 3, 6, 12, 0, 0, 0, time.UTC)) + cpReleaseImage := "quay.io/ocp/release@sha256:cponly" + hcp := newHCP("quay.io/ocp/release@sha256:dataplane", strPtr(cpReleaseImage), 1) + + components := []hyperv1.ControlPlaneComponent{ + newComponent("kube-apiserver", "4.17.0", true), + } + + // The caller resolves the image — when ControlPlaneReleaseImage is set, + // the caller passes its resolved digest as desiredImage. + result := reconcileControlPlaneVersion(hcp, components, fakeClock, "4.17.0", cpReleaseImage) + + if result.Desired.Image != cpReleaseImage { + t.Errorf("When ControlPlaneReleaseImage is set, it should use it as desired, got %s", result.Desired.Image) + } +} + +// TestReconcileControlPlaneVersion_ObservedGeneration verifies that +// When the CPO reconciles successfully, observedGeneration reflects the +// generation that was actually processed. +func TestReconcileControlPlaneVersion_ObservedGeneration(t *testing.T) { + fakeClock := testingclock.NewFakeClock(time.Date(2026, 3, 6, 12, 0, 0, 0, time.UTC)) + hcp := newHCP("quay.io/ocp/release@sha256:aaa", nil, 7) + + components := []hyperv1.ControlPlaneComponent{ + newComponent("kube-apiserver", "4.17.0", true), + } + + result := reconcileControlPlaneVersion(hcp, components, fakeClock, "4.17.0", hcp.Spec.ReleaseImage) + + if result.ObservedGeneration != 7 { + t.Errorf("When reconciliation succeeds, it should set observedGeneration to current generation (7), got %d", result.ObservedGeneration) + } +} + +// TestReconcileControlPlaneVersion_ComponentFailure verifies that +// when a component is at the desired version but its rollout has not completed +// (e.g. deployment updated but pods crashing), controlPlaneVersion stays Partial. +func TestReconcileControlPlaneVersion_ComponentFailure(t *testing.T) { + fakeClock := testingclock.NewFakeClock(time.Date(2026, 3, 6, 12, 0, 0, 0, time.UTC)) + hcp := newHCP("quay.io/ocp/release@sha256:aaa", nil, 1) + hcp.Status.ControlPlaneVersion = hyperv1.ControlPlaneVersionStatus{ + Desired: configv1.Release{ + Version: "4.17.0", + Image: "quay.io/ocp/release@sha256:aaa", + }, + History: []hyperv1.ControlPlaneUpdateHistory{ + { + State: configv1.PartialUpdate, + StartedTime: metav1.NewTime(fakeClock.Now().Add(-5 * time.Minute)), + Version: "4.17.0", + Image: "quay.io/ocp/release@sha256:aaa", + }, + }, + ObservedGeneration: 1, + } + + components := []hyperv1.ControlPlaneComponent{ + newComponent("kube-apiserver", "4.17.0", true), + newComponent("kube-controller-manager", "4.17.0", false), // at desired version but rollout not complete + } + + result := reconcileControlPlaneVersion(hcp, components, fakeClock, "4.17.0", hcp.Spec.ReleaseImage) + + if result.History[0].State != configv1.PartialUpdate { + t.Errorf("When a component fails, it should maintain Partial state, got %s", result.History[0].State) + } + if !result.History[0].CompletionTime.IsZero() { + t.Error("When a component fails, it should not set completionTime") + } + if result.History[0].Version != "4.17.0" { + t.Errorf("When a component fails, history version should remain 4.17.0, got %s", result.History[0].Version) + } +} + +// TestReconcileControlPlaneVersion_SupersededPartial verifies that +// When controlPlaneVersion is Partial for version X and a new desired release +// Y is detected, the Partial entry for X receives a CompletionTime stamp +// before Y's entry is prepended. +func TestReconcileControlPlaneVersion_SupersededPartial(t *testing.T) { + fakeClock := testingclock.NewFakeClock(time.Date(2026, 3, 6, 12, 0, 0, 0, time.UTC)) + hcp := newHCP("quay.io/ocp/release@sha256:bbb", nil, 2) + startTime := metav1.NewTime(fakeClock.Now().Add(-10 * time.Minute)) + hcp.Status.ControlPlaneVersion = hyperv1.ControlPlaneVersionStatus{ + Desired: configv1.Release{ + Version: "4.17.0", + Image: "quay.io/ocp/release@sha256:aaa", + }, + History: []hyperv1.ControlPlaneUpdateHistory{ + { + State: configv1.PartialUpdate, + StartedTime: startTime, + Version: "4.17.0", + Image: "quay.io/ocp/release@sha256:aaa", + }, + }, + ObservedGeneration: 1, + } + + components := []hyperv1.ControlPlaneComponent{ + newComponent("kube-apiserver", "4.17.0", false), + } + + result := reconcileControlPlaneVersion(hcp, components, fakeClock, "4.17.0", hcp.Spec.ReleaseImage) + + if len(result.History) < 2 { + t.Fatalf("When superseding a Partial entry, it should prepend new entry, got %d entries", len(result.History)) + } + // New entry at [0] + if result.History[0].State != configv1.PartialUpdate { + t.Errorf("When superseding, it should prepend new Partial entry, got %s", result.History[0].State) + } + if result.History[0].Image != "quay.io/ocp/release@sha256:bbb" { + t.Errorf("When superseding, it should use new image for prepended entry, got %s", result.History[0].Image) + } + // Superseded entry at [1] should have CompletionTime stamped + if result.History[1].CompletionTime.IsZero() { + t.Error("When superseding a Partial entry, it should stamp CompletionTime on the old entry") + } + if result.History[1].State != configv1.PartialUpdate { + t.Errorf("When superseding, the old entry should remain Partial (not switch to Completed), got %s", result.History[1].State) + } +} + +// TestReconcileControlPlaneVersion_NoComponents verifies behavior when no +// ControlPlaneComponent resources exist yet — should create initial Partial entry. +func TestReconcileControlPlaneVersion_NoComponents(t *testing.T) { + fakeClock := testingclock.NewFakeClock(time.Date(2026, 3, 6, 12, 0, 0, 0, time.UTC)) + hcp := newHCP("quay.io/ocp/release@sha256:aaa", nil, 1) + + var components []hyperv1.ControlPlaneComponent + + result := reconcileControlPlaneVersion(hcp, components, fakeClock, "4.17.0", hcp.Spec.ReleaseImage) + + if result.Desired.Image == "" { + t.Fatal("When no components exist, it should still return a status with desired set") + } + if len(result.History) != 1 { + t.Fatalf("When no components exist, it should create initial Partial entry, got %d entries", len(result.History)) + } + if result.History[0].State != configv1.PartialUpdate { + t.Errorf("When no components exist, it should create Partial entry, got %s", result.History[0].State) + } + if result.History[0].Version != "4.17.0" { + t.Errorf("When no components exist, version should be 4.17.0, got %s", result.History[0].Version) + } + if result.History[0].Image != hcp.Spec.ReleaseImage { + t.Errorf("When no components exist, image should be %s, got %s", hcp.Spec.ReleaseImage, result.History[0].Image) + } +} + +func TestAllComponentsAtVersion(t *testing.T) { + tests := []struct { + name string + components []hyperv1.ControlPlaneComponent + desiredVersion string + want bool + }{ + { + name: "When no components exist, it should return false", + components: nil, + desiredVersion: "4.17.0", + want: false, + }, + { + name: "When all components match version and have RolloutComplete, it should return true", + components: []hyperv1.ControlPlaneComponent{ + newComponent("kube-apiserver", "4.17.0", true), + newComponent("kube-controller-manager", "4.17.0", true), + }, + desiredVersion: "4.17.0", + want: true, + }, + { + name: "When a component has a version mismatch, it should return false", + components: []hyperv1.ControlPlaneComponent{ + newComponent("kube-apiserver", "4.17.0", true), + newComponent("kube-controller-manager", "4.16.0", true), + }, + desiredVersion: "4.17.0", + want: false, + }, + { + name: "When a component has RolloutComplete=False but version matches, it should return false", + components: []hyperv1.ControlPlaneComponent{ + newComponent("kube-apiserver", "4.17.0", true), + newComponent("kube-controller-manager", "4.17.0", false), + }, + desiredVersion: "4.17.0", + want: false, + }, + { + name: "When a component has empty version, it should return false", + components: []hyperv1.ControlPlaneComponent{ + newComponent("kube-apiserver", "4.17.0", true), + newComponent("kube-controller-manager", "", true), + }, + desiredVersion: "4.17.0", + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := allComponentsAtVersion(tt.components, tt.desiredVersion) + if got != tt.want { + t.Errorf("allComponentsAtVersion() = %v, want %v", got, tt.want) + } + }) + } +} + +// Ensure the clock.Clock interface is used for testability. +var _ clock.Clock = &testingclock.FakeClock{} diff --git a/control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go b/control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go index 37a0d8598b05..1482cd2d4bac 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go +++ b/control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go @@ -113,6 +113,7 @@ import ( "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/util/workqueue" + "k8s.io/utils/clock" "k8s.io/utils/ptr" ctrl "sigs.k8s.io/controller-runtime" @@ -181,9 +182,13 @@ type HostedControlPlaneReconciler struct { ImageMetadataProvider util.ImageMetadataProvider cpoAzureCredentialsLoaded sync.Map kmsAzureCredentialsLoaded sync.Map + clock clock.Clock } func (r *HostedControlPlaneReconciler) SetupWithManager(mgr ctrl.Manager, createOrUpdate upsert.CreateOrUpdateFN, hcp *hyperv1.HostedControlPlane) error { + if r.clock == nil { + r.clock = clock.RealClock{} + } r.setup(createOrUpdate) b := ctrl.NewControllerManagedBy(mgr). For(&hyperv1.HostedControlPlane{}). @@ -793,6 +798,40 @@ func (r *HostedControlPlaneReconciler) Reconcile(ctx context.Context, req ctrl.R return reconcile.Result{}, fmt.Errorf("failed to look up release image metadata: %w", err) } + // Reconcile controlPlaneVersion status. + // This runs after LookupReleaseImage so we can use the version and resolved + // digest from the release image metadata. + { + clk := r.clock + if clk == nil { + clk = clock.RealClock{} + } + // Resolve the release image to its digest so controlPlaneVersion records + // the immutable image reference, consistent with how CVO records images. + pullSecret := common.PullSecret(hostedControlPlane.Namespace) + if err := r.Client.Get(ctx, client.ObjectKeyFromObject(pullSecret), pullSecret); err != nil { + return reconcile.Result{}, fmt.Errorf("failed to get pull secret for version reconciliation: %w", err) + } + _, resolvedRef, err := r.ImageMetadataProvider.GetDigest(ctx, util.HCPControlPlaneReleaseImage(hostedControlPlane), pullSecret.Data[corev1.DockerConfigJsonKey]) + if err != nil { + return reconcile.Result{}, fmt.Errorf("failed to resolve control plane release image digest: %w", err) + } + resolvedImage := resolvedRef.String() + + componentsList := &hyperv1.ControlPlaneComponentList{} + if listErr := r.Client.List(ctx, componentsList, client.InNamespace(hostedControlPlane.Namespace)); listErr != nil { + // On list failure, ensure a Partial entry exists so consumers + // know an upgrade was attempted. Preserve observedGeneration. + hostedControlPlane.Status.ControlPlaneVersion = ensureControlPlaneVersionPartial(hostedControlPlane, clk, releaseImage.Version(), resolvedImage) + // Persist the Partial entry before returning the error. + if patchErr := r.Client.Status().Patch(ctx, hostedControlPlane, client.MergeFromWithOptions(originalHostedControlPlane, client.MergeFromWithOptimisticLock{})); patchErr != nil { + return reconcile.Result{}, fmt.Errorf("failed to patch status after component list failure: %w (list error: %v)", patchErr, listErr) + } + return reconcile.Result{}, fmt.Errorf("failed to list control plane components for version reconciliation: %w", listErr) + } + hostedControlPlane.Status.ControlPlaneVersion = reconcileControlPlaneVersion(hostedControlPlane, componentsList.Items, clk, releaseImage.Version(), resolvedImage) + } + hostedControlPlane.Status.Initialized = true meta.SetStatusCondition(&hostedControlPlane.Status.Conditions, util.GenerateReconciliationActiveCondition(hostedControlPlane.Spec.PausedUntil, hostedControlPlane.Generation)) diff --git a/control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller_test.go b/control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller_test.go index 7a91428d5256..caba095e9daa 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller_test.go +++ b/control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller_test.go @@ -722,6 +722,7 @@ func TestEventHandling(t *testing.T) { ManagementClusterCapabilities: &fakecapabilities.FakeSupportAllCapabilities{}, ReleaseProvider: mockedProviderWithOpenshiftImageRegistryOverrides, UserReleaseProvider: &fakereleaseprovider.FakeReleaseProvider{}, + ImageMetadataProvider: &fakeimagemetadataprovider.FakeRegistryClientImageMetadataProviderHCCO{}, reconcileInfrastructureStatus: func(context.Context, *hyperv1.HostedControlPlane) (infra.InfrastructureStatus, error) { return readyInfraStatus, nil }, @@ -803,6 +804,7 @@ func TestNonReadyInfraTriggersRequeueAfter(t *testing.T) { ManagementClusterCapabilities: &fakecapabilities.FakeSupportAllCapabilities{}, ReleaseProvider: mockedProviderWithOpenshiftImageRegistryOverrides, UserReleaseProvider: &fakereleaseprovider.FakeReleaseProvider{}, + ImageMetadataProvider: &fakeimagemetadataprovider.FakeRegistryClientImageMetadataProviderHCCO{}, reconcileInfrastructureStatus: func(context.Context, *hyperv1.HostedControlPlane) (infra.InfrastructureStatus, error) { return infra.InfrastructureStatus{}, nil }, diff --git a/docs/content/reference/api.md b/docs/content/reference/api.md index 6d6652cdff5b..3e6739901d03 100644 --- a/docs/content/reference/api.md +++ b/docs/content/reference/api.md @@ -5170,6 +5170,156 @@ ManagedIdentity +###ControlPlaneUpdateHistory { #hypershift.openshift.io/v1beta1.ControlPlaneUpdateHistory } +

+(Appears on: +ControlPlaneVersionStatus) +

+

+

ControlPlaneUpdateHistory is a record of a single version transition for management-side +control plane components. Each entry captures the target version, its release image, when +the rollout started, and when (or whether) it completed.

+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+state
+ + +github.com/openshift/api/config/v1.UpdateState + + +
+

state reflects whether the update was fully applied. The Partial state +indicates the update is not fully applied, while the Completed state +indicates the update was successfully rolled out.

+
+startedTime,omitempty,omitzero
+ + +Kubernetes meta/v1.Time + + +
+

startedTime is the time at which the update was started.

+
+completionTime,omitempty,omitzero
+ + +Kubernetes meta/v1.Time + + +
+(Optional) +

completionTime is the time at which the update completed. It is set +when all management-side components have reached the target version. +It is not set while the update is in progress.

+
+version
+ +string + +
+

version is a semantic version string identifying the update version +(e.g. “4.20.1”).

+
+image
+ +string + +
+

image is the release image pullspec used for this update.

+
+###ControlPlaneVersionStatus { #hypershift.openshift.io/v1beta1.ControlPlaneVersionStatus } +

+(Appears on: +HostedClusterStatus, +HostedControlPlaneStatus) +

+

+

ControlPlaneVersionStatus tracks the rollout state of management-side control plane components. +It records the desired release, a pruned history of version transitions (newest first), and +the last observed generation of the HostedControlPlane spec.

+

+ + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+desired,omitempty,omitzero
+ + +github.com/openshift/api/config/v1.Release + + +
+

desired is the release version that the control plane is reconciling towards. +It is derived from the HostedControlPlane release image fields.

+
+history
+ + +[]ControlPlaneUpdateHistory + + +
+(Optional) +

history contains a list of versions applied to management-side control plane components. The newest entry is +first in the list. Entries have state Completed when all ControlPlaneComponent resources report the target +version with RolloutComplete=True. Entries have state Partial when the rollout is in progress or has failed.

+
+observedGeneration,omitempty,omitzero
+ +int64 + +
+(Optional) +

observedGeneration reports which generation of the HostedControlPlane spec is being synced.

+
###DNSSpec { #hypershift.openshift.io/v1beta1.DNSSpec }

(Appears on: @@ -6216,6 +6366,22 @@ plane’s current state.

+controlPlaneVersion,omitzero
+ + +ControlPlaneVersionStatus + + + + +(Optional) +

controlPlaneVersion tracks the rollout status of the control plane +components running on the management cluster, independently from +the data-plane version reported in the version field.

+ + + + version
@@ -6957,6 +7123,22 @@ This is populated after the infrastructure is ready.

+controlPlaneVersion,omitzero
+ +
+ControlPlaneVersionStatus + + + + +(Optional) +

controlPlaneVersion tracks the rollout status of the control plane +components running on the management cluster, independently from +the data-plane version reported in the version field.

+ + + + versionStatus
diff --git a/hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go b/hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go index 78ac9c396eee..f41d3372341c 100644 --- a/hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go +++ b/hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go @@ -853,6 +853,9 @@ func (r *HostedClusterReconciler) reconcile(ctx context.Context, req ctrl.Reques hcluster.Status.Platform = hcp.Status.Platform } + // Copy the control plane version status from the hostedcontrolplane + propagateControlPlaneVersion(hcluster, hcp) + // Copy the AWSDefaultSecurityGroupCreated condition from the hostedcontrolplane if hcluster.Spec.Platform.Type == hyperv1.AWSPlatform { if hcp != nil { @@ -4862,3 +4865,13 @@ func (r *HostedClusterReconciler) reconcileAdditionalTrustBundle(ctx context.Con return nil } + +// propagateControlPlaneVersion copies the ControlPlaneVersion status from the +// HostedControlPlane to the HostedCluster using DeepCopy for value safety. +// When HCP is nil (not yet created) the existing HC value is preserved. +func propagateControlPlaneVersion(hcluster *hyperv1.HostedCluster, hcp *hyperv1.HostedControlPlane) { + if hcp == nil { + return + } + hcluster.Status.ControlPlaneVersion = *hcp.Status.ControlPlaneVersion.DeepCopy() +} diff --git a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/controlplaneversion_types.go b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/controlplaneversion_types.go new file mode 100644 index 000000000000..14c0ed3fda94 --- /dev/null +++ b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/controlplaneversion_types.go @@ -0,0 +1,70 @@ +package v1beta1 + +import ( + configv1 "github.com/openshift/api/config/v1" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// ControlPlaneVersionStatus tracks the rollout state of management-side control plane components. +// It records the desired release, a pruned history of version transitions (newest first), and +// the last observed generation of the HostedControlPlane spec. +// +k8s:deepcopy-gen=true +type ControlPlaneVersionStatus struct { + // desired is the release version that the control plane is reconciling towards. + // It is derived from the HostedControlPlane release image fields. + // +required + Desired configv1.Release `json:"desired,omitempty,omitzero"` + + // history contains a list of versions applied to management-side control plane components. The newest entry is + // first in the list. Entries have state Completed when all ControlPlaneComponent resources report the target + // version with RolloutComplete=True. Entries have state Partial when the rollout is in progress or has failed. + // +optional + // +listType=atomic + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:MaxItems=100 + History []ControlPlaneUpdateHistory `json:"history,omitempty"` + + // observedGeneration reports which generation of the HostedControlPlane spec is being synced. + // +optional + // +kubebuilder:validation:Minimum=1 + // +kubebuilder:validation:Maximum=9007199254740992 + ObservedGeneration int64 `json:"observedGeneration,omitempty,omitzero"` +} + +// ControlPlaneUpdateHistory is a record of a single version transition for management-side +// control plane components. Each entry captures the target version, its release image, when +// the rollout started, and when (or whether) it completed. +// +k8s:deepcopy-gen=true +type ControlPlaneUpdateHistory struct { + // state reflects whether the update was fully applied. The Partial state + // indicates the update is not fully applied, while the Completed state + // indicates the update was successfully rolled out. + // +required + // +kubebuilder:validation:Enum=Completed;Partial + State configv1.UpdateState `json:"state"` + + // startedTime is the time at which the update was started. + // +required + StartedTime metav1.Time `json:"startedTime,omitempty,omitzero"` + + // completionTime is the time at which the update completed. It is set + // when all management-side components have reached the target version. + // It is not set while the update is in progress. + // +optional + CompletionTime metav1.Time `json:"completionTime,omitempty,omitzero"` + + // version is a semantic version string identifying the update version + // (e.g. "4.20.1"). + // +required + // +kubebuilder:validation:XValidation:rule=`self.matches('^\\d+\\.\\d+\\.\\d+.*')`,message="version must start with semantic version prefix x.y.z" + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=64 + Version string `json:"version"` + + // image is the release image pullspec used for this update. + // +required + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=447 + Image string `json:"image"` +} diff --git a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hosted_controlplane.go b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hosted_controlplane.go index b6236a0065c9..79af290bb4c9 100644 --- a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hosted_controlplane.go +++ b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hosted_controlplane.go @@ -349,6 +349,12 @@ type HostedControlPlaneStatus struct { // +kubebuilder:validation:MaxLength=255 OAuthCallbackURLTemplate string `json:"oauthCallbackURLTemplate,omitempty"` + // controlPlaneVersion tracks the rollout status of the control plane + // components running on the management cluster, independently from + // the data-plane version reported in the version field. + // +optional + ControlPlaneVersion ControlPlaneVersionStatus `json:"controlPlaneVersion,omitzero"` + // versionStatus is the status of the release version applied by the // hosted control plane operator. // +optional diff --git a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_types.go b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_types.go index dfaf052fd5f6..412823635aa3 100644 --- a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_types.go +++ b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_types.go @@ -1735,6 +1735,12 @@ type HostedClusterStatus struct { // +kubebuilder:validation:MaxItems=100 Conditions []metav1.Condition `json:"conditions,omitempty"` + // controlPlaneVersion tracks the rollout status of the control plane + // components running on the management cluster, independently from + // the data-plane version reported in the version field. + // +optional + ControlPlaneVersion ControlPlaneVersionStatus `json:"controlPlaneVersion,omitzero"` + // version is the status of the release version applied to the // HostedCluster. // +optional @@ -1947,11 +1953,14 @@ type OperatorConfiguration struct { // +kubebuilder:storageversion // +kubebuilder:subresource:status // +kubebuilder:printcolumn:name="Version",type="string",JSONPath=".status.version.history[?(@.state==\"Completed\")].version",description="Version" +// +kubebuilder:printcolumn:name="CP Version",type="string",JSONPath=".status.controlPlaneVersion.history[?(@.state==\"Completed\")].version",description="Control Plane Version" // +kubebuilder:printcolumn:name="KubeConfig",type="string",JSONPath=".status.kubeconfig.name",description="KubeConfig Secret" // +kubebuilder:printcolumn:name="Progress",type="string",JSONPath=".status.version.history[?(@.state!=\"\")].state",description="Progress" // +kubebuilder:printcolumn:name="Available",type="string",JSONPath=".status.conditions[?(@.type==\"Available\")].status",description="Available" // +kubebuilder:printcolumn:name="Progressing",type="string",JSONPath=".status.conditions[?(@.type==\"Progressing\")].status",description="Progressing" // +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.conditions[?(@.type==\"Available\")].message",description="Message" +// +kubebuilder:printcolumn:name="CP Progress",type="string",JSONPath=".status.controlPlaneVersion.history[0].state",description="Control Plane Progress",priority=1 +// +kubebuilder:printcolumn:name="DP Progress",type="string",JSONPath=".status.version.history[0].state",description="Data Plane Progress",priority=1 type HostedCluster struct { metav1.TypeMeta `json:",inline"` // metadata is the metadata for the HostedCluster. diff --git a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.deepcopy.go b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.deepcopy.go index 41a13b0ab84e..cd7523fac676 100644 --- a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.deepcopy.go +++ b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.deepcopy.go @@ -1290,6 +1290,46 @@ func (in *ControlPlaneManagedIdentities) DeepCopy() *ControlPlaneManagedIdentiti return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ControlPlaneUpdateHistory) DeepCopyInto(out *ControlPlaneUpdateHistory) { + *out = *in + in.StartedTime.DeepCopyInto(&out.StartedTime) + in.CompletionTime.DeepCopyInto(&out.CompletionTime) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControlPlaneUpdateHistory. +func (in *ControlPlaneUpdateHistory) DeepCopy() *ControlPlaneUpdateHistory { + if in == nil { + return nil + } + out := new(ControlPlaneUpdateHistory) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ControlPlaneVersionStatus) DeepCopyInto(out *ControlPlaneVersionStatus) { + *out = *in + in.Desired.DeepCopyInto(&out.Desired) + if in.History != nil { + in, out := &in.History, &out.History + *out = make([]ControlPlaneUpdateHistory, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControlPlaneVersionStatus. +func (in *ControlPlaneVersionStatus) DeepCopy() *ControlPlaneVersionStatus { + if in == nil { + return nil + } + out := new(ControlPlaneVersionStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DNSSpec) DeepCopyInto(out *DNSSpec) { *out = *in @@ -1618,6 +1658,7 @@ func (in *HostedClusterStatus) DeepCopyInto(out *HostedClusterStatus) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + in.ControlPlaneVersion.DeepCopyInto(&out.ControlPlaneVersion) if in.Version != nil { in, out := &in.Version, &out.Version *out = new(ClusterVersionStatus) @@ -1843,6 +1884,7 @@ func (in *HostedControlPlaneStatus) DeepCopyInto(out *HostedControlPlaneStatus) **out = **in } out.ControlPlaneEndpoint = in.ControlPlaneEndpoint + in.ControlPlaneVersion.DeepCopyInto(&out.ControlPlaneVersion) if in.VersionStatus != nil { in, out := &in.VersionStatus, &out.VersionStatus *out = new(ClusterVersionStatus) diff --git a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests.yaml b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests.yaml index 42f072849951..97df08a90653 100644 --- a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests.yaml +++ b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests.yaml @@ -115,6 +115,10 @@ hostedclusters.hypershift.openshift.io: jsonPath: .status.version.history[?(@.state=="Completed")].version name: Version type: string + - description: Control Plane Version + jsonPath: .status.controlPlaneVersion.history[?(@.state=="Completed")].version + name: CP Version + type: string - description: KubeConfig Secret jsonPath: .status.kubeconfig.name name: KubeConfig @@ -135,6 +139,16 @@ hostedclusters.hypershift.openshift.io: jsonPath: .status.conditions[?(@.type=="Available")].message name: Message type: string + - description: Control Plane Progress + jsonPath: .status.controlPlaneVersion.history[0].state + name: CP Progress + priority: 1 + type: string + - description: Data Plane Progress + jsonPath: .status.version.history[0].state + name: DP Progress + priority: 1 + type: string Scope: Namespaced ShortNames: - hc