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:
parent
1b6f0476c7
commit
be8ae2539e
5 changed files with 106 additions and 55 deletions
|
@ -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
|
||||||
|
|
|
@ -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"))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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{})
|
||||||
|
|
|
@ -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),
|
||||||
)
|
)
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue