Skip to content

Commit 491b8fc

Browse files
committed
Add pgbackrest clone support
Adds new attributes to cluster manifest clone section that allows cloning from pgbackrest sources. Right now the stanza is not configurable and must be "db". Adds a pgabckrest-clone configmap with repository configuration that gets mounted to the container. PVC based clones automatically mount the certificate secret from the source cluster to be able to clone. Cross namespace clones are currently not supported. S3 support is to be tested, but uses same code as backups.
1 parent 8ca1ce6 commit 491b8fc

8 files changed

Lines changed: 421 additions & 9 deletions

File tree

charts/postgres-operator/crds/postgresqls.yaml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,39 @@ spec:
133133
uid:
134134
format: uuid
135135
type: string
136+
pgbackrest:
137+
type: object
138+
properties:
139+
configuration:
140+
type: object
141+
properties:
142+
secret:
143+
type: string
144+
options:
145+
type: object
146+
additionalProperties:
147+
type: string
148+
repo:
149+
type: object
150+
properties:
151+
storage:
152+
type: string
153+
enum:
154+
- "s3"
155+
- "gcs"
156+
- "azure"
157+
- "pvc"
158+
resource:
159+
type: string
160+
endpoint:
161+
type: string
162+
region:
163+
type: string
164+
required:
165+
- storage
166+
- resource
167+
required:
168+
- repo
136169
connectionPooler:
137170
type: object
138171
properties:

manifests/postgresql.crd.yaml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,39 @@ spec:
131131
uid:
132132
format: uuid
133133
type: string
134+
pgbackrest:
135+
type: object
136+
properties:
137+
configuration:
138+
type: object
139+
properties:
140+
secret:
141+
type: string
142+
options:
143+
type: object
144+
additionalProperties:
145+
type: string
146+
repo:
147+
type: object
148+
properties:
149+
storage:
150+
type: string
151+
enum:
152+
- "s3"
153+
- "gcs"
154+
- "azure"
155+
- "pvc"
156+
resource:
157+
type: string
158+
endpoint:
159+
type: string
160+
region:
161+
type: string
162+
required:
163+
- storage
164+
- resource
165+
required:
166+
- repo
134167
connectionPooler:
135168
type: object
136169
properties:

pkg/apis/cpo.opensource.cybertec.at/v1/crds.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,68 @@ var PostgresCRDResourceValidation = apiextv1.CustomResourceValidation{
213213
Type: "string",
214214
Format: "uuid",
215215
},
216+
"pgbackrest": {
217+
Type: "object",
218+
Properties: map[string]apiextv1.JSONSchemaProps{
219+
"configuration": {
220+
Type: "object",
221+
Properties: map[string]apiextv1.JSONSchemaProps{
222+
"secret": {
223+
Type: "string",
224+
},
225+
},
226+
},
227+
"options": {
228+
Type: "object",
229+
AdditionalProperties: &apiextv1.JSONSchemaPropsOrBool{
230+
Schema: &apiextv1.JSONSchemaProps{
231+
Type: "string",
232+
XPreserveUnknownFields: util.True(),
233+
},
234+
},
235+
},
236+
"repo": {
237+
Type: "object",
238+
Properties: map[string]apiextv1.JSONSchemaProps{
239+
"storage": {
240+
Type: "string",
241+
Enum: []apiextv1.JSON{
242+
{
243+
Raw: []byte(`"s3"`),
244+
},
245+
{
246+
Raw: []byte(`"gcs"`),
247+
},
248+
{
249+
Raw: []byte(`"azure"`),
250+
},
251+
{
252+
Raw: []byte(`"pvc"`),
253+
},
254+
},
255+
},
256+
"resource": {
257+
Type: "string",
258+
},
259+
"endpoint": {
260+
Type: "string",
261+
},
262+
"region": {
263+
Type: "string",
264+
},
265+
"account": {
266+
Type: "string",
267+
},
268+
"key": {
269+
Type: "string",
270+
},
271+
"keyType": {
272+
Type: "string",
273+
},
274+
},
275+
},
276+
},
277+
},
216278
},
217279
},
218280
"connectionPooler": {

pkg/apis/cpo.opensource.cybertec.at/v1/postgresql_type.go

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -203,14 +203,15 @@ type TLSDescription struct {
203203

204204
// CloneDescription describes which cluster the new should clone and up to which point in time
205205
type CloneDescription struct {
206-
ClusterName string `json:"cluster,omitempty"`
207-
UID string `json:"uid,omitempty"`
208-
EndTimestamp string `json:"timestamp,omitempty"`
209-
S3WalPath string `json:"s3_wal_path,omitempty"`
210-
S3Endpoint string `json:"s3_endpoint,omitempty"`
211-
S3AccessKeyId string `json:"s3_access_key_id,omitempty"`
212-
S3SecretAccessKey string `json:"s3_secret_access_key,omitempty"`
213-
S3ForcePathStyle *bool `json:"s3_force_path_style,omitempty" defaults:"false"`
206+
ClusterName string `json:"cluster,omitempty"`
207+
UID string `json:"uid,omitempty"`
208+
EndTimestamp string `json:"timestamp,omitempty"`
209+
S3WalPath string `json:"s3_wal_path,omitempty"`
210+
S3Endpoint string `json:"s3_endpoint,omitempty"`
211+
S3AccessKeyId string `json:"s3_access_key_id,omitempty"`
212+
S3SecretAccessKey string `json:"s3_secret_access_key,omitempty"`
213+
S3ForcePathStyle *bool `json:"s3_force_path_style,omitempty" defaults:"false"`
214+
Pgbackrest *PgbackrestClone `json:"pgbackrest,omitempty"`
214215
}
215216

216217
// Sidecar defines a container to be run in the same pod as the Postgres container.
@@ -283,6 +284,12 @@ type Pgbackrest struct {
283284
Resources *Resources `json:"resources,omitempty"`
284285
}
285286

287+
type PgbackrestClone struct {
288+
Repo Repo `json:"repo"`
289+
Options map[string]string `json:"options"`
290+
Configuration Configuration `json:"configuration"`
291+
}
292+
286293
type Repo struct {
287294
Name string `json:"name"`
288295
Storage string `json:"storage"`

pkg/apis/cpo.opensource.cybertec.at/v1/zz_generated.deepcopy.go

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

pkg/cluster/cluster.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,12 @@ func (c *Cluster) Create() (err error) {
366366
c.logger.Info("a monitoring secret was successfully created")
367367
}
368368

369+
if specHasPgbackrestClone(&c.Postgresql.Spec) {
370+
if err := c.createPgbackrestCloneConfig(); err != nil {
371+
return fmt.Errorf("could not create pgbackrest clone config: %v", err)
372+
}
373+
}
374+
369375
if c.multisiteEnabled() {
370376
c.logger.Infof("waiting for load balancer IP to be assigned")
371377
c.waitForPrimaryLoadBalancerIp()
@@ -1067,6 +1073,28 @@ func (c *Cluster) Update(oldSpec, newSpec *cpov1.Postgresql) error {
10671073
}
10681074
}()
10691075

1076+
// Clone configmap for pgbackrest
1077+
func() {
1078+
if specHasPgbackrestClone(&oldSpec.Spec) {
1079+
if specHasPgbackrestClone(&newSpec.Spec) {
1080+
// TODO: if we know cluster state and it has been initialized, then should ignore this
1081+
if err := c.updatePgbackrestCloneConfig(); err != nil {
1082+
c.logger.Warningf("could not update pgbackrest clone config: %v", err)
1083+
updateFailed = true
1084+
}
1085+
} else {
1086+
if err := c.deletePgbackrestCloneConfig(); err != nil {
1087+
c.logger.Warningf("could not delete pgbackrest clone config: %v", err)
1088+
}
1089+
}
1090+
} else if specHasPgbackrestClone(&newSpec.Spec) {
1091+
c.logger.Warningf("Can't add a clone specification after cluster has been initialized")
1092+
updateFailed = true
1093+
} else {
1094+
// TODO: try to delete just in case?
1095+
}
1096+
}()
1097+
10701098
// Statefulset
10711099
func() {
10721100
oldSs, err := c.generateStatefulSet(&oldSpec.Spec)
@@ -1225,6 +1253,10 @@ func specHasPgbackrestPVCRepo(newSpec *cpov1.PostgresSpec) bool {
12251253
return false
12261254
}
12271255

1256+
func specHasPgbackrestClone(newSpec *cpov1.PostgresSpec) bool {
1257+
return newSpec.Clone != nil && newSpec.Clone.Pgbackrest != nil
1258+
}
1259+
12281260
func syncResources(a, b *v1.ResourceRequirements) bool {
12291261
for _, res := range []v1.ResourceName{
12301262
v1.ResourceCPU,
@@ -1291,6 +1323,10 @@ func (c *Cluster) Delete() {
12911323
c.logger.Warningf("could not delete pod disruption budget: %v", err)
12921324
}
12931325

1326+
if err := c.deletePgbackrestCloneConfig(); err != nil {
1327+
c.logger.Warningf("could not delete pgbackrest clone config: %v", err)
1328+
}
1329+
12941330
for _, role := range []PostgresRole{Master, Replica, ClusterPods} {
12951331

12961332
if !c.patroniKubernetesUseConfigMaps() {

0 commit comments

Comments
 (0)