mirror of
https://github.com/cozystack/cozystack.git
synced 2026-11-09 14:02:56 +09:00
fix(mongodb): set the s3 bucket and prefix on the bootstrap restore
With bootstrap.enabled the chart rendered a PerconaServerMongoDBRestore without backupSource.s3.bucket. The operator CRD requires that field, so the API server rejected the restore and the HelmRelease failed. The prefix was missing too, and it matters just as much. For a backupSource restore the operator builds the PBM storage from backupSource.s3 alone and takes only the backup name from backupSource.destination, so a restore without the prefix would look for the backup at the bucket root. The restore now takes the bucket and prefix from the same helpers that fill the backup storage, so it reads from where the backups are written. Both places quote the two values, so a numeric bucket or prefix stays a string instead of making the resource invalid. The backup storage still leaves out an empty prefix, so running releases keep the same object. A destinationPath that names no bucket fails at render time instead of reaching the operator with an empty bucket. Assisted-by: LLM Signed-off-by: Yan Bondarenko <202671653+yankawai@users.noreply.github.com>
This commit is contained in:
1 parent
9620be0103
commit
a6cf0e5ce4
5 files changed
+272
-2
No files matched your search
@@ -0,0 +1,13 @@
|
||||
{{- /*
|
||||
Bucket and prefix of backup.destinationPath. The bootstrap restore has to
|
||||
read from the place the backup storage writes to. The operator builds the
|
||||
restore's storage from backupSource.s3 alone and takes only the backup name
|
||||
from backupSource.destination, so both templates derive the pair here.
|
||||
*/}}
|
||||
{{- define "mongodb.backup.bucket" -}}
|
||||
{{- .Values.backup.destinationPath | trimPrefix "s3://" | regexFind "^[^/]+" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "mongodb.backup.prefix" -}}
|
||||
{{- .Values.backup.destinationPath | trimPrefix "s3://" | splitList "/" | rest | join "/" -}}
|
||||
{{- end -}}
|
||||
@@ -244,8 +244,10 @@ spec:
|
||||
s3-storage:
|
||||
type: s3
|
||||
s3:
|
||||
bucket: {{ .Values.backup.destinationPath | trimPrefix "s3://" | regexFind "^[^/]+" }}
|
||||
prefix: {{ .Values.backup.destinationPath | trimPrefix "s3://" | splitList "/" | rest | join "/" }}
|
||||
bucket: {{ include "mongodb.backup.bucket" . | quote }}
|
||||
{{- with include "mongodb.backup.prefix" . }}
|
||||
prefix: {{ . | quote }}
|
||||
{{- end }}
|
||||
endpointUrl: {{ .Values.backup.endpointURL }}
|
||||
credentialsSecret: {{ .Release.Name }}-s3-creds
|
||||
insecureSkipTLSVerify: {{ .Values.backup.insecureSkipTLSVerify | default false }}
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
{{- if not .Values.backup.destinationPath }}
|
||||
{{- fail "backup.destinationPath is required when bootstrap.enabled is true" }}
|
||||
{{- end }}
|
||||
{{- if not (include "mongodb.backup.bucket" .) }}
|
||||
{{- fail "backup.destinationPath must name a bucket (s3://bucket/path/) when bootstrap.enabled is true" }}
|
||||
{{- end }}
|
||||
{{- if not .Values.backup.endpointURL }}
|
||||
{{- fail "backup.endpointURL is required when bootstrap.enabled is true" }}
|
||||
{{- end }}
|
||||
@@ -33,6 +36,8 @@ spec:
|
||||
type: logical
|
||||
destination: {{ .Values.backup.destinationPath | trimSuffix "/" }}/{{ .Values.bootstrap.backupName }}
|
||||
s3:
|
||||
bucket: {{ include "mongodb.backup.bucket" . | quote }}
|
||||
prefix: {{ include "mongodb.backup.prefix" . | quote }}
|
||||
credentialsSecret: {{ .Release.Name }}-s3-creds
|
||||
endpointUrl: {{ .Values.backup.endpointURL }}
|
||||
insecureSkipTLSVerify: {{ .Values.backup.insecureSkipTLSVerify | default false }}
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
suite: bootstrap restore reads where the backup storage writes
|
||||
|
||||
templates:
|
||||
- templates/mongodb.yaml
|
||||
- templates/restore.yaml
|
||||
|
||||
release:
|
||||
name: test-mongodb
|
||||
namespace: tenant-test
|
||||
|
||||
tests:
|
||||
- it: gives the restore the same S3 location and access as the backup storage
|
||||
set:
|
||||
_cluster:
|
||||
cluster-domain: cozy.local
|
||||
bootstrap:
|
||||
enabled: true
|
||||
backupName: "2026-10-01T02:00:21Z"
|
||||
backup:
|
||||
enabled: true
|
||||
destinationPath: "s3://mybucket/mongodb/prod/"
|
||||
endpointURL: "https://s3.example.org"
|
||||
insecureSkipTLSVerify: true
|
||||
s3AccessKey: "access"
|
||||
s3SecretKey: "secret"
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.backup.storages.s3-storage.s3.bucket
|
||||
value: mybucket
|
||||
template: templates/mongodb.yaml
|
||||
documentSelector:
|
||||
path: kind
|
||||
value: PerconaServerMongoDB
|
||||
- equal:
|
||||
path: spec.backupSource.s3.bucket
|
||||
value: mybucket
|
||||
template: templates/restore.yaml
|
||||
- equal:
|
||||
path: spec.backup.storages.s3-storage.s3.prefix
|
||||
value: mongodb/prod/
|
||||
template: templates/mongodb.yaml
|
||||
documentSelector:
|
||||
path: kind
|
||||
value: PerconaServerMongoDB
|
||||
- equal:
|
||||
path: spec.backupSource.s3.prefix
|
||||
value: mongodb/prod/
|
||||
template: templates/restore.yaml
|
||||
- equal:
|
||||
path: spec.backup.storages.s3-storage.s3.endpointUrl
|
||||
value: https://s3.example.org
|
||||
template: templates/mongodb.yaml
|
||||
documentSelector:
|
||||
path: kind
|
||||
value: PerconaServerMongoDB
|
||||
- equal:
|
||||
path: spec.backupSource.s3.endpointUrl
|
||||
value: https://s3.example.org
|
||||
template: templates/restore.yaml
|
||||
- equal:
|
||||
path: spec.backup.storages.s3-storage.s3.credentialsSecret
|
||||
value: test-mongodb-s3-creds
|
||||
template: templates/mongodb.yaml
|
||||
documentSelector:
|
||||
path: kind
|
||||
value: PerconaServerMongoDB
|
||||
- equal:
|
||||
path: spec.backupSource.s3.credentialsSecret
|
||||
value: test-mongodb-s3-creds
|
||||
template: templates/restore.yaml
|
||||
- equal:
|
||||
path: spec.backup.storages.s3-storage.s3.insecureSkipTLSVerify
|
||||
value: true
|
||||
template: templates/mongodb.yaml
|
||||
documentSelector:
|
||||
path: kind
|
||||
value: PerconaServerMongoDB
|
||||
- equal:
|
||||
path: spec.backupSource.s3.insecureSkipTLSVerify
|
||||
value: true
|
||||
template: templates/restore.yaml
|
||||
- equal:
|
||||
path: spec.backup.storages.s3-storage.s3.forcePathStyle
|
||||
value: true
|
||||
template: templates/mongodb.yaml
|
||||
documentSelector:
|
||||
path: kind
|
||||
value: PerconaServerMongoDB
|
||||
- equal:
|
||||
path: spec.backupSource.s3.forcePathStyle
|
||||
value: true
|
||||
template: templates/restore.yaml
|
||||
- equal:
|
||||
path: spec.backupSource.destination
|
||||
value: s3://mybucket/mongodb/prod/2026-10-01T02:00:21Z
|
||||
template: templates/restore.yaml
|
||||
|
||||
- it: keeps a numeric bucket and prefix as strings on both sides
|
||||
set:
|
||||
_cluster:
|
||||
cluster-domain: cozy.local
|
||||
bootstrap:
|
||||
enabled: true
|
||||
backupName: "2026-10-01T02:00:21Z"
|
||||
backup:
|
||||
enabled: true
|
||||
destinationPath: "s3://2024/10"
|
||||
endpointURL: "https://s3.example.org"
|
||||
s3AccessKey: "access"
|
||||
s3SecretKey: "secret"
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.backup.storages.s3-storage.s3.bucket
|
||||
value: "2024"
|
||||
template: templates/mongodb.yaml
|
||||
documentSelector:
|
||||
path: kind
|
||||
value: PerconaServerMongoDB
|
||||
- equal:
|
||||
path: spec.backup.storages.s3-storage.s3.prefix
|
||||
value: "10"
|
||||
template: templates/mongodb.yaml
|
||||
documentSelector:
|
||||
path: kind
|
||||
value: PerconaServerMongoDB
|
||||
- equal:
|
||||
path: spec.backupSource.s3.bucket
|
||||
value: "2024"
|
||||
template: templates/restore.yaml
|
||||
- equal:
|
||||
path: spec.backupSource.s3.prefix
|
||||
value: "10"
|
||||
template: templates/restore.yaml
|
||||
@@ -281,6 +281,123 @@ tests:
|
||||
path: spec.backupSource.s3.forcePathStyle
|
||||
value: true
|
||||
|
||||
- it: sets bucket and prefix from destinationPath
|
||||
release:
|
||||
name: test-mongodb
|
||||
namespace: tenant-test
|
||||
set:
|
||||
bootstrap:
|
||||
enabled: true
|
||||
backupName: "backup"
|
||||
backup:
|
||||
destinationPath: "s3://mybucket/mongodb/prod/"
|
||||
endpointURL: "http://minio:9000"
|
||||
s3AccessKey: "access"
|
||||
s3SecretKey: "secret"
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.backupSource.s3.bucket
|
||||
value: mybucket
|
||||
- equal:
|
||||
path: spec.backupSource.s3.prefix
|
||||
value: mongodb/prod/
|
||||
|
||||
- it: keeps a prefix without a trailing slash as given
|
||||
release:
|
||||
name: test-mongodb
|
||||
namespace: tenant-test
|
||||
set:
|
||||
bootstrap:
|
||||
enabled: true
|
||||
backupName: "backup"
|
||||
backup:
|
||||
destinationPath: "s3://mybucket/mongodb/prod"
|
||||
endpointURL: "http://minio:9000"
|
||||
s3AccessKey: "access"
|
||||
s3SecretKey: "secret"
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.backupSource.s3.prefix
|
||||
value: mongodb/prod
|
||||
- equal:
|
||||
path: spec.backupSource.destination
|
||||
value: s3://mybucket/mongodb/prod/backup
|
||||
|
||||
- it: sets an empty prefix when destinationPath is the bucket root
|
||||
release:
|
||||
name: test-mongodb
|
||||
namespace: tenant-test
|
||||
set:
|
||||
bootstrap:
|
||||
enabled: true
|
||||
backupName: "backup"
|
||||
backup:
|
||||
destinationPath: "s3://mybucket"
|
||||
endpointURL: "http://minio:9000"
|
||||
s3AccessKey: "access"
|
||||
s3SecretKey: "secret"
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.backupSource.s3.bucket
|
||||
value: mybucket
|
||||
- equal:
|
||||
path: spec.backupSource.s3.prefix
|
||||
value: ""
|
||||
- equal:
|
||||
path: spec.backupSource.destination
|
||||
value: s3://mybucket/backup
|
||||
|
||||
- it: keeps a numeric bucket and prefix as strings
|
||||
release:
|
||||
name: test-mongodb
|
||||
namespace: tenant-test
|
||||
set:
|
||||
bootstrap:
|
||||
enabled: true
|
||||
backupName: "backup"
|
||||
backup:
|
||||
destinationPath: "s3://2024/10"
|
||||
endpointURL: "http://minio:9000"
|
||||
s3AccessKey: "access"
|
||||
s3SecretKey: "secret"
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.backupSource.s3.bucket
|
||||
value: "2024"
|
||||
- equal:
|
||||
path: spec.backupSource.s3.prefix
|
||||
value: "10"
|
||||
|
||||
- it: fails when destinationPath names no bucket
|
||||
release:
|
||||
name: test-mongodb
|
||||
namespace: tenant-test
|
||||
set:
|
||||
bootstrap:
|
||||
enabled: true
|
||||
backupName: "backup"
|
||||
backup:
|
||||
destinationPath: "s3://"
|
||||
endpointURL: "http://minio:9000"
|
||||
s3AccessKey: "access"
|
||||
s3SecretKey: "secret"
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: "backup.destinationPath must name a bucket (s3://bucket/path/) when bootstrap.enabled is true"
|
||||
|
||||
- it: does not check the bucket when bootstrap is disabled
|
||||
release:
|
||||
name: test-mongodb
|
||||
namespace: tenant-test
|
||||
set:
|
||||
bootstrap:
|
||||
enabled: false
|
||||
backup:
|
||||
destinationPath: "s3://"
|
||||
asserts:
|
||||
- hasDocuments:
|
||||
count: 0
|
||||
|
||||
#####################
|
||||
# PITR #
|
||||
#####################
|
||||
|
||||
Reference in new issue
Block a user