Skip to content

Commit 1ea0bc2

Browse files
committed
feat(platform): add implementation of backup-strategy controller for etcd
Signed-off-by: Andrey Kolkov <[email protected]>
1 parent c5e9287 commit 1ea0bc2

34 files changed

Lines changed: 5246 additions & 30 deletions

‎.gitignore‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,12 @@ tmp/
8484
# build revision marker (generated by make image-packages)
8585
packages/core/platform/.build-revision
8686
.claude/
87+
88+
# Credentials and runtime state minted by the backup/restore demo scripts
89+
# under examples/backups/*/. Files are written by 00-helpers.sh +
90+
# 02-create-bucket.sh + 04-create-backupjob.sh; cleanup.sh deletes them
91+
# on teardown. Keep them out of git so a tenant who runs the demo and
92+
# then `git add .` does not accidentally commit S3 keys.
93+
examples/backups/*/.bucket-info.env
94+
examples/backups/*/.sentinel.env
95+
examples/backups/*/.backup-name.env
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// Package v1alpha1 defines strategy.backups.cozystack.io API types.
3+
//
4+
// Group: strategy.backups.cozystack.io
5+
// Version: v1alpha1
6+
package v1alpha1
7+
8+
import (
9+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10+
"k8s.io/apimachinery/pkg/runtime"
11+
)
12+
13+
func init() {
14+
SchemeBuilder.Register(func(s *runtime.Scheme) error {
15+
s.AddKnownTypes(GroupVersion,
16+
&Etcd{},
17+
&EtcdList{},
18+
)
19+
return nil
20+
})
21+
}
22+
23+
const (
24+
EtcdStrategyKind = "Etcd"
25+
)
26+
27+
// +kubebuilder:object:root=true
28+
// +kubebuilder:subresource:status
29+
// +kubebuilder:resource:scope=Cluster
30+
31+
// Etcd defines a backup strategy that delegates execution to the
32+
// etcd-operator (etcd.aenix.io). The strategy carries a templated backup
33+
// destination configuration; the driver materialises one
34+
// etcd.aenix.io/v1alpha1 EtcdBackup per Cozystack BackupJob and surfaces
35+
// it as a Cozystack Backup artefact. Restores are driven by stamping the
36+
// rendered destination back onto EtcdCluster.spec.bootstrap.restore.source
37+
// on the target Etcd application - either by recreating the source
38+
// EtcdCluster (in-place) or by patching a freshly provisioned target
39+
// EtcdCluster before the operator marks it Ready (to-copy).
40+
type Etcd struct {
41+
metav1.TypeMeta `json:",inline"`
42+
metav1.ObjectMeta `json:"metadata,omitempty"`
43+
44+
Spec EtcdSpec `json:"spec,omitempty"`
45+
Status EtcdStatus `json:"status,omitempty"`
46+
}
47+
48+
// +kubebuilder:object:root=true
49+
50+
// EtcdList contains a list of Etcd backup strategies.
51+
type EtcdList struct {
52+
metav1.TypeMeta `json:",inline"`
53+
metav1.ListMeta `json:"metadata,omitempty"`
54+
Items []Etcd `json:"items"`
55+
}
56+
57+
// EtcdSpec specifies the desired etcd-operator-driven backup strategy.
58+
type EtcdSpec struct {
59+
// Template carries the templated EtcdBackup destination configuration
60+
// applied per BackupJob (and re-rendered against the same
61+
// .Application / .Parameters at restore time). String fields support
62+
// Helm-style Go templating with two top-level values:
63+
// .Application - the application object (apps.cozystack.io/Etcd)
64+
// .Parameters - the parameters from the matched BackupClassStrategy.
65+
// These values MUST NOT carry credentials; route S3
66+
// access keys through
67+
// Destination.S3.CredentialsSecretRef.
68+
Template EtcdTemplate `json:"template"`
69+
}
70+
71+
// EtcdTemplate describes the templated EtcdBackup-shaped configuration the
72+
// driver renders per BackupJob (and on the restore path stamps onto
73+
// EtcdCluster.spec.bootstrap.restore.source).
74+
type EtcdTemplate struct {
75+
// Destination defines where the etcd snapshot will be stored. Field
76+
// semantics mirror etcd.aenix.io/v1alpha1 EtcdBackup.spec.destination.
77+
Destination EtcdDestinationTemplate `json:"destination"`
78+
}
79+
80+
// EtcdDestinationTemplate mirrors etcd.aenix.io/v1alpha1
81+
// EtcdBackup.spec.destination. Exactly one of S3 or PVC must be set; the
82+
// XValidation rule rejects ambiguous templates at admission time so the
83+
// driver never has to invent precedence.
84+
// +kubebuilder:validation:XValidation:rule="(has(self.s3) ? 1 : 0) + (has(self.pvc) ? 1 : 0) == 1",message="exactly one of s3 or pvc must be set"
85+
type EtcdDestinationTemplate struct {
86+
// S3 configures an S3-compatible storage target. Templating is
87+
// supported on every string field (Bucket, Endpoint, Key, Region,
88+
// CredentialsSecretRef.Name).
89+
// +optional
90+
S3 *EtcdS3Template `json:"s3,omitempty"`
91+
92+
// PVC configures a PersistentVolumeClaim-backed storage target.
93+
// Templating is supported on ClaimName and SubPath.
94+
// +optional
95+
PVC *EtcdPVCTemplate `json:"pvc,omitempty"`
96+
}
97+
98+
// EtcdS3Template is a typed, kubebuilder-validated mirror of
99+
// etcd.aenix.io/v1alpha1 EtcdBackup.spec.destination.s3. Restores reuse
100+
// the same shape: the driver re-renders the strategy and stamps the
101+
// resulting block onto EtcdCluster.spec.bootstrap.restore.source.s3 of the
102+
// target Etcd application.
103+
type EtcdS3Template struct {
104+
// Bucket is the S3 (or compatible) bucket name. Templating is
105+
// supported.
106+
// +kubebuilder:validation:MinLength=1
107+
Bucket string `json:"bucket"`
108+
109+
// Endpoint is the S3-compatible endpoint URL, including scheme (e.g.
110+
// "https://s3.amazonaws.com" or
111+
// "http://seaweedfs-s3.tenant-root.svc:8333"). Templating is
112+
// supported.
113+
// +kubebuilder:validation:MinLength=1
114+
Endpoint string `json:"endpoint"`
115+
116+
// Key is the key prefix (directory path) within the bucket. The
117+
// etcd-operator appends the snapshot filename automatically.
118+
// Templating is supported.
119+
// +optional
120+
Key string `json:"key,omitempty"`
121+
122+
// Region is the AWS region for the S3 bucket. Templating is
123+
// supported.
124+
// +optional
125+
Region string `json:"region,omitempty"`
126+
127+
// ForcePathStyle forces path-style S3 URLs (e.g., endpoint/bucket/key)
128+
// instead of virtual-hosted-style (e.g., bucket.endpoint/key). Most
129+
// S3-compatible providers (MinIO, Ceph, seaweedfs-s3) require path
130+
// style.
131+
// +optional
132+
ForcePathStyle *bool `json:"forcePathStyle,omitempty"`
133+
134+
// CredentialsSecretRef references a Secret containing
135+
// AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY keys. The Secret must
136+
// live in the application's namespace. Templating is supported on
137+
// Name (typical pattern:
138+
// "{{ .Application.metadata.name }}-etcd-backup-creds").
139+
CredentialsSecretRef EtcdLocalObjectReference `json:"credentialsSecretRef"`
140+
}
141+
142+
// EtcdLocalObjectReference is a minimal local Secret reference. The driver
143+
// looks the Secret up in the application namespace.
144+
type EtcdLocalObjectReference struct {
145+
// Name is the Secret name. Templating is supported.
146+
// +kubebuilder:validation:MinLength=1
147+
Name string `json:"name"`
148+
}
149+
150+
// EtcdPVCTemplate mirrors etcd.aenix.io/v1alpha1
151+
// EtcdBackup.spec.destination.pvc. The driver stamps the rendered fields
152+
// onto the operator-side EtcdBackup verbatim; the operator mounts the PVC
153+
// and appends the snapshot filename under SubPath.
154+
type EtcdPVCTemplate struct {
155+
// ClaimName is the name of the PersistentVolumeClaim to use as the
156+
// backup destination. The PVC must live in the application's
157+
// namespace and be ReadWriteMany if multiple BackupJobs may run
158+
// concurrently. Templating is supported.
159+
// +kubebuilder:validation:MinLength=1
160+
ClaimName string `json:"claimName"`
161+
162+
// SubPath is an optional sub-directory within the PVC volume. The
163+
// operator appends the snapshot filename automatically. Templating is
164+
// supported.
165+
// +optional
166+
SubPath string `json:"subPath,omitempty"`
167+
}
168+
169+
// EtcdStatus reports observed state for the strategy CR. Driver
170+
// controllers surface diagnostic conditions here (e.g. validation issues).
171+
type EtcdStatus struct {
172+
// Conditions holds the latest available observations.
173+
// +optional
174+
// +listType=map
175+
// +listMapKey=type
176+
Conditions []metav1.Condition `json:"conditions,omitempty"`
177+
}

‎api/backups/strategy/v1alpha1/zz_generated.deepcopy.go‎

Lines changed: 189 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)