Skip to content

Commit 567c392

Browse files
committed
Add field status.clusterSize and CEL rule for spec.replica transitions
1 parent 01b90bd commit 567c392

File tree

6 files changed

+51
-11
lines changed

6 files changed

+51
-11
lines changed

api/core/v1alpha1/conditions.go

+10
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,13 @@ type Condition struct {
4747
// A human-readable message indicating details about the transition.
4848
Message string `json:"message"`
4949
}
50+
51+
// HasConditionWithStatus checks if the Etcd has a condition of the specified type with the given status.
52+
func (e *Etcd) HasConditionWithStatus(condType ConditionType, status ConditionStatus) bool {
53+
for _, condition := range e.Status.Conditions {
54+
if condition.Type == condType && condition.Status == status {
55+
return true
56+
}
57+
}
58+
return false
59+
}

api/core/v1alpha1/crds/druid.gardener.cloud_etcds.yaml

+13-4
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,11 @@ spec:
3030
- jsonPath: .metadata.creationTimestamp
3131
name: Age
3232
type: date
33-
- jsonPath: .spec.replicas
33+
- jsonPath: .status.clusterSize
3434
name: Cluster Size
35+
type: integer
36+
- jsonPath: .spec.replicas
37+
name: Desired Replicas
3538
priority: 1
3639
type: integer
3740
- jsonPath: .status.currentReplicas
@@ -648,9 +651,6 @@ spec:
648651
replicas:
649652
format: int32
650653
type: integer
651-
x-kubernetes-validations:
652-
- message: Replicas can either be increased or be downscaled to 0.
653-
rule: 'self==0 ? true : self < oldSelf ? false : true'
654654
schedulingConstraints:
655655
description: |-
656656
SchedulingConstraints defines the different scheduling constraints that must be applied to the
@@ -1876,6 +1876,10 @@ spec:
18761876
status:
18771877
description: EtcdStatus defines the observed state of Etcd.
18781878
properties:
1879+
clusterSize:
1880+
description: ClusterSize is the last recorded etcd cluster size.
1881+
format: int32
1882+
type: integer
18791883
conditions:
18801884
description: Conditions represents the latest available observations
18811885
of an etcd's current state.
@@ -2101,6 +2105,11 @@ spec:
21012105
type: integer
21022106
type: object
21032107
type: object
2108+
x-kubernetes-validations:
2109+
- message: etcd.spec.replicas transition is not allowed.
2110+
rule: 'self.spec.replicas == 0 || (oldSelf.spec.replicas == 0 ? (!has(self.status.clusterSize)
2111+
|| (self.spec.replicas == self.status.clusterSize)) : (self.spec.replicas
2112+
>= oldSelf.spec.replicas))'
21042113
served: true
21052114
storage: true
21062115
subresources:

api/core/v1alpha1/crds/druid.gardener.cloud_etcds_without_cel.yaml

+8-1
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,11 @@ spec:
3030
- jsonPath: .metadata.creationTimestamp
3131
name: Age
3232
type: date
33-
- jsonPath: .spec.replicas
33+
- jsonPath: .status.clusterSize
3434
name: Cluster Size
35+
type: integer
36+
- jsonPath: .spec.replicas
37+
name: Desired Replicas
3538
priority: 1
3639
type: integer
3740
- jsonPath: .status.currentReplicas
@@ -1741,6 +1744,10 @@ spec:
17411744
status:
17421745
description: EtcdStatus defines the observed state of Etcd.
17431746
properties:
1747+
clusterSize:
1748+
description: ClusterSize is the last recorded etcd cluster size.
1749+
format: int32
1750+
type: integer
17441751
conditions:
17451752
description: Conditions represents the latest available observations of an etcd's current state.
17461753
items:

api/core/v1alpha1/etcd.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,13 @@ const (
4848
// +kubebuilder:printcolumn:name="All Members Ready",type=string,JSONPath=`.status.conditions[?(@.type=="AllMembersReady")].status`
4949
// +kubebuilder:printcolumn:name="Backup Ready",type=string,JSONPath=`.status.conditions[?(@.type=="BackupReady")].status`
5050
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
51-
// +kubebuilder:printcolumn:name="Cluster Size",type=integer,JSONPath=`.spec.replicas`,priority=1
51+
// +kubebuilder:printcolumn:name="Cluster Size",type=integer,JSONPath=`.status.clusterSize`
52+
// +kubebuilder:printcolumn:name="Desired Replicas",type=integer,JSONPath=`.spec.replicas`,priority=1
5253
// +kubebuilder:printcolumn:name="Current Replicas",type=integer,JSONPath=`.status.currentReplicas`,priority=1
5354
// +kubebuilder:printcolumn:name="Ready Replicas",type=integer,JSONPath=`.status.readyReplicas`,priority=1
5455

5556
// Etcd is the Schema for the etcds API
57+
// +kubebuilder:validation:XValidation:message="etcd.spec.replicas transition is not allowed.",rule="self.spec.replicas == 0 || (oldSelf.spec.replicas == 0 ? (!has(self.status.clusterSize) || (self.spec.replicas == self.status.clusterSize)) : (self.spec.replicas >= oldSelf.spec.replicas))"
5658
type Etcd struct {
5759
metav1.TypeMeta `json:",inline"`
5860
metav1.ObjectMeta `json:"metadata,omitempty"`
@@ -309,7 +311,6 @@ type EtcdSpec struct {
309311
// +optional
310312
SchedulingConstraints SchedulingConstraints `json:"schedulingConstraints,omitempty"`
311313
// +required
312-
// +kubebuilder:validation:XValidation:message="Replicas can either be increased or be downscaled to 0.",rule="self==0 ? true : self < oldSelf ? false : true"
313314
Replicas int32 `json:"replicas"`
314315
// PriorityClassName is the name of a priority class that shall be used for the etcd pods.
315316
// +optional
@@ -435,6 +436,9 @@ type EtcdStatus struct {
435436
// PeerUrlTLSEnabled captures the state of peer url TLS being enabled for the etcd member(s)
436437
// +optional
437438
PeerUrlTLSEnabled *bool `json:"peerUrlTLSEnabled,omitempty"`
439+
// ClusterSize is the last recorded etcd cluster size.
440+
// +optional
441+
ClusterSize int32 `json:"clusterSize"`
438442
}
439443

440444
// LastOperationType is a string alias representing type of the last operation.

docs/api-reference/etcd-druid-api.md

+1
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,7 @@ _Appears in:_
428428
| `labelSelector` _[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#labelselector-v1-meta)_ | LabelSelector is a label query over pods that should match the replica count.<br />It must match the pod template's labels.<br />Deprecated: this field will be removed in the future. | | |
429429
| `members` _[EtcdMemberStatus](#etcdmemberstatus) array_ | Members represents the members of the etcd cluster | | |
430430
| `peerUrlTLSEnabled` _boolean_ | PeerUrlTLSEnabled captures the state of peer url TLS being enabled for the etcd member(s) | | |
431+
| `clusterSize` _integer_ | ClusterSize is the last recorded etcd cluster size. | | |
431432

432433

433434
#### GarbageCollectionPolicy

internal/controller/etcd/reconcile_status.go

+13-4
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,9 @@ func (r *Reconciler) reconcileStatus(ctx component.OperatorContext, etcdObjectKe
2727
sLog := r.logger.WithValues("etcd", etcdObjectKey, "operation", "reconcileStatus").WithValues("runID", ctx.RunID)
2828
originalEtcd := etcd.DeepCopy()
2929
mutateETCDStatusStepFns := []mutateEtcdStatusFn{
30-
r.mutateETCDStatusWithMemberStatusAndConditions,
31-
r.inspectStatefulSetAndMutateETCDStatus,
30+
r.mutateEtcdStatusWithMemberStatusAndConditions,
31+
r.inspectStatefulSetAndMutateEtcdStatus,
32+
r.mutateEtcdStatusWithClusterSize,
3233
}
3334
for _, fn := range mutateETCDStatusStepFns {
3435
if stepResult := fn(ctx, etcd, sLog); ctrlutils.ShortCircuitReconcileFlow(stepResult) {
@@ -42,7 +43,7 @@ func (r *Reconciler) reconcileStatus(ctx component.OperatorContext, etcdObjectKe
4243
return ctrlutils.ContinueReconcile()
4344
}
4445

45-
func (r *Reconciler) mutateETCDStatusWithMemberStatusAndConditions(ctx component.OperatorContext, etcd *druidv1alpha1.Etcd, logger logr.Logger) ctrlutils.ReconcileStepResult {
46+
func (r *Reconciler) mutateEtcdStatusWithMemberStatusAndConditions(ctx component.OperatorContext, etcd *druidv1alpha1.Etcd, logger logr.Logger) ctrlutils.ReconcileStepResult {
4647
statusCheck := status.NewChecker(r.client, r.config.EtcdMember.NotReadyThreshold, r.config.EtcdMember.UnknownThreshold)
4748
if err := statusCheck.Check(ctx, logger, etcd); err != nil {
4849
logger.Error(err, "Error executing status checks to update member status and conditions")
@@ -51,7 +52,7 @@ func (r *Reconciler) mutateETCDStatusWithMemberStatusAndConditions(ctx component
5152
return ctrlutils.ContinueReconcile()
5253
}
5354

54-
func (r *Reconciler) inspectStatefulSetAndMutateETCDStatus(ctx component.OperatorContext, etcd *druidv1alpha1.Etcd, _ logr.Logger) ctrlutils.ReconcileStepResult {
55+
func (r *Reconciler) inspectStatefulSetAndMutateEtcdStatus(ctx component.OperatorContext, etcd *druidv1alpha1.Etcd, _ logr.Logger) ctrlutils.ReconcileStepResult {
5556
sts, err := kubernetes.GetStatefulSet(ctx, r.client, etcd)
5657
if err != nil {
5758
return ctrlutils.ReconcileWithError(err)
@@ -79,3 +80,11 @@ func (r *Reconciler) inspectStatefulSetAndMutateETCDStatus(ctx component.Operato
7980
}
8081
return ctrlutils.ContinueReconcile()
8182
}
83+
84+
func (r *Reconciler) mutateEtcdStatusWithClusterSize(_ component.OperatorContext, etcd *druidv1alpha1.Etcd, _ logr.Logger) ctrlutils.ReconcileStepResult {
85+
if etcd.Spec.Replicas > etcd.Status.ClusterSize && etcd.HasConditionWithStatus(druidv1alpha1.ConditionTypeAllMembersReady, druidv1alpha1.ConditionTrue) {
86+
etcd.Status.ClusterSize = etcd.Spec.Replicas
87+
}
88+
89+
return ctrlutils.ContinueReconcile()
90+
}

0 commit comments

Comments
 (0)