Skip to content

Commit ae8a01d

Browse files
authored
STAC-23601: Delete ES snapshot repository before configuring it (#20)
1 parent 36a2ecc commit ae8a01d

4 files changed

Lines changed: 73 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: 42 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(_ 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
@@ -260,32 +270,51 @@ minio:
260270
}
261271

262272
// TestMockESClientForConfigure demonstrates mock usage for configure
273+
//
274+
//nolint:funlen // Table-driven test
263275
func TestMockESClientForConfigure(t *testing.T) {
264276
tests := []struct {
265277
name string
278+
deleteRepoErr error
266279
configureRepoErr error
267280
configureSLMErr error
281+
expectDeleteOK bool
268282
expectRepoOK bool
269283
expectSLMOK bool
270284
}{
271285
{
272286
name: "successful configuration",
287+
deleteRepoErr: nil,
273288
configureRepoErr: nil,
274289
configureSLMErr: nil,
290+
expectDeleteOK: true,
275291
expectRepoOK: true,
276292
expectSLMOK: true,
277293
},
294+
{
295+
name: "repository deletion fails",
296+
deleteRepoErr: fmt.Errorf("repository deletion failed"),
297+
configureRepoErr: nil,
298+
configureSLMErr: nil,
299+
expectDeleteOK: false,
300+
expectRepoOK: false,
301+
expectSLMOK: false,
302+
},
278303
{
279304
name: "repository configuration fails",
305+
deleteRepoErr: nil,
280306
configureRepoErr: fmt.Errorf("repository creation failed"),
281307
configureSLMErr: nil,
308+
expectDeleteOK: true,
282309
expectRepoOK: false,
283310
expectSLMOK: false,
284311
},
285312
{
286313
name: "SLM configuration fails",
314+
deleteRepoErr: nil,
287315
configureRepoErr: nil,
288316
configureSLMErr: fmt.Errorf("SLM policy creation failed"),
317+
expectDeleteOK: true,
289318
expectRepoOK: true,
290319
expectSLMOK: false,
291320
},
@@ -294,12 +323,24 @@ func TestMockESClientForConfigure(t *testing.T) {
294323
for _, tt := range tests {
295324
t.Run(tt.name, func(t *testing.T) {
296325
mockClient := &mockESClientForConfigure{
326+
deleteRepoErr: tt.deleteRepoErr,
297327
configureRepoErr: tt.configureRepoErr,
298328
configureSLMErr: tt.configureSLMErr,
299329
}
300330

331+
// Delete repository
332+
err := mockClient.DeleteSnapshotRepository("backup-repo")
333+
334+
if tt.expectDeleteOK {
335+
assert.NoError(t, err)
336+
assert.True(t, mockClient.repoDeleted)
337+
} else {
338+
assert.Error(t, err)
339+
return // Don't test configure if delete failed
340+
}
341+
301342
// Configure repository
302-
err := mockClient.ConfigureSnapshotRepository(
343+
err = mockClient.ConfigureSnapshotRepository(
303344
"backup-repo",
304345
"backup-bucket",
305346
"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)