3 minute read
CRD Validations for etcd
- The validations for the fields within the
etcd
resource are done via kubebuilder markers for CRD validation. - The validations for clusters with kubernetes versions
>= 1.29
are written using a combination of CEL expressions via thex-validation
tag which provides a straightforward syntax to write validation rules for the fields, and pattern matching with the use of thevalidation
tag. - The validations for clusters with kubernetes versions
< 1.29
will not contain validations viaCEL
expressions since this is GA for kubernetes version 1.29 or higher. - Upon any changes to the validation rules to the etcd resource, the
yaml
files for the same can be generated by running themake generate
command.
Validation rules:
Type Validation rules:
The validations for fields of types Duration
(metav1.Duration) and cron
expressions are done via regex
matching. These use the validation:Pattern
marker.(The checking for the Quantity
(resource.Quantity) fields are done by default, hence, no explicit validation is needed for the fields of this type):
Duration fields:
'^([0-9]+([.][0-9]+)?h)?([0-9]+([.][0-9]+)?m)?([0-9]+([.][0-9]+)?s)?([0-9]+([.][0-9]+)?d)?$')
Cron expression:
^(\*|[1-5]?[0-9]|[1-5]?[0-9]-[1-5]?[0-9]|(?:[1-9]|[1-4][0-9]|5[0-9])\/(?:[1-9]|[1-4][0-9]|5[0-9]|60)|\*\/(?:[1-9]|[1-4][0-9]|5[0-9]|60))\s+(\*|[0-9]|1[0-9]|2[0-3]|[0-9]-(?:[0-9]|1[0-9]|2[0-3])|1[0-9]-(?:1[0-9]|2[0-3])|2[0-3]-2[0-3]|(?:[1-9]|1[0-9]|2[0-3])\/(?:[1-9]|1[0-9]|2[0-4])|\*\/(?:[1-9]|1[0-9]|2[0-4]))\s+(\*|[1-9]|[12][0-9]|3[01]|[1-9]-(?:[1-9]|[12][0-9]|3[01])|[12][0-9]-(?:[12][0-9]|3[01])|3[01]-3[01]|(?:[1-9]|[12][0-9]|30)\/(?:[1-9]|[12][0-9]|3[01])|\*\/(?:[1-9]|[12][0-9]|3[01]))\s+(\*|[1-9]|1[0-2]|[1-9]-(?:[1-9]|1[0-2])|1[0-2]-1[0-2]|(?:[1-9]|1[0-2])\/(?:[1-9]|1[0-2])|\*\/(?:[1-9]|1[0-2]))\s+(\*|[1-7]|[1-6]-[1-7]|[1-6]\/[1-7]|\*\/[1-7])$
- NOTE: The provided regex does not account for
special strings
such as@yearly
or@monthly
. Additionally, it fails to invalidate cases involving thestep operator (x/y)
and therange operator (x-y)
, where the cron expression is considered valid even ifx > y
. Please ensure these values are validated before passing the expression.
- NOTE: The provided regex does not account for
Update validations
These validations are triggered when an update operation is done on the etcd resource.
Immutable fields: The fields
etcd.spec.StorageClass
,etcd.spec.StorageCapacity
andetcd.spec.VolumeClaimTemplate
are immutable. The immutability is enforced by the CEL expression :self == oldSelf
.The value set for the field
etcd.spec.replicas
can either be decreased to0
or increased. This is enforced by the CEL expression:self==0 ? true : self < oldSelf ? false : true
Field validations
- The fields which expect only a particular set of values are checked by using the kubebuilder marker:
+kubebuilder:validation:Enum=<value1>;<value2>
- The
etcd.spec.etcd.metrics
can only be set as eitherbasic
orextensive
. - The
etcd.spec.backup.garbageCollectionPolicy
can only be set asExponential
orLimitBased
- The
etcd.spec.backup.compression.policy
can only be set as eithergzip
orlzw
orzlib
. - The
etcd.spec.sharedConfig.autoCompactionMode
can only be set as eitherperiodic
orrevision
.
- The
The value of
etcd.spec.backup.garbageCollectionPeriod
must be greater thanetcd.spec.backup.deltaSnapshotPeriod
. This is enforced by the CEL expression!(has(self.deltaSnapshotPeriod) && has(self.garbageCollectionPeriod)) || duration(self.deltaSnapshotPeriod).getSeconds() < duration(self.garbageCollectionPeriod).getSeconds()
. The first part of the expression ensures that both the fields are present and then compares the values of the garbageCollectionPeriod and deltaSnapshotPeriod fields, if not, skips the check.The value of
etcd.spec.StorageCapacity
must be more than 3 times that of theetcd.spec.etcd.quota
if backups are enabled. If not, the value must be greater than that of theetcd.spec.etcd.quota
field. This is enforced by using the CEL expression:has(self.storageCapacity) && has(self.etcd.quota) ? (has(self.backup.store) ? quantity(self.storageCapacity).compareTo(quantity(self.etcd.quota).add(quantity(self.etcd.quota)).add(quantity(self.etcd.quota))) > 0 : quantity(self.storageCapacity).compareTo(quantity(self.etcd.quota)) > 0 ): true
The check for whether backups are enabled or not is done by checking if the fieldetcd.spec.backup.store
exists.