Skip to content

Commit f29bdaf

Browse files
authored
Override clone s3 bucket path (zalando#487)
Override clone s3 bucket path Add possibility to use a custom s3 bucket path for cloning a cluster from an arbitrary bucket (e.g. from another k8s cluster). For that a new config options is introduced `s3_wal_path`, that should point to a location that spilo would understand.
1 parent ad0b250 commit f29bdaf

File tree

5 files changed

+114
-6
lines changed

5 files changed

+114
-6
lines changed

manifests/complete-postgres-manifest.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ spec:
6363
# uid: "efd12e58-5786-11e8-b5a7-06148230260c"
6464
# cluster: "acid-batman"
6565
# timestamp: "2017-12-19T12:40:33+01:00" # timezone required (offset relative to UTC, see RFC 3339 section 5.6)
66+
# s3_wal_path: "s3://custom/path/to/bucket"
6667
maintenanceWindows:
6768
- 01:00-06:00 #UTC
6869
- Sat:00:00-04:00

pkg/apis/acid.zalan.do/v1/postgresql_type.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ type CloneDescription struct {
114114
ClusterName string `json:"cluster,omitempty"`
115115
UID string `json:"uid,omitempty"`
116116
EndTimestamp string `json:"timestamp,omitempty"`
117+
S3WalPath string `json:"s3_wal_path,omitempty"`
117118
}
118119

119120
// Sidecar defines a container to be run in the same pod as the Postgres container.

pkg/apis/acid.zalan.do/v1/util_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,12 @@ var cloneClusterDescriptions = []struct {
6161
in *CloneDescription
6262
err error
6363
}{
64-
{&CloneDescription{"foo+bar", "", "NotEmpty"}, nil},
65-
{&CloneDescription{"foo+bar", "", ""},
64+
{&CloneDescription{"foo+bar", "", "NotEmpty", ""}, nil},
65+
{&CloneDescription{"foo+bar", "", "", ""},
6666
errors.New(`clone cluster name must confirm to DNS-1035, regex used for validation is "^[a-z]([-a-z0-9]*[a-z0-9])?$"`)},
67-
{&CloneDescription{"foobar123456789012345678901234567890123456789012345678901234567890", "", ""},
67+
{&CloneDescription{"foobar123456789012345678901234567890123456789012345678901234567890", "", "", ""},
6868
errors.New("clone cluster name must be no longer than 63 characters")},
69-
{&CloneDescription{"foobar", "", ""}, nil},
69+
{&CloneDescription{"foobar", "", "", ""}, nil},
7070
}
7171

7272
var maintenanceWindows = []struct {

pkg/cluster/k8sres.go

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1216,10 +1216,37 @@ func (c *Cluster) generateCloneEnvironment(description *acidv1.CloneDescription)
12161216
})
12171217
} else {
12181218
// cloning with S3, find out the bucket to clone
1219+
msg := "Clone from S3 bucket"
1220+
c.logger.Info(msg, description.S3WalPath)
1221+
1222+
if description.S3WalPath == "" {
1223+
msg := "Figure out which S3 bucket to use from env"
1224+
c.logger.Info(msg, description.S3WalPath)
1225+
1226+
envs := []v1.EnvVar{
1227+
v1.EnvVar{
1228+
Name: "CLONE_WAL_S3_BUCKET",
1229+
Value: c.OpConfig.WALES3Bucket,
1230+
},
1231+
v1.EnvVar{
1232+
Name: "CLONE_WAL_BUCKET_SCOPE_SUFFIX",
1233+
Value: getBucketScopeSuffix(description.UID),
1234+
},
1235+
}
1236+
1237+
result = append(result, envs...)
1238+
} else {
1239+
msg := "Use custom parsed S3WalPath %s from the manifest"
1240+
c.logger.Warningf(msg, description.S3WalPath)
1241+
1242+
result = append(result, v1.EnvVar{
1243+
Name: "CLONE_WALE_S3_PREFIX",
1244+
Value: description.S3WalPath,
1245+
})
1246+
}
1247+
12191248
result = append(result, v1.EnvVar{Name: "CLONE_METHOD", Value: "CLONE_WITH_WALE"})
1220-
result = append(result, v1.EnvVar{Name: "CLONE_WAL_S3_BUCKET", Value: c.OpConfig.WALES3Bucket})
12211249
result = append(result, v1.EnvVar{Name: "CLONE_TARGET_TIME", Value: description.EndTimestamp})
1222-
result = append(result, v1.EnvVar{Name: "CLONE_WAL_BUCKET_SCOPE_SUFFIX", Value: getBucketScopeSuffix(description.UID)})
12231250
result = append(result, v1.EnvVar{Name: "CLONE_WAL_BUCKET_SCOPE_PREFIX", Value: ""})
12241251
}
12251252

pkg/cluster/k8sres_test.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,3 +129,82 @@ func TestShmVolume(t *testing.T) {
129129
}
130130
}
131131
}
132+
133+
func TestCloneEnv(t *testing.T) {
134+
testName := "TestCloneEnv"
135+
tests := []struct {
136+
subTest string
137+
cloneOpts *acidv1.CloneDescription
138+
env v1.EnvVar
139+
envPos int
140+
}{
141+
{
142+
subTest: "custom s3 path",
143+
cloneOpts: &acidv1.CloneDescription{
144+
ClusterName: "test-cluster",
145+
S3WalPath: "s3://some/path/",
146+
EndTimestamp: "somewhen",
147+
},
148+
env: v1.EnvVar{
149+
Name: "CLONE_WALE_S3_PREFIX",
150+
Value: "s3://some/path/",
151+
},
152+
envPos: 1,
153+
},
154+
{
155+
subTest: "generated s3 path, bucket",
156+
cloneOpts: &acidv1.CloneDescription{
157+
ClusterName: "test-cluster",
158+
EndTimestamp: "somewhen",
159+
UID: "0000",
160+
},
161+
env: v1.EnvVar{
162+
Name: "CLONE_WAL_S3_BUCKET",
163+
Value: "wale-bucket",
164+
},
165+
envPos: 1,
166+
},
167+
{
168+
subTest: "generated s3 path, target time",
169+
cloneOpts: &acidv1.CloneDescription{
170+
ClusterName: "test-cluster",
171+
EndTimestamp: "somewhen",
172+
UID: "0000",
173+
},
174+
env: v1.EnvVar{
175+
Name: "CLONE_TARGET_TIME",
176+
Value: "somewhen",
177+
},
178+
envPos: 4,
179+
},
180+
}
181+
182+
var cluster = New(
183+
Config{
184+
OpConfig: config.Config{
185+
WALES3Bucket: "wale-bucket",
186+
ProtectedRoles: []string{"admin"},
187+
Auth: config.Auth{
188+
SuperUsername: superUserName,
189+
ReplicationUsername: replicationUserName,
190+
},
191+
},
192+
}, k8sutil.KubernetesClient{}, acidv1.Postgresql{}, logger)
193+
194+
for _, tt := range tests {
195+
envs := cluster.generateCloneEnvironment(tt.cloneOpts)
196+
197+
env := envs[tt.envPos]
198+
199+
if env.Name != tt.env.Name {
200+
t.Errorf("%s %s: Expected env name %s, have %s instead",
201+
testName, tt.subTest, tt.env.Name, env.Name)
202+
}
203+
204+
if env.Value != tt.env.Value {
205+
t.Errorf("%s %s: Expected env value %s, have %s instead",
206+
testName, tt.subTest, tt.env.Value, env.Value)
207+
}
208+
209+
}
210+
}

0 commit comments

Comments
 (0)