Skip to content

Commit 2a62af3

Browse files
authored
OAS-10007 Fix race condition in ArangoBackup (#1708)
1 parent 8264471 commit 2a62af3

File tree

4 files changed

+67
-2
lines changed

4 files changed

+67
-2
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
- (Improvement) Better panic handling
1919
- (Feature) PongV1 Integration Service
2020
- (Feature) Custom Gateway image
21+
- (Bugfix) Fix race condition in ArangoBackup
2122

2223
## [1.2.42](https://github.com/arangodb/kube-arangodb/tree/1.2.42) (2024-07-23)
2324
- (Maintenance) Go 1.22.4 & Kubernetes 1.29.6 libraries

pkg/apis/deployment/v2alpha1/deployment_spec_gateway.go

+11-2
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,17 @@ package v2alpha1
2323
import "github.com/arangodb/kube-arangodb/pkg/util"
2424

2525
type DeploymentSpecGateway struct {
26-
Enabled *bool `json:"enabled,omitempty"`
27-
Image *string `json:"image"`
26+
// Enabled setting enables/disables support for gateway in the cluster.
27+
// When enabled, the cluster will contain a number of `gateway` servers.
28+
// +doc/default: false
29+
Enabled *bool `json:"enabled,omitempty"`
30+
31+
// Image is the image to use for the gateway.
32+
// By default, the image is determined by the operator.
33+
Image *string `json:"image"`
2834
}
2935

36+
// IsEnabled returns whether the gateway is enabled.
3037
func (d *DeploymentSpecGateway) IsEnabled() bool {
3138
if d == nil || d.Enabled == nil {
3239
return false
@@ -35,10 +42,12 @@ func (d *DeploymentSpecGateway) IsEnabled() bool {
3542
return *d.Enabled
3643
}
3744

45+
// Validate the given spec
3846
func (d *DeploymentSpecGateway) Validate() error {
3947
return nil
4048
}
4149

50+
// GetImage returns the image to use for the gateway.
4251
func (d *DeploymentSpecGateway) GetImage() string {
4352
return util.TypeOrDefault[string](d.Image)
4453
}

pkg/handlers/backup/handler.go

+8
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,14 @@ func (h *handler) refreshDeployment(deployment *database.ArangoDeployment) error
123123
return err
124124
}
125125

126+
for _, backup := range backups.Items {
127+
switch backup.GetStatus().ArangoBackupState.State {
128+
case backupApi.ArangoBackupStateCreate, backupApi.ArangoBackupStateCreating:
129+
// Skip refreshing backups if they are in creation state
130+
return nil
131+
}
132+
}
133+
126134
existingBackups, err := client.List()
127135
if err != nil {
128136
return err

pkg/handlers/backup/handler_test.go

+47
Original file line numberDiff line numberDiff line change
@@ -129,4 +129,51 @@ func Test_Refresh_Cleanup(t *testing.T) {
129129
require.NoError(t, err)
130130
require.Len(t, backups.Items, 0)
131131
})
132+
133+
t.Run("Do not refresh if backup is creating", func(t *testing.T) {
134+
// Arrange
135+
fakeId := driver.BackupID(uuid.NewUUID())
136+
createBackup := backupApi.ArangoBackup{
137+
138+
ObjectMeta: meta.ObjectMeta{
139+
Name: "backup",
140+
},
141+
Status: backupApi.ArangoBackupStatus{
142+
ArangoBackupState: backupApi.ArangoBackupState{
143+
State: backupApi.ArangoBackupStateCreating,
144+
},
145+
Backup: &backupApi.ArangoBackupDetails{
146+
ID: string(fakeId),
147+
},
148+
},
149+
}
150+
b, err := handler.client.BackupV1().ArangoBackups(tests.FakeNamespace).Create(context.Background(), &createBackup, meta.CreateOptions{})
151+
require.NoError(t, err)
152+
require.NotNil(t, b)
153+
require.Equal(t, backupApi.ArangoBackupStateCreating, b.Status.State)
154+
155+
t.Run("Refresh should not happen if there is Backup in creation state", func(t *testing.T) {
156+
require.NoError(t, handler.refreshDeployment(arangoDeployment))
157+
158+
backups, err := handler.client.BackupV1().ArangoBackups(tests.FakeNamespace).List(context.Background(), meta.ListOptions{})
159+
require.NoError(t, err)
160+
require.Len(t, backups.Items, 1)
161+
require.NotNil(t, backups.Items[0].Status.Backup)
162+
require.EqualValues(t, fakeId, backups.Items[0].Status.Backup.ID)
163+
})
164+
165+
createBackup.Status.State = backupApi.ArangoBackupStateReady
166+
b, err = handler.client.BackupV1().ArangoBackups(tests.FakeNamespace).UpdateStatus(context.Background(), &createBackup, meta.UpdateOptions{})
167+
require.NoError(t, err)
168+
require.NotNil(t, b)
169+
require.Equal(t, backupApi.ArangoBackupStateReady, b.Status.State)
170+
171+
t.Run("Refresh should happen if there is Backup in ready state", func(t *testing.T) {
172+
require.NoError(t, handler.refreshDeployment(arangoDeployment))
173+
174+
backups, err := handler.client.BackupV1().ArangoBackups(tests.FakeNamespace).List(context.Background(), meta.ListOptions{})
175+
require.NoError(t, err)
176+
require.Len(t, backups.Items, 2)
177+
})
178+
})
132179
}

0 commit comments

Comments
 (0)