1
0
Fork 0
mirror of https://github.com/arangodb/kube-arangodb.git synced 2024-12-14 11:57:37 +00:00

[Bugfix] Allow ArangoBackup Creation during Upload state (#1009)

This commit is contained in:
Adam Janikowski 2022-06-14 14:27:58 +02:00 committed by GitHub
parent 1b6f0476c7
commit be8ae2539e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 106 additions and 55 deletions

View file

@ -12,6 +12,7 @@
- (Feature) Set a leader in active fail-over mode - (Feature) Set a leader in active fail-over mode
- (Feature) Use policy/v1 instead policy/v1beta1 - (Feature) Use policy/v1 instead policy/v1beta1
- (Feature) OPS CLI with Arango Task - (Feature) OPS CLI with Arango Task
- (Bugfix) Allow ArangoBackup Creation during Upload state
## [1.2.13](https://github.com/arangodb/kube-arangodb/tree/1.2.13) (2022-06-07) ## [1.2.13](https://github.com/arangodb/kube-arangodb/tree/1.2.13) (2022-06-07)
- (Bugfix) Fix arangosync members state inspection - (Bugfix) Fix arangosync members state inspection

View file

@ -30,12 +30,12 @@ func statePendingHandler(h *handler, backup *backupApi.ArangoBackup) (*backupApi
return nil, err return nil, err
} }
running, err := isBackupRunning(backup, h.client.BackupV1().ArangoBackups(backup.Namespace)) states, err := countBackupStates(backup, h.client.BackupV1().ArangoBackups(backup.Namespace))
if err != nil { if err != nil {
return nil, err return nil, err
} }
if running { if l := states.get(backupApi.ArangoBackupStateScheduled, backupApi.ArangoBackupStateCreate, backupApi.ArangoBackupStateDownload, backupApi.ArangoBackupStateDownloading); len(l) > 0 {
return wrapUpdateStatus(backup, return wrapUpdateStatus(backup,
updateStatusState(backupApi.ArangoBackupStatePending, "backup already in process")) updateStatusState(backupApi.ArangoBackupStatePending, "backup already in process"))
} }

View file

@ -78,6 +78,44 @@ func Test_State_Pending_OneBackupObject(t *testing.T) {
checkBackup(t, newObj, backupApi.ArangoBackupStateScheduled, false) checkBackup(t, newObj, backupApi.ArangoBackupStateScheduled, false)
} }
func Test_State_Pending_WithUploadRunning(t *testing.T) {
// Arrange
handler, _ := newErrorsFakeHandler(mockErrorsArangoClientBackup{})
obj, deployment := newObjectSet(backupApi.ArangoBackupStatePending)
uploading := newArangoBackup(deployment.GetName(), deployment.GetNamespace(), string(uuid.NewUUID()), backupApi.ArangoBackupStateUploading)
// Act
createArangoDeployment(t, handler, deployment)
createArangoBackup(t, handler, obj, uploading)
require.NoError(t, handler.Handle(newItemFromBackup(operation.Update, obj)))
// Assert
newObj := refreshArangoBackup(t, handler, obj)
checkBackup(t, newObj, backupApi.ArangoBackupStateScheduled, false)
}
func Test_State_Pending_WithScheduled(t *testing.T) {
// Arrange
handler, _ := newErrorsFakeHandler(mockErrorsArangoClientBackup{})
obj, deployment := newObjectSet(backupApi.ArangoBackupStatePending)
uploading := newArangoBackup(deployment.GetName(), deployment.GetNamespace(), string(uuid.NewUUID()), backupApi.ArangoBackupStateScheduled)
// Act
createArangoDeployment(t, handler, deployment)
createArangoBackup(t, handler, obj, uploading)
require.NoError(t, handler.Handle(newItemFromBackup(operation.Update, obj)))
// Assert
newObj := refreshArangoBackup(t, handler, obj)
checkBackup(t, newObj, backupApi.ArangoBackupStatePending, false)
}
func Test_State_Pending_MultipleBackupObjectWithLimitation(t *testing.T) { func Test_State_Pending_MultipleBackupObjectWithLimitation(t *testing.T) {
// Arrange // Arrange
handler, _ := newErrorsFakeHandler(mockErrorsArangoClientBackup{}) handler, _ := newErrorsFakeHandler(mockErrorsArangoClientBackup{})

View file

@ -23,6 +23,7 @@ package backup
import ( import (
"github.com/arangodb/go-driver" "github.com/arangodb/go-driver"
backupApi "github.com/arangodb/kube-arangodb/pkg/apis/backup/v1" backupApi "github.com/arangodb/kube-arangodb/pkg/apis/backup/v1"
"github.com/arangodb/kube-arangodb/pkg/util/globals"
) )
func stateReadyHandler(h *handler, backup *backupApi.ArangoBackup) (*backupApi.ArangoBackupStatus, error) { func stateReadyHandler(h *handler, backup *backupApi.ArangoBackup) (*backupApi.ArangoBackupStatus, error) {
@ -71,21 +72,33 @@ func stateReadyHandler(h *handler, backup *backupApi.ArangoBackup) (*backupApi.A
if backup.Spec.Upload != nil && if backup.Spec.Upload != nil &&
(backup.Status.Backup.Uploaded == nil || (backup.Status.Backup.Uploaded != nil && !*backup.Status.Backup.Uploaded)) { (backup.Status.Backup.Uploaded == nil || (backup.Status.Backup.Uploaded != nil && !*backup.Status.Backup.Uploaded)) {
// Ensure that we can start upload process // Ensure that we can start upload process
running, err := isBackupRunning(backup, h.client.BackupV1().ArangoBackups(backup.Namespace)) states, err := countBackupStates(backup, h.client.BackupV1().ArangoBackups(backup.Namespace))
if err != nil { if err != nil {
return nil, err return nil, err
} }
if running { if l := states.get(backupApi.ArangoBackupStateUpload, backupApi.ArangoBackupStateUploading); globals.GetGlobals().Backup().ConcurrentUploads().Get() > len(l) {
return wrapUpdateStatus(backup, // Check if there is no upload with same id
updateStatusState(backupApi.ArangoBackupStateReady, "Upload process queued"), if len(l.filter(func(b *backupApi.ArangoBackup) bool {
updateStatusBackup(backupMeta), if a1 := b.Status.Backup; a1 != nil {
updateStatusAvailable(true), if a2 := backup.Status.Backup; a2 != nil {
) return a1.ID == a2.ID
}
}
return false
})) == 0 {
return wrapUpdateStatus(backup,
updateStatusState(backupApi.ArangoBackupStateUpload, ""),
updateStatusBackup(backupMeta),
updateStatusAvailable(true),
)
}
} }
return wrapUpdateStatus(backup, return wrapUpdateStatus(backup,
updateStatusState(backupApi.ArangoBackupStateUpload, ""), updateStatusState(backupApi.ArangoBackupStateReady, "Upload process queued"),
updateStatusBackup(backupMeta), updateStatusBackup(backupMeta),
updateStatusAvailable(true), updateStatusAvailable(true),
) )

View file

@ -22,9 +22,6 @@ package backup
import ( import (
"context" "context"
"strings"
"github.com/arangodb/kube-arangodb/pkg/util/globals"
clientBackup "github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned/typed/backup/v1" clientBackup "github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned/typed/backup/v1"
@ -34,66 +31,68 @@ import (
"github.com/arangodb/kube-arangodb/pkg/handlers/backup/state" "github.com/arangodb/kube-arangodb/pkg/handlers/backup/state"
) )
var ( type backupStates []*backupApi.ArangoBackup
progressStates = []state.State{
backupApi.ArangoBackupStateScheduled,
backupApi.ArangoBackupStateCreate,
backupApi.ArangoBackupStateDownload,
backupApi.ArangoBackupStateDownloading,
backupApi.ArangoBackupStateUpload,
backupApi.ArangoBackupStateUploading,
}
)
func inProgress(backup *backupApi.ArangoBackup) bool { func (b backupStates) filter(f func(b *backupApi.ArangoBackup) bool) backupStates {
for _, state := range progressStates { if f == nil {
if state == backup.Status.State { return nil
return true }
r := make(backupStates, 0, len(b))
for id := range b {
if f(b[id]) {
r = append(r, b[id])
} }
} }
return false return r
} }
func isBackupRunning(backup *backupApi.ArangoBackup, client clientBackup.ArangoBackupInterface) (bool, error) { type backupStatesCount map[state.State]backupStates
func (b backupStatesCount) get(states ...state.State) backupStates {
i := 0
for _, s := range states {
i += len(b[s])
}
if i == 0 {
return nil
}
r := make(backupStates, 0, i)
for _, s := range states {
r = append(r, b[s]...)
}
return r
}
func countBackupStates(backup *backupApi.ArangoBackup, client clientBackup.ArangoBackupInterface) (backupStatesCount, error) {
backups, err := client.List(context.Background(), meta.ListOptions{}) backups, err := client.List(context.Background(), meta.ListOptions{})
if err != nil { if err != nil {
return false, newTemporaryError(err) return nil, newTemporaryError(err)
} }
currentUploads := 0 ret := map[state.State]backupStates{}
for _, existingBackup := range backups.Items { for _, existingBackup := range backups.Items {
// Skip same backup from count
if existingBackup.Name == backup.Name { if existingBackup.Name == backup.Name {
continue continue
} }
// We can upload multiple uploads from same deployment in same time // Skip backups which are not on same deployment from count
if backup.Status.State == backupApi.ArangoBackupStateReady && if existingBackup.Spec.Deployment.Name != backup.Spec.Deployment.Name {
(existingBackup.Status.State == backupApi.ArangoBackupStateUpload || existingBackup.Status.State == backupApi.ArangoBackupStateUploading) { continue
currentUploads++
if backupUpload := backup.Status.Backup; backupUpload != nil {
if existingBackupUpload := existingBackup.Status.Backup; existingBackupUpload != nil {
if strings.EqualFold(backupUpload.ID, existingBackupUpload.ID) {
return true, nil
}
}
}
} else {
if existingBackup.Spec.Deployment.Name != backup.Spec.Deployment.Name {
continue
}
if inProgress(&existingBackup) {
return true, nil
}
} }
ret[existingBackup.Status.State] = append(ret[existingBackup.Status.State], existingBackup.DeepCopy())
} }
if backup.Status.State == backupApi.ArangoBackupStateReady { return ret, nil
return currentUploads >= globals.GetGlobals().Backup().ConcurrentUploads().Get(), nil
}
return false, nil
} }