Skip to content

Commit 5dfb314

Browse files
committed
STAC-23601: Delete ES snapshot repository before configuring it
1 parent 36a2ecc commit 5dfb314

4 files changed

Lines changed: 71 additions & 1 deletion

File tree

cmd/elasticsearch/configure.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ func runConfigure(appCtx *app.Context) error {
4040

4141
// Configure snapshot repository
4242
repo := appCtx.Config.Elasticsearch.SnapshotRepository
43+
44+
// Always unregister existing repository to ensure clean state
45+
appCtx.Logger.Infof("Unregistering snapshot repository '%s'...", repo.Name)
46+
if err := appCtx.ESClient.DeleteSnapshotRepository(repo.Name); err != nil {
47+
return fmt.Errorf("failed to unregister snapshot repository: %w", err)
48+
}
49+
appCtx.Logger.Successf("Snapshot repository unregistered successfully")
50+
4351
appCtx.Logger.Infof("Configuring snapshot repository '%s' (bucket: %s)...", repo.Name, repo.Bucket)
4452

4553
err = appCtx.ESClient.ConfigureSnapshotRepository(

cmd/elasticsearch/configure_test.go

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,24 @@ import (
1616

1717
// mockESClientForConfigure is a mock for testing configure command
1818
type mockESClientForConfigure struct {
19+
deleteRepoErr error
1920
configureRepoErr error
2021
configureSLMErr error
22+
repoDeleted bool
2123
repoConfigured bool
2224
slmConfigured bool
2325
lastRepoConfig map[string]string
2426
lastSLMConfig map[string]interface{}
2527
}
2628

29+
func (m *mockESClientForConfigure) DeleteSnapshotRepository(name string) error {
30+
if m.deleteRepoErr != nil {
31+
return m.deleteRepoErr
32+
}
33+
m.repoDeleted = true
34+
return nil
35+
}
36+
2737
func (m *mockESClientForConfigure) ConfigureSnapshotRepository(name, bucket, endpoint, basePath, accessKey, secretKey string) error {
2838
if m.configureRepoErr != nil {
2939
return m.configureRepoErr
@@ -263,29 +273,46 @@ minio:
263273
func TestMockESClientForConfigure(t *testing.T) {
264274
tests := []struct {
265275
name string
276+
deleteRepoErr error
266277
configureRepoErr error
267278
configureSLMErr error
279+
expectDeleteOK bool
268280
expectRepoOK bool
269281
expectSLMOK bool
270282
}{
271283
{
272284
name: "successful configuration",
285+
deleteRepoErr: nil,
273286
configureRepoErr: nil,
274287
configureSLMErr: nil,
288+
expectDeleteOK: true,
275289
expectRepoOK: true,
276290
expectSLMOK: true,
277291
},
292+
{
293+
name: "repository deletion fails",
294+
deleteRepoErr: fmt.Errorf("repository deletion failed"),
295+
configureRepoErr: nil,
296+
configureSLMErr: nil,
297+
expectDeleteOK: false,
298+
expectRepoOK: false,
299+
expectSLMOK: false,
300+
},
278301
{
279302
name: "repository configuration fails",
303+
deleteRepoErr: nil,
280304
configureRepoErr: fmt.Errorf("repository creation failed"),
281305
configureSLMErr: nil,
306+
expectDeleteOK: true,
282307
expectRepoOK: false,
283308
expectSLMOK: false,
284309
},
285310
{
286311
name: "SLM configuration fails",
312+
deleteRepoErr: nil,
287313
configureRepoErr: nil,
288314
configureSLMErr: fmt.Errorf("SLM policy creation failed"),
315+
expectDeleteOK: true,
289316
expectRepoOK: true,
290317
expectSLMOK: false,
291318
},
@@ -294,12 +321,24 @@ func TestMockESClientForConfigure(t *testing.T) {
294321
for _, tt := range tests {
295322
t.Run(tt.name, func(t *testing.T) {
296323
mockClient := &mockESClientForConfigure{
324+
deleteRepoErr: tt.deleteRepoErr,
297325
configureRepoErr: tt.configureRepoErr,
298326
configureSLMErr: tt.configureSLMErr,
299327
}
300328

329+
// Delete repository
330+
err := mockClient.DeleteSnapshotRepository("backup-repo")
331+
332+
if tt.expectDeleteOK {
333+
assert.NoError(t, err)
334+
assert.True(t, mockClient.repoDeleted)
335+
} else {
336+
assert.Error(t, err)
337+
return // Don't test configure if delete failed
338+
}
339+
301340
// Configure repository
302-
err := mockClient.ConfigureSnapshotRepository(
341+
err = mockClient.ConfigureSnapshotRepository(
303342
"backup-repo",
304343
"backup-bucket",
305344
"minio:9000",

internal/clients/elasticsearch/client.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,28 @@ func (c *Client) RolloverDatastream(datastreamName string) error {
247247
return nil
248248
}
249249

250+
// DeleteSnapshotRepository deletes a snapshot repository
251+
func (c *Client) DeleteSnapshotRepository(name string) error {
252+
res, err := c.es.Snapshot.DeleteRepository(
253+
[]string{name},
254+
c.es.Snapshot.DeleteRepository.WithContext(context.Background()),
255+
)
256+
if err != nil {
257+
return fmt.Errorf("failed to delete snapshot repository: %w", err)
258+
}
259+
defer res.Body.Close()
260+
261+
if res.StatusCode == http.StatusNotFound {
262+
return nil // Repository doesn't exist, which is fine
263+
}
264+
265+
if res.IsError() {
266+
return fmt.Errorf("elasticsearch returned error: %s", res.String())
267+
}
268+
269+
return nil
270+
}
271+
250272
// ConfigureSnapshotRepository configures an S3 snapshot repository
251273
func (c *Client) ConfigureSnapshotRepository(name, bucket, endpoint, basePath, accessKey, secretKey string) error {
252274
body := map[string]interface{}{

internal/clients/elasticsearch/interface.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ type Interface interface {
1919
RolloverDatastream(datastreamName string) error
2020

2121
// Repository and SLM operations
22+
DeleteSnapshotRepository(name string) error
2223
ConfigureSnapshotRepository(name, bucket, endpoint, basePath, accessKey, secretKey string) error
2324
ConfigureSLMPolicy(name, schedule, snapshotName, repository, indices, expireAfter string, minCount, maxCount int) error
2425
}

0 commit comments

Comments
 (0)