Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions api/v1alpha1/etcd_maintenance.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package v1alpha1

import (
"fmt"
"strconv"
"time"
)

// EffectiveCompaction returns etcd's configured mode and retention, including
// defaults. Validate here as well as in the CRD for callers without admission.
func (c *EtcdMaintenanceConfig) EffectiveCompaction() (mode, retention string, err error) {
mode = "periodic"
if c != nil && c.AutoCompactionMode != "" {
mode = c.AutoCompactionMode
}
switch mode {
case "periodic":
retention = "1h"
case "revision":
retention = "10000"
default:
return "", "", fmt.Errorf("invalid etcd compaction mode %q", mode)
}
if c != nil && c.AutoCompactionRetention != "" {
retention = c.AutoCompactionRetention
}
if mode == "periodic" {
d, parseErr := time.ParseDuration(retention)
if parseErr != nil || d <= 0 {
return "", "", fmt.Errorf("invalid periodic etcd compaction retention %q", retention)
}
} else {
n, parseErr := strconv.ParseInt(retention, 10, 64)
if parseErr != nil || n <= 0 {
return "", "", fmt.Errorf("invalid revision etcd compaction retention %q", retention)
}
}
return mode, retention, nil
}

// EffectiveQuotaBackendBytes preserves the pre-existing etcd quota unless an
// administrator explicitly supplies one. Quota cannot predict restore memory.
func (c *EtcdMaintenanceConfig) EffectiveQuotaBackendBytes() int64 {
if c == nil || c.QuotaBackendBytes == nil {
return 2 * 1024 * 1024 * 1024
}
return *c.QuotaBackendBytes
}

// DefragmentationIsEnabled reports whether automatic defragmentation is opted in.
func (c *EtcdMaintenanceConfig) DefragmentationIsEnabled() bool {
return c != nil && c.DefragmentationEnabled != nil && *c.DefragmentationEnabled
}
31 changes: 31 additions & 0 deletions api/v1alpha1/etcd_maintenance_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package v1alpha1

import "testing"

func TestEffectiveCompaction(t *testing.T) {
for _, tc := range []struct {
name string
config *EtcdMaintenanceConfig
mode, retention string
wantErr bool
}{
{"omitted", nil, "periodic", "1h", false},
{"empty", &EtcdMaintenanceConfig{}, "periodic", "1h", false},
{"periodic", &EtcdMaintenanceConfig{AutoCompactionRetention: "30m"}, "periodic", "30m", false},
{"revision default", &EtcdMaintenanceConfig{AutoCompactionMode: "revision"}, "revision", "10000", false},
{"revision", &EtcdMaintenanceConfig{AutoCompactionMode: "revision", AutoCompactionRetention: "5000"}, "revision", "5000", false},
{"unknown mode", &EtcdMaintenanceConfig{AutoCompactionMode: "bad"}, "", "", true},
{"disabled retention", &EtcdMaintenanceConfig{AutoCompactionRetention: "0h"}, "", "", true},
{"negative retention", &EtcdMaintenanceConfig{AutoCompactionRetention: "-1h"}, "", "", true},
{"invalid duration", &EtcdMaintenanceConfig{AutoCompactionRetention: "forever"}, "", "", true},
{"revision duration", &EtcdMaintenanceConfig{AutoCompactionMode: "revision", AutoCompactionRetention: "1h"}, "", "", true},
{"zero revisions", &EtcdMaintenanceConfig{AutoCompactionMode: "revision", AutoCompactionRetention: "0"}, "", "", true},
} {
t.Run(tc.name, func(t *testing.T) {
mode, retention, err := tc.config.EffectiveCompaction()
if (err != nil) != tc.wantErr || mode != tc.mode || retention != tc.retention {
t.Fatalf("got (%q,%q,%v)", mode, retention, err)
}
})
}
}
56 changes: 56 additions & 0 deletions api/v1alpha1/toposerver_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,22 @@ type TopoServerStatus struct {
// PeerService is the name of the service for peers.
// +optional
PeerService string `json:"peerService,omitempty"`

// EtcdMaintenance records a maintenance reservation before contacting etcd,
// preventing overlapping defragmentation across reconciles and restarts.
// +optional
EtcdMaintenance *EtcdMaintenanceStatus `json:"etcdMaintenance,omitempty"`
}

// EtcdMaintenanceStatus tracks the most recent automatic defragmentation.
type EtcdMaintenanceStatus struct {
// LastAttemptTime starts the one-hour minimum interval between members.
LastAttemptTime metav1.Time `json:"lastAttemptTime"`
// Endpoint identifies the member reserved for defragmentation.
Endpoint string `json:"endpoint"`
// InProgress remains true after an interrupted or uncertain operation until
// all members pass health checks again. While true, pod rollouts are paused.
InProgress bool `json:"inProgress"`
}

// ============================================================================
Expand Down Expand Up @@ -127,6 +143,12 @@ type EtcdSpec struct {
// +optional
Resources corev1.ResourceRequirements `json:"resources,omitempty"`

// Maintenance configures MVCC history retention, backend quota, and optional
// defragmentation. Applies only to operator-managed etcd. Omitted fields use
// the defaults documented on EtcdMaintenanceConfig.
// +optional
Maintenance *EtcdMaintenanceConfig `json:"maintenance,omitempty"`

// RootPath is the etcd prefix for this cluster.
// +optional
// +kubebuilder:validation:MinLength=1
Expand All @@ -139,6 +161,40 @@ type EtcdSpec struct {
PVCDeletionPolicy *PVCDeletionPolicy `json:"pvcDeletionPolicy,omitempty"`
}

// EtcdMaintenanceConfig controls storage maintenance independently of logical
// topology pruning. Defaults are applied at rendering time so template values
// remain inheritable. Changing compaction or quota rolls the etcd pods.
// +kubebuilder:validation:XValidation:rule="!has(self.autoCompactionRetention) || ((has(self.autoCompactionMode) && self.autoCompactionMode == 'revision') ? self.autoCompactionRetention.matches('^[1-9][0-9]{0,9}$') : self.autoCompactionRetention.matches('^([0-9]{1,6}h)?([0-9]{1,6}m)?([0-9]{1,6}s)?$'))",message="compaction retention must be a positive revision count in revision mode or a duration using h, m, s in periodic mode"
type EtcdMaintenanceConfig struct {
// AutoCompactionMode defaults to periodic (time-based retention).
// +kubebuilder:validation:Enum=periodic;revision
// +optional
AutoCompactionMode string `json:"autoCompactionMode,omitempty"`

// AutoCompactionRetention defaults to 1h in periodic mode or 10000 in
// revision mode. Periodic values must be positive durations (e.g. 30m, 1h).
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=32
// +kubebuilder:validation:XValidation:rule="self.matches('[1-9]')",message="compaction retention must be positive"
// +optional
AutoCompactionRetention string `json:"autoCompactionRetention,omitempty"`

// QuotaBackendBytes defaults to 2147483648 (2 GiB), preserving etcd's
// existing default. This is a storage quota, not a memory limit: provision
// memory for measured restore-time usage and disk for the backend and WAL.
// Do not lower the quota below an existing backend's size.
// +kubebuilder:validation:Minimum=1048576
// +kubebuilder:validation:Maximum=8589934592
// +optional
QuotaBackendBytes *int64 `json:"quotaBackendBytes,omitempty"`

// DefragmentationEnabled opts into hourly, health-gated maintenance of at
// most one member. Requires at least three healthy members, no rollout,
// and at least 100 MiB and 30% reclaimable space. Disabled by default.
// +optional
DefragmentationEnabled *bool `json:"defragmentationEnabled,omitempty"`
}

// GlobalTopoServerSpec defines the configuration for the global topology server.
// It can be either an inline Etcd spec, an External reference, or a Template reference.
// +kubebuilder:validation:XValidation:rule="[has(self.etcd), has(self.external), has(self.templateRef)].filter(x, x).size() == 1",message="must specify exactly one of 'etcd', 'external', or 'templateRef'"
Expand Down
51 changes: 51 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

47 changes: 47 additions & 0 deletions config/crd/bases/multigres.com_cells.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1453,6 +1453,53 @@ spec:
maxLength: 512
minLength: 1
type: string
maintenance:
description: |-
Maintenance configures MVCC history retention, backend quota, and optional
defragmentation. Applies only to operator-managed etcd. Omitted fields use
the defaults documented on EtcdMaintenanceConfig.
properties:
autoCompactionMode:
description: AutoCompactionMode defaults to periodic (time-based
retention).
enum:
- periodic
- revision
type: string
autoCompactionRetention:
description: |-
AutoCompactionRetention defaults to 1h in periodic mode or 10000 in
revision mode. Periodic values must be positive durations (e.g. 30m, 1h).
maxLength: 32
minLength: 1
type: string
x-kubernetes-validations:
- message: compaction retention must be positive
rule: self.matches('[1-9]')
defragmentationEnabled:
description: |-
DefragmentationEnabled opts into hourly, health-gated maintenance of at
most one member. Requires at least three healthy members, no rollout,
and at least 100 MiB and 30% reclaimable space. Disabled by default.
type: boolean
quotaBackendBytes:
description: |-
QuotaBackendBytes defaults to 2147483648 (2 GiB), preserving etcd's
existing default. This is a storage quota, not a memory limit: provision
memory for measured restore-time usage and disk for the backend and WAL.
Do not lower the quota below an existing backend's size.
format: int64
maximum: 8589934592
minimum: 1048576
type: integer
type: object
x-kubernetes-validations:
- message: compaction retention must be a positive revision
count in revision mode or a duration using h, m, s in
periodic mode
rule: '!has(self.autoCompactionRetention) || ((has(self.autoCompactionMode)
&& self.autoCompactionMode == ''revision'') ? self.autoCompactionRetention.matches(''^[1-9][0-9]{0,9}$'')
: self.autoCompactionRetention.matches(''^([0-9]{1,6}h)?([0-9]{1,6}m)?([0-9]{1,6}s)?$''))'
pvcDeletionPolicy:
description: |-
PVCDeletionPolicy controls PVC lifecycle for etcd volumes.
Expand Down
47 changes: 47 additions & 0 deletions config/crd/bases/multigres.com_celltemplates.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,53 @@ spec:
maxLength: 512
minLength: 1
type: string
maintenance:
description: |-
Maintenance configures MVCC history retention, backend quota, and optional
defragmentation. Applies only to operator-managed etcd. Omitted fields use
the defaults documented on EtcdMaintenanceConfig.
properties:
autoCompactionMode:
description: AutoCompactionMode defaults to periodic (time-based
retention).
enum:
- periodic
- revision
type: string
autoCompactionRetention:
description: |-
AutoCompactionRetention defaults to 1h in periodic mode or 10000 in
revision mode. Periodic values must be positive durations (e.g. 30m, 1h).
maxLength: 32
minLength: 1
type: string
x-kubernetes-validations:
- message: compaction retention must be positive
rule: self.matches('[1-9]')
defragmentationEnabled:
description: |-
DefragmentationEnabled opts into hourly, health-gated maintenance of at
most one member. Requires at least three healthy members, no rollout,
and at least 100 MiB and 30% reclaimable space. Disabled by default.
type: boolean
quotaBackendBytes:
description: |-
QuotaBackendBytes defaults to 2147483648 (2 GiB), preserving etcd's
existing default. This is a storage quota, not a memory limit: provision
memory for measured restore-time usage and disk for the backend and WAL.
Do not lower the quota below an existing backend's size.
format: int64
maximum: 8589934592
minimum: 1048576
type: integer
type: object
x-kubernetes-validations:
- message: compaction retention must be a positive revision
count in revision mode or a duration using h, m, s in
periodic mode
rule: '!has(self.autoCompactionRetention) || ((has(self.autoCompactionMode)
&& self.autoCompactionMode == ''revision'') ? self.autoCompactionRetention.matches(''^[1-9][0-9]{0,9}$'')
: self.autoCompactionRetention.matches(''^([0-9]{1,6}h)?([0-9]{1,6}m)?([0-9]{1,6}s)?$''))'
pvcDeletionPolicy:
description: |-
PVCDeletionPolicy controls PVC lifecycle for etcd volumes.
Expand Down
47 changes: 47 additions & 0 deletions config/crd/bases/multigres.com_coretemplates.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,53 @@ spec:
maxLength: 512
minLength: 1
type: string
maintenance:
description: |-
Maintenance configures MVCC history retention, backend quota, and optional
defragmentation. Applies only to operator-managed etcd. Omitted fields use
the defaults documented on EtcdMaintenanceConfig.
properties:
autoCompactionMode:
description: AutoCompactionMode defaults to periodic (time-based
retention).
enum:
- periodic
- revision
type: string
autoCompactionRetention:
description: |-
AutoCompactionRetention defaults to 1h in periodic mode or 10000 in
revision mode. Periodic values must be positive durations (e.g. 30m, 1h).
maxLength: 32
minLength: 1
type: string
x-kubernetes-validations:
- message: compaction retention must be positive
rule: self.matches('[1-9]')
defragmentationEnabled:
description: |-
DefragmentationEnabled opts into hourly, health-gated maintenance of at
most one member. Requires at least three healthy members, no rollout,
and at least 100 MiB and 30% reclaimable space. Disabled by default.
type: boolean
quotaBackendBytes:
description: |-
QuotaBackendBytes defaults to 2147483648 (2 GiB), preserving etcd's
existing default. This is a storage quota, not a memory limit: provision
memory for measured restore-time usage and disk for the backend and WAL.
Do not lower the quota below an existing backend's size.
format: int64
maximum: 8589934592
minimum: 1048576
type: integer
type: object
x-kubernetes-validations:
- message: compaction retention must be a positive revision
count in revision mode or a duration using h, m, s in
periodic mode
rule: '!has(self.autoCompactionRetention) || ((has(self.autoCompactionMode)
&& self.autoCompactionMode == ''revision'') ? self.autoCompactionRetention.matches(''^[1-9][0-9]{0,9}$'')
: self.autoCompactionRetention.matches(''^([0-9]{1,6}h)?([0-9]{1,6}m)?([0-9]{1,6}s)?$''))'
pvcDeletionPolicy:
description: |-
PVCDeletionPolicy controls PVC lifecycle for etcd volumes.
Expand Down
Loading
Loading