mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-07-20 06:52:40 +00:00
Merge pull request #6771 from qiuming-best/bsl-fix
Fix default BSL setting not work
This commit is contained in:
@@ -92,11 +92,8 @@ func (r *backupStorageLocationReconciler) Reconcile(ctx context.Context, req ctr
|
||||
pluginManager := r.newPluginManager(log)
|
||||
defer pluginManager.CleanupClients()
|
||||
|
||||
var defaultFound bool
|
||||
// find the BSL that matches the request
|
||||
for _, bsl := range locationList.Items {
|
||||
if bsl.Spec.Default {
|
||||
defaultFound = true
|
||||
}
|
||||
if bsl.Name == req.Name && bsl.Namespace == req.Namespace {
|
||||
location = bsl
|
||||
}
|
||||
@@ -107,15 +104,11 @@ func (r *backupStorageLocationReconciler) Reconcile(ctx context.Context, req ctr
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
isDefault := location.Spec.Default
|
||||
|
||||
// TODO(2.0) remove this check since the server default will be deprecated
|
||||
if !defaultFound && location.Name == r.defaultBackupLocationInfo.StorageLocation {
|
||||
// For backward-compatible, to configure the backup storage location as the default if
|
||||
// none of the BSLs be marked as the default and the BSL name matches against the
|
||||
// "velero server --default-backup-storage-location".
|
||||
isDefault = true
|
||||
defaultFound = true
|
||||
// decide the default BSL
|
||||
defaultFound, err := r.ensureSingleDefaultBSL(locationList)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("failed to ensure single default bsl")
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
func() {
|
||||
@@ -151,9 +144,6 @@ func (r *backupStorageLocationReconciler) Reconcile(ctx context.Context, req ctr
|
||||
log.WithError(err).Error("fail to validate backup store")
|
||||
return
|
||||
}
|
||||
|
||||
// updates the default backup location
|
||||
location.Spec.Default = isDefault
|
||||
}()
|
||||
|
||||
r.logReconciledPhase(defaultFound, locationList, unavailableErrors)
|
||||
@@ -216,3 +206,72 @@ func (r *backupStorageLocationReconciler) SetupWithManager(mgr ctrl.Manager) err
|
||||
Watches(g, nil, builder.WithPredicates(gp)).
|
||||
Complete(r)
|
||||
}
|
||||
|
||||
// ensureSingleDefaultBSL ensures that there is only one default BSL in the namespace.
|
||||
// the default BSL priority is as follows:
|
||||
// 1. follow the user's setting (the most recent validation BSL is the default BSL)
|
||||
// 2. follow the server's setting ("velero server --default-backup-storage-location")
|
||||
func (r *backupStorageLocationReconciler) ensureSingleDefaultBSL(locationList velerov1api.BackupStorageLocationList) (bool, error) {
|
||||
// get all default BSLs
|
||||
var defaultBSLs []*velerov1api.BackupStorageLocation
|
||||
var defaultFound bool
|
||||
for i, location := range locationList.Items {
|
||||
if location.Spec.Default {
|
||||
defaultBSLs = append(defaultBSLs, &locationList.Items[i])
|
||||
}
|
||||
}
|
||||
|
||||
if len(defaultBSLs) > 1 { // more than 1 default BSL
|
||||
// find the most recent updated default BSL
|
||||
var mostRecentCreatedBSL *velerov1api.BackupStorageLocation
|
||||
defaultFound = true
|
||||
for _, bsl := range defaultBSLs {
|
||||
if mostRecentCreatedBSL == nil {
|
||||
mostRecentCreatedBSL = bsl
|
||||
continue
|
||||
}
|
||||
// For lack of a better way to compare timestamps, we use the CreationTimestamp
|
||||
// it cloud not really find the most recent updated BSL, but it is good enough for now
|
||||
bslTimestamp := bsl.CreationTimestamp
|
||||
mostRecentTimestamp := mostRecentCreatedBSL.CreationTimestamp
|
||||
if mostRecentTimestamp.Before(&bslTimestamp) {
|
||||
mostRecentCreatedBSL = bsl
|
||||
}
|
||||
}
|
||||
|
||||
// unset all other default BSLs
|
||||
for _, bsl := range defaultBSLs {
|
||||
if bsl.Name != mostRecentCreatedBSL.Name {
|
||||
bsl.Spec.Default = false
|
||||
if err := r.client.Update(r.ctx, bsl); err != nil {
|
||||
return defaultFound, errors.Wrapf(err, "failed to unset default backup storage location %q", bsl.Name)
|
||||
}
|
||||
r.log.Debugf("update default backup storage location %q to false", bsl.Name)
|
||||
}
|
||||
}
|
||||
} else if len(defaultBSLs) == 0 { // no default BSL
|
||||
// find the BSL that matches the "velero server --default-backup-storage-location"
|
||||
var defaultBSL *velerov1api.BackupStorageLocation
|
||||
for i, location := range locationList.Items {
|
||||
if location.Name == r.defaultBackupLocationInfo.StorageLocation {
|
||||
defaultBSL = &locationList.Items[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// set the default BSL
|
||||
if defaultBSL != nil {
|
||||
defaultBSL.Spec.Default = true
|
||||
defaultFound = true
|
||||
if err := r.client.Update(r.ctx, defaultBSL); err != nil {
|
||||
return defaultFound, errors.Wrapf(err, "failed to set default backup storage location %q", defaultBSL.Name)
|
||||
}
|
||||
r.log.Debugf("update default backup storage location %q to true", defaultBSL.Name)
|
||||
} else {
|
||||
defaultFound = false
|
||||
}
|
||||
} else { // only 1 default BSL
|
||||
defaultFound = true
|
||||
}
|
||||
return defaultFound, nil
|
||||
}
|
||||
|
||||
@@ -17,12 +17,15 @@ limitations under the License.
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
@@ -172,3 +175,125 @@ var _ = Describe("Backup Storage Location Reconciler", func() {
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
func TestEnsureSingleDefaultBSL(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
locations velerov1api.BackupStorageLocationList
|
||||
defaultBackupInfo storage.DefaultBackupLocationInfo
|
||||
expectedDefaultSet bool
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "MultipleDefaults",
|
||||
locations: func() velerov1api.BackupStorageLocationList {
|
||||
var locations velerov1api.BackupStorageLocationList
|
||||
locations.Items = append(locations.Items, *builder.ForBackupStorageLocation(velerov1api.DefaultNamespace, "location-1").LastValidationTime(time.Now()).Default(true).Result())
|
||||
locations.Items = append(locations.Items, *builder.ForBackupStorageLocation(velerov1api.DefaultNamespace, "location-2").LastValidationTime(time.Now().Add(-1 * time.Hour)).Default(true).Result())
|
||||
return locations
|
||||
}(),
|
||||
expectedDefaultSet: true,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "NoDefault with exist default bsl in defaultBackupInfo",
|
||||
locations: func() velerov1api.BackupStorageLocationList {
|
||||
var locations velerov1api.BackupStorageLocationList
|
||||
locations.Items = append(locations.Items, *builder.ForBackupStorageLocation(velerov1api.DefaultNamespace, "location-1").Default(false).Result())
|
||||
locations.Items = append(locations.Items, *builder.ForBackupStorageLocation(velerov1api.DefaultNamespace, "location-2").Default(false).Result())
|
||||
return locations
|
||||
}(),
|
||||
defaultBackupInfo: storage.DefaultBackupLocationInfo{
|
||||
StorageLocation: "location-2",
|
||||
},
|
||||
expectedDefaultSet: true,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "NoDefault with non-exist default bsl in defaultBackupInfo",
|
||||
locations: func() velerov1api.BackupStorageLocationList {
|
||||
var locations velerov1api.BackupStorageLocationList
|
||||
locations.Items = append(locations.Items, *builder.ForBackupStorageLocation(velerov1api.DefaultNamespace, "location-1").Default(false).Result())
|
||||
locations.Items = append(locations.Items, *builder.ForBackupStorageLocation(velerov1api.DefaultNamespace, "location-2").Default(false).Result())
|
||||
return locations
|
||||
}(),
|
||||
defaultBackupInfo: storage.DefaultBackupLocationInfo{
|
||||
StorageLocation: "location-3",
|
||||
},
|
||||
expectedDefaultSet: false,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "SingleDefault",
|
||||
locations: func() velerov1api.BackupStorageLocationList {
|
||||
var locations velerov1api.BackupStorageLocationList
|
||||
locations.Items = append(locations.Items, *builder.ForBackupStorageLocation(velerov1api.DefaultNamespace, "location-1").Default(true).Result())
|
||||
locations.Items = append(locations.Items, *builder.ForBackupStorageLocation(velerov1api.DefaultNamespace, "location-2").Default(false).Result())
|
||||
return locations
|
||||
}(),
|
||||
expectedDefaultSet: true,
|
||||
expectedError: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
// Setup reconciler
|
||||
assert.Nil(t, velerov1api.AddToScheme(scheme.Scheme))
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
r := &backupStorageLocationReconciler{
|
||||
ctx: context.Background(),
|
||||
client: fake.NewClientBuilder().WithScheme(scheme.Scheme).WithRuntimeObjects(&test.locations).Build(),
|
||||
defaultBackupLocationInfo: test.defaultBackupInfo,
|
||||
log: velerotest.NewLogger(),
|
||||
}
|
||||
defaultFound, err := r.ensureSingleDefaultBSL(test.locations)
|
||||
|
||||
assert.Equal(t, test.expectedDefaultSet, defaultFound)
|
||||
assert.Equal(t, test.expectedError, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBSLReconcile(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
locationList velerov1api.BackupStorageLocationList
|
||||
defaultFound bool
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "NoBSL",
|
||||
locationList: velerov1api.BackupStorageLocationList{},
|
||||
defaultFound: false,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "BSLNotFound",
|
||||
locationList: func() velerov1api.BackupStorageLocationList {
|
||||
var locations velerov1api.BackupStorageLocationList
|
||||
locations.Items = append(locations.Items, *builder.ForBackupStorageLocation(velerov1api.DefaultNamespace, "location-2").Result())
|
||||
return locations
|
||||
}(),
|
||||
defaultFound: false,
|
||||
expectedError: nil,
|
||||
},
|
||||
}
|
||||
pluginManager := &pluginmocks.Manager{}
|
||||
pluginManager.On("CleanupClients").Return(nil)
|
||||
for _, test := range tests {
|
||||
// Setup reconciler
|
||||
assert.Nil(t, velerov1api.AddToScheme(scheme.Scheme))
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
r := &backupStorageLocationReconciler{
|
||||
ctx: context.Background(),
|
||||
client: fake.NewClientBuilder().WithScheme(scheme.Scheme).WithRuntimeObjects(&test.locationList).Build(),
|
||||
newPluginManager: func(logrus.FieldLogger) clientmgmt.Manager { return pluginManager },
|
||||
log: velerotest.NewLogger(),
|
||||
}
|
||||
|
||||
result, err := r.Reconcile(context.TODO(), ctrl.Request{NamespacedName: types.NamespacedName{Namespace: velerov1api.DefaultNamespace, Name: "location-1"}})
|
||||
assert.Equal(t, test.expectedError, err)
|
||||
assert.Equal(t, ctrl.Result{}, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user