Skip to content

Commit 62d68e1

Browse files
authored
feat: Implement CAPI v1beta1 compliant status handling and initial v1beta2 support for K0smotronControlPlane (#1090)
* feat: Set default empty string for K0smotronControlPlane status.version to comply with CAPI Set default value for status.version to empty string to comply with CAPI requirements. CAPI specification mandates that status.version must be an empty string (not null) until ControlPlane creation is complete. - Add kubebuilder:default annotation to Status field - Ensures CAPI compliance for status.version initialization Signed-off-by: kahirokunn <[email protected]> * feat: implement CAPI v1beta1 compliant control plane status handling - Add proper default values for status.ready and status.initialized - Implement API server ping-based availability checking - Set status fields only after successful control plane verification - Update cluster client naming for consistency Ensures compliance with Cluster API v1beta1 status contract requirements. Signed-off-by: kahirokunn <[email protected]> * feat: Add CAPI v1beta2 initialization.controlPlaneInitialized field Add initialization.controlPlaneInitialized field to K0sControlPlane and K0smotronControlPlane status for CAPI v1beta2 compatibility. - Add Initialization struct with controlPlaneInitialized field - Update status adapters to handle the new field - Set controlPlaneInitialized=true when API becomes available - Update CRD schemas with default values and field definitions Signed-off-by: kahirokunn <[email protected]> * feat: add Conditions support to K0smotronControlPlane and unify availability computation - Add Conditions field to K0smotronControlPlane to support v1beta2 semantics - Support both v1beta1 and v1beta2 specifications simultaneously - Update CRD definitions and deepcopy methods accordingly This change prepares for the 1-year coexistence period of v1beta1 and v1beta2, ensuring proper status management while maintaining backward compatibility. Signed-off-by: kahirokunn <[email protected]> * Fix cluster annotation persistence in K0smotronController to match K0sController The K0smotronController was creating a new cluster object in computeStatus instead of using the original one passed from Reconcile, causing annotations added in computeAvailability (specifically k0sproject.io/cluster-id) to be lost. This inconsistency with K0sController's correct implementation caused CI tests to loop indefinitely waiting for the annotation that would never be persisted. Changes: - Pass the original cluster object from Reconcile through to computeAvailability This aligns K0smotronController with the correct pattern already used in K0sController. Signed-off-by: kahirokunn <[email protected]> * test: Add e2e test for K0smotronControlPlane conditions This test verifies the ControlPlaneReadyCondition lifecycle: - Initially starts as False when cluster is created - Transitions to True when the control plane API is available - Validates the condition status and cluster ready state The test ensures the condition functionality works correctly in real cluster environments. Signed-off-by: kahirokunn <[email protected]> --------- Signed-off-by: kahirokunn <[email protected]>
1 parent 96b0846 commit 62d68e1

File tree

12 files changed

+553
-29
lines changed

12 files changed

+553
-29
lines changed

.github/workflows/go.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ jobs:
181181
matrix:
182182
e2e-suite:
183183
- controlplane-remediation
184+
- controlplane-conditions
184185
- workload-cluster-inplace-upgrade
185186
- workload-cluster-recreate-upgrade
186187
- admission-webhook-recreate-strategy-in-single-mode

api/controlplane/v1beta1/k0s_types.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ type K0sControlPlane struct {
7979

8080
Spec K0sControlPlaneSpec `json:"spec,omitempty"`
8181

82-
// +kubebuilder:default:={version:""}
82+
// +kubebuilder:default:={version:"",ready:false,initialized:false,initialization:{controlPlaneInitialized:false}}
8383
Status K0sControlPlaneStatus `json:"status,omitempty"`
8484
}
8585

@@ -149,6 +149,10 @@ type K0sControlPlaneStatus struct {
149149
// +optional
150150
Initialized bool `json:"initialized"`
151151

152+
// initialization represents the initialization status of the control plane
153+
// +optional
154+
Initialization Initialization `json:"initialization,omitempty"`
155+
152156
// externalManagedControlPlane is a bool that should be set to true if the Node objects do not exist in the cluster.
153157
// +optional
154158
ExternalManagedControlPlane bool `json:"externalManagedControlPlane"`

api/controlplane/v1beta1/k0smotron_types.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package v1beta1
1919
import (
2020
kmapi "github.com/k0sproject/k0smotron/api/k0smotron.io/v1beta1"
2121
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
22+
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
2223
)
2324

2425
const K0smotronControlPlaneFinalizer = "k0smotron.controlplane.cluster.x-k8s.io"
@@ -47,6 +48,7 @@ type K0smotronControlPlane struct {
4748
metav1.ObjectMeta `json:"metadata,omitempty"`
4849
Spec kmapi.ClusterSpec `json:"spec,omitempty"`
4950

51+
// +kubebuilder:default={version:"",ready:false,initialized:false,initialization:{controlPlaneInitialized:false},conditions: {{type: "ControlPlaneReady", status: "Unknown", reason:"ControlPlaneDoesNotExist", message:"Waiting for cluster topology to be reconciled", lastTransitionTime: "1970-01-01T00:00:00Z"}}}
5052
Status K0smotronControlPlaneStatus `json:"status,omitempty"`
5153
}
5254

@@ -58,6 +60,13 @@ type K0smotronControlPlaneList struct {
5860
Items []K0smotronControlPlane `json:"items"`
5961
}
6062

63+
// Initialization represents the initialization status of the control plane
64+
type Initialization struct {
65+
// controlPlaneInitialized indicates whether the control plane is initialized
66+
// +optional
67+
ControlPlaneInitialized bool `json:"controlPlaneInitialized"`
68+
}
69+
6170
type K0smotronControlPlaneStatus struct {
6271
// Ready denotes that the control plane is ready
6372
// +optional
@@ -69,6 +78,11 @@ type K0smotronControlPlaneStatus struct {
6978
// to check the operational state of the control plane.
7079
// +optional
7180
Initialized bool `json:"initialized"`
81+
82+
// initialization represents the initialization status of the control plane
83+
// +optional
84+
Initialization Initialization `json:"initialization,omitempty"`
85+
7286
// externalManagedControlPlane is a bool that should be set to true if the Node objects do not exist in the cluster.
7387
// +optional
7488
ExternalManagedControlPlane bool `json:"externalManagedControlPlane"`
@@ -93,4 +107,16 @@ type K0smotronControlPlaneStatus struct {
93107
UnavailableReplicas int32 `json:"unavailableReplicas"`
94108
// selector is the label selector for pods that should match the replicas count.
95109
Selector string `json:"selector,omitempty"`
110+
111+
// Conditions defines current service state of the K0smotronControlPlane.
112+
// +optional
113+
Conditions clusterv1.Conditions `json:"conditions,omitempty"`
114+
}
115+
116+
func (k *K0smotronControlPlane) GetConditions() clusterv1.Conditions {
117+
return k.Status.Conditions
118+
}
119+
120+
func (k *K0smotronControlPlane) SetConditions(conditions clusterv1.Conditions) {
121+
k.Status.Conditions = conditions
96122
}

api/controlplane/v1beta1/zz_generated.deepcopy.go

Lines changed: 25 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/clusterapi/controlplane/bases/controlplane.cluster.x-k8s.io_k0scontrolplanes.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,10 @@ spec:
362362
type: object
363363
status:
364364
default:
365+
initialization:
366+
controlPlaneInitialized: false
367+
initialized: false
368+
ready: false
365369
version: ""
366370
properties:
367371
conditions:
@@ -413,6 +417,15 @@ spec:
413417
description: externalManagedControlPlane is a bool that should be
414418
set to true if the Node objects do not exist in the cluster.
415419
type: boolean
420+
initialization:
421+
description: initialization represents the initialization status of
422+
the control plane
423+
properties:
424+
controlPlaneInitialized:
425+
description: controlPlaneInitialized indicates whether the control
426+
plane is initialized
427+
type: boolean
428+
type: object
416429
initialized:
417430
description: |-
418431
initialized denotes that the K0sControlPlane API Server is initialized and thus

config/clusterapi/controlplane/bases/controlplane.cluster.x-k8s.io_k0smotroncontrolplanes.yaml

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4587,11 +4587,77 @@ spec:
45874587
type: string
45884588
type: object
45894589
status:
4590+
default:
4591+
conditions:
4592+
- lastTransitionTime: "1970-01-01T00:00:00Z"
4593+
message: Waiting for cluster topology to be reconciled
4594+
reason: ControlPlaneDoesNotExist
4595+
status: Unknown
4596+
type: ControlPlaneReady
4597+
initialization:
4598+
controlPlaneInitialized: false
4599+
initialized: false
4600+
ready: false
4601+
version: ""
45904602
properties:
4603+
conditions:
4604+
description: Conditions defines current service state of the K0smotronControlPlane.
4605+
items:
4606+
description: Condition defines an observation of a Cluster API resource
4607+
operational state.
4608+
properties:
4609+
lastTransitionTime:
4610+
description: |-
4611+
Last time the condition transitioned from one status to another.
4612+
This should be when the underlying condition changed. If that is not known, then using the time when
4613+
the API field changed is acceptable.
4614+
format: date-time
4615+
type: string
4616+
message:
4617+
description: |-
4618+
A human readable message indicating details about the transition.
4619+
This field may be empty.
4620+
type: string
4621+
reason:
4622+
description: |-
4623+
The reason for the condition's last transition in CamelCase.
4624+
The specific API may choose whether or not this field is considered a guaranteed API.
4625+
This field may not be empty.
4626+
type: string
4627+
severity:
4628+
description: |-
4629+
Severity provides an explicit classification of Reason code, so the users or machines can immediately
4630+
understand the current situation and act accordingly.
4631+
The Severity field MUST be set only when Status=False.
4632+
type: string
4633+
status:
4634+
description: Status of the condition, one of True, False, Unknown.
4635+
type: string
4636+
type:
4637+
description: |-
4638+
Type of condition in CamelCase or in foo.example.com/CamelCase.
4639+
Many .condition.type values are consistent across resources like Available, but because arbitrary conditions
4640+
can be useful (see .node.status.conditions), the ability to deconflict is important.
4641+
type: string
4642+
required:
4643+
- lastTransitionTime
4644+
- status
4645+
- type
4646+
type: object
4647+
type: array
45914648
externalManagedControlPlane:
45924649
description: externalManagedControlPlane is a bool that should be
45934650
set to true if the Node objects do not exist in the cluster.
45944651
type: boolean
4652+
initialization:
4653+
description: initialization represents the initialization status of
4654+
the control plane
4655+
properties:
4656+
controlPlaneInitialized:
4657+
description: controlPlaneInitialized indicates whether the control
4658+
plane is initialized
4659+
type: boolean
4660+
type: object
45954661
initialized:
45964662
description: |-
45974663
initialized denotes that the K0smotronControlPlane API Server is initialized and thus

config/crd/bases/controlplane/controlplane.cluster.x-k8s.io_k0scontrolplanes.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,10 @@ spec:
362362
type: object
363363
status:
364364
default:
365+
initialization:
366+
controlPlaneInitialized: false
367+
initialized: false
368+
ready: false
365369
version: ""
366370
properties:
367371
conditions:
@@ -413,6 +417,15 @@ spec:
413417
description: externalManagedControlPlane is a bool that should be
414418
set to true if the Node objects do not exist in the cluster.
415419
type: boolean
420+
initialization:
421+
description: initialization represents the initialization status of
422+
the control plane
423+
properties:
424+
controlPlaneInitialized:
425+
description: controlPlaneInitialized indicates whether the control
426+
plane is initialized
427+
type: boolean
428+
type: object
416429
initialized:
417430
description: |-
418431
initialized denotes that the K0sControlPlane API Server is initialized and thus

config/crd/bases/controlplane/controlplane.cluster.x-k8s.io_k0smotroncontrolplanes.yaml

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4587,11 +4587,77 @@ spec:
45874587
type: string
45884588
type: object
45894589
status:
4590+
default:
4591+
conditions:
4592+
- lastTransitionTime: "1970-01-01T00:00:00Z"
4593+
message: Waiting for cluster topology to be reconciled
4594+
reason: ControlPlaneDoesNotExist
4595+
status: Unknown
4596+
type: ControlPlaneReady
4597+
initialization:
4598+
controlPlaneInitialized: false
4599+
initialized: false
4600+
ready: false
4601+
version: ""
45904602
properties:
4603+
conditions:
4604+
description: Conditions defines current service state of the K0smotronControlPlane.
4605+
items:
4606+
description: Condition defines an observation of a Cluster API resource
4607+
operational state.
4608+
properties:
4609+
lastTransitionTime:
4610+
description: |-
4611+
Last time the condition transitioned from one status to another.
4612+
This should be when the underlying condition changed. If that is not known, then using the time when
4613+
the API field changed is acceptable.
4614+
format: date-time
4615+
type: string
4616+
message:
4617+
description: |-
4618+
A human readable message indicating details about the transition.
4619+
This field may be empty.
4620+
type: string
4621+
reason:
4622+
description: |-
4623+
The reason for the condition's last transition in CamelCase.
4624+
The specific API may choose whether or not this field is considered a guaranteed API.
4625+
This field may not be empty.
4626+
type: string
4627+
severity:
4628+
description: |-
4629+
Severity provides an explicit classification of Reason code, so the users or machines can immediately
4630+
understand the current situation and act accordingly.
4631+
The Severity field MUST be set only when Status=False.
4632+
type: string
4633+
status:
4634+
description: Status of the condition, one of True, False, Unknown.
4635+
type: string
4636+
type:
4637+
description: |-
4638+
Type of condition in CamelCase or in foo.example.com/CamelCase.
4639+
Many .condition.type values are consistent across resources like Available, but because arbitrary conditions
4640+
can be useful (see .node.status.conditions), the ability to deconflict is important.
4641+
type: string
4642+
required:
4643+
- lastTransitionTime
4644+
- status
4645+
- type
4646+
type: object
4647+
type: array
45914648
externalManagedControlPlane:
45924649
description: externalManagedControlPlane is a bool that should be
45934650
set to true if the Node objects do not exist in the cluster.
45944651
type: boolean
4652+
initialization:
4653+
description: initialization represents the initialization status of
4654+
the control plane
4655+
properties:
4656+
controlPlaneInitialized:
4657+
description: controlPlaneInitialized indicates whether the control
4658+
plane is initialized
4659+
type: boolean
4660+
type: object
45954661
initialized:
45964662
description: |-
45974663
initialized denotes that the K0smotronControlPlane API Server is initialized and thus

0 commit comments

Comments
 (0)