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

GT-350 Backup lifetime - remove Backup once its lifetime has been reached (#1262)

This commit is contained in:
jwierzbo 2023-07-17 14:43:54 +02:00 committed by GitHub
parent 87f558fae4
commit 34ae2c0f82
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 139 additions and 9 deletions

View file

@ -1,6 +1,7 @@
# Change Log
## [master](https://github.com/arangodb/kube-arangodb/tree/master) (N/A)
- (Feature) Backup lifetime - remove Backup once its lifetime has been reached
## [1.2.31](https://github.com/arangodb/kube-arangodb/tree/1.2.31) (2023-07-14)
- (Improvement) Block traffic on the services if there is more than 1 active leader in ActiveFailover mode

View file

@ -18,8 +18,9 @@
- [Operator API](./api.md)
- [Logging](./logging.md)
- [Manual Recovery](./recovery.md)
- [Backup](./backup.md)
## Features
- [Force rebuild out-synced Shards with broken Merkle Tree](./features/rebuild_out_synced_shards.md)
- [Failover Leader service](./features/failover_leader_service.md)
- [Restore defaults from last accepted state of deployment](./features/deployment_spec_defaults.md)
- [Restore defaults from last accepted state of deployment](./features/deployment_spec_defaults.md)

59
docs/design/backup.md Normal file
View file

@ -0,0 +1,59 @@
# ArangoBackup
## Lifetime
The Lifetime of an ArangoBackup let us define the time an ArangoBackup is available in the system.
E.g.: if we want to keep the ArangoBackup for 1 day, we can set the Lifetime to 1 day. After 1 day the ArangoBackup will be deleted automatically.
```yaml
apiVersion: "backup.arangodb.com/v1alpha"
kind: "ArangoBackup"
metadata:
name: backup-with-one-day-lifetime
spec:
deployment:
name: deployment
lifetime: 1d
```
## Upload
You can upload the backup to a remote storage.
Here is an example for uploading the backup to AWS S3.
```yaml
apiVersion: "backup.arangodb.com/v1alpha"
kind: "ArangoBackup"
metadata:
name: backup-and-upload
spec:
deployment:
name: deployment
upload:
repositoryURL: "s3:BUCKET_NAME"
credentialsSecretName: upload-credentials
```
To make this work, you need to create a `upload-credentials` Secret with the credentials for the remote storage:
```yaml
apiVersion: v1
kind: Secret
metadata:
name: upload-credentials
type: Opaque
stringData:
token: |
{
"s3": {
"type": "s3",
"provider": "AWS",
"env_auth": "false",
"region": "eu-central-1",
"access_key_id": "ACCESS_KEY_ID",
"secret_access_key": "SECRECT_ACCESS_KEY",
"acl": "private",
"no_check_bucket": "true"
}
}
```

View file

@ -20,7 +20,7 @@ By default, operator logs in `pretty` format.
To switch logging format to the JSON, you can use `operator.args` in chart template value:
```yaml
operator:
args: ["--log.format=pretty"]
args: ["--log.format=json"]
```
## ArangoDeployment logging

View file

@ -1,7 +1,7 @@
//
// DISCLAIMER
//
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -20,6 +20,8 @@
package v1
import meta "k8s.io/apimachinery/pkg/apis/meta/v1"
type ArangoBackupSpec struct {
// Deployment
Deployment ArangoBackupSpecDeployment `json:"deployment,omitempty"`
@ -35,6 +37,9 @@ type ArangoBackupSpec struct {
PolicyName *string `json:"policyName,omitempty"`
Backoff *ArangoBackupSpecBackOff `json:"backoff,omitempty"`
// Lifetime is the time after which the backup will be deleted. Format: "1.5h" or "2h45m".
Lifetime *meta.Duration `json:"lifetime,omitempty"`
}
type ArangoBackupSpecDeployment struct {

View file

@ -45,7 +45,7 @@ const (
)
var ArangoBackupStateMap = state.Map{
ArangoBackupStateNone: {ArangoBackupStatePending},
ArangoBackupStateNone: {ArangoBackupStatePending, ArangoBackupStateFailed},
ArangoBackupStatePending: {ArangoBackupStateScheduled, ArangoBackupStateFailed},
ArangoBackupStateScheduled: {ArangoBackupStateDownload, ArangoBackupStateCreate, ArangoBackupStateFailed},
ArangoBackupStateDownload: {ArangoBackupStateDownloading, ArangoBackupStateFailed, ArangoBackupStateDownloadError},

View file

@ -1,7 +1,7 @@
//
// DISCLAIMER
//
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -20,7 +20,9 @@
package v1
import "github.com/arangodb/kube-arangodb/pkg/util/errors"
import (
"github.com/arangodb/kube-arangodb/pkg/util/errors"
)
func (a *ArangoBackup) Validate() error {
if err := a.Spec.Validate(); err != nil {

View file

@ -284,6 +284,11 @@ func (in *ArangoBackupSpec) DeepCopyInto(out *ArangoBackupSpec) {
*out = new(ArangoBackupSpecBackOff)
(*in).DeepCopyInto(*out)
}
if in.Lifetime != nil {
in, out := &in.Lifetime, &out.Lifetime
*out = new(metav1.Duration)
**out = **in
}
return
}

View file

@ -1,7 +1,7 @@
//
// DISCLAIMER
//
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -21,6 +21,8 @@
package backup
import (
"time"
"github.com/arangodb/go-driver"
backupApi "github.com/arangodb/kube-arangodb/pkg/apis/backup/v1"
@ -56,6 +58,20 @@ func stateReadyHandler(h *handler, backup *backupApi.ArangoBackup) (*backupApi.A
)
}
if backup.Spec.Lifetime != nil {
if backupMeta.DateTime.Add(backup.Spec.Lifetime.Duration).Before(time.Now()) {
err = client.Delete(driver.BackupID(backup.Status.Backup.ID))
if err != nil {
return nil, err
}
return wrapUpdateStatus(backup,
updateStatusState(backupApi.ArangoBackupStateDeleted, "Backup expired by lifetime"),
updateStatusAvailable(false),
)
}
}
var available = backupMeta.Available
// Temporally check if number of db servers match number of pieces

View file

@ -23,8 +23,10 @@ package backup
import (
"sync"
"testing"
"time"
"github.com/stretchr/testify/require"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/uuid"
"github.com/arangodb/go-driver"
@ -66,6 +68,45 @@ func Test_State_Ready_Success(t *testing.T) {
compareBackupMeta(t, backupMeta, newObj)
}
func Test_State_Ready_With_Lifetime(t *testing.T) {
// Arrange
handler, mock := newErrorsFakeHandler(mockErrorsArangoClientBackup{})
obj, deployment := newObjectSet(backupApi.ArangoBackupStateReady)
obj.Spec.Lifetime = &meta.Duration{Duration: 5 * time.Second}
createResponse, err := mock.Create()
require.NoError(t, err)
backupMeta, err := mock.Get(createResponse.ID)
require.NoError(t, err)
obj.Status.Backup = createBackupFromMeta(backupMeta, nil)
// Act
createArangoDeployment(t, handler, deployment)
createArangoBackup(t, handler, obj)
t.Run("First iteration", func(t *testing.T) {
require.NoError(t, handler.Handle(newItemFromBackup(operation.Update, obj)))
// Assert
newObj := refreshArangoBackup(t, handler, obj)
checkBackup(t, newObj, backupApi.ArangoBackupStateReady, true)
compareBackupMeta(t, backupMeta, newObj)
})
t.Run("Second iteration once Lifetime is expired", func(t *testing.T) {
time.Sleep(10 * time.Second)
require.NoError(t, handler.Handle(newItemFromBackup(operation.Update, obj)))
// Assert
newObj := refreshArangoBackup(t, handler, obj)
checkBackup(t, newObj, backupApi.ArangoBackupStateDeleted, false)
compareBackupMeta(t, backupMeta, newObj)
})
}
func Test_State_Ready_Unavailable(t *testing.T) {
// Arrange
handler, mock := newErrorsFakeHandler(mockErrorsArangoClientBackup{})

View file

@ -1,7 +1,7 @@
//
// DISCLAIMER
//
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -61,7 +61,7 @@ func (o *operator) processNextItem() bool {
err := o.processObject(obj)
if err != nil {
loggerWorker.Interface("object", obj).Error("Error during object handling")
loggerWorker.Interface("object", obj).Error("Error during object handling: %v", err)
return true
}