mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-01-03 11:45:20 +00:00
Refactor BSL related code (#2870)
* Refactor BSL related code Signed-off-by: Carlisia <carlisia@vmware.com> * Increase # of max concurrent reconciles Signed-off-by: Carlisia <carlisia@vmware.com> * Clean up for better, more precise interfaces Signed-off-by: Carlisia <carlisia@vmware.com> * Minor clean up - code reviews Signed-off-by: Carlisia <carlisia@vmware.com> * Address code review Signed-off-by: Carlisia <carlisia@vmware.com> * Add import and fix CI Signed-off-by: Carlisia <carlisia@vmware.com>
This commit is contained in:
committed by
GitHub
parent
b5edac3c83
commit
be1cd03023
92
internal/storage/storagelocation.go
Normal file
92
internal/storage/storagelocation.go
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
Copyright 2020 the Velero contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
)
|
||||
|
||||
// DefaultBackupLocationInfo holds server default backup storage location information
|
||||
type DefaultBackupLocationInfo struct {
|
||||
// StorageLocation is the name of the backup storage location designated as the default
|
||||
StorageLocation string
|
||||
// StoreValidationFrequency is the default validation frequency for any backup storage location
|
||||
StoreValidationFrequency time.Duration
|
||||
}
|
||||
|
||||
// IsReadyToValidate calculates if a given backup storage location is ready to be validated.
|
||||
//
|
||||
// Rules:
|
||||
// Users can choose a validation frequency per location. This will overrite the server's default value
|
||||
// To skip/stop validation, set the frequency to zero
|
||||
// This will always return "true" for the first attempt at validating a location, regardless of its validation frequency setting
|
||||
// Otherwise, it returns "ready" only when NOW is equal to or after the next validation time
|
||||
// (next validation time: last validation time + validation frequency)
|
||||
func IsReadyToValidate(bslValidationFrequency *metav1.Duration, lastValidationTime *metav1.Time, defaultLocationInfo DefaultBackupLocationInfo, log logrus.FieldLogger) bool {
|
||||
validationFrequency := defaultLocationInfo.StoreValidationFrequency
|
||||
// If the bsl validation frequency is not specifically set, skip this block and continue, using the server's default
|
||||
if bslValidationFrequency != nil {
|
||||
validationFrequency = bslValidationFrequency.Duration
|
||||
}
|
||||
|
||||
if validationFrequency == 0 {
|
||||
log.Debug("Validation period for this backup location is set to 0, skipping validation")
|
||||
return false
|
||||
}
|
||||
|
||||
if validationFrequency < 0 {
|
||||
log.Debugf("Validation period must be non-negative, changing from %d to %d", validationFrequency, defaultLocationInfo.StoreValidationFrequency)
|
||||
validationFrequency = defaultLocationInfo.StoreValidationFrequency
|
||||
}
|
||||
|
||||
lastValidation := lastValidationTime
|
||||
if lastValidation != nil { // always ready to validate the first time around, so only even do this check if this has happened before
|
||||
nextValidation := lastValidation.Add(validationFrequency) // next validation time: last validation time + validation frequency
|
||||
if time.Now().UTC().Before(nextValidation) { // ready only when NOW is equal to or after the next validation time
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// ListBackupStorageLocations verifies if there are any backup storage locations.
|
||||
// For all purposes, if either there is an error while attempting to fetch items or
|
||||
// if there are no items an error would be returned since the functioning of the system
|
||||
// would be haulted.
|
||||
func ListBackupStorageLocations(ctx context.Context, kbClient client.Client, namespace string) (velerov1api.BackupStorageLocationList, error) {
|
||||
var locations velerov1api.BackupStorageLocationList
|
||||
if err := kbClient.List(ctx, &locations, &client.ListOptions{
|
||||
Namespace: namespace,
|
||||
}); err != nil {
|
||||
return velerov1api.BackupStorageLocationList{}, err
|
||||
}
|
||||
|
||||
if len(locations.Items) == 0 {
|
||||
return velerov1api.BackupStorageLocationList{}, errors.New("no backup storage locations found")
|
||||
}
|
||||
|
||||
return locations, nil
|
||||
}
|
||||
168
internal/storage/storagelocation_test.go
Normal file
168
internal/storage/storagelocation_test.go
Normal file
@@ -0,0 +1,168 @@
|
||||
/*Copyright 2020 the Velero contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/gomega"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/builder"
|
||||
"github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/scheme"
|
||||
velerotest "github.com/vmware-tanzu/velero/pkg/test"
|
||||
)
|
||||
|
||||
func TestIsReadyToValidate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
bslValidationFrequency *metav1.Duration
|
||||
lastValidationTime *metav1.Time
|
||||
defaultLocationInfo DefaultBackupLocationInfo
|
||||
|
||||
// serverDefaultValidationFrequency time.Duration
|
||||
// backupLocation *velerov1api.BackupStorageLocation
|
||||
ready bool
|
||||
}{
|
||||
{
|
||||
name: "don't validate, since frequency is set to zero",
|
||||
bslValidationFrequency: &metav1.Duration{Duration: 0},
|
||||
defaultLocationInfo: DefaultBackupLocationInfo{
|
||||
StoreValidationFrequency: 0,
|
||||
},
|
||||
ready: false,
|
||||
},
|
||||
{
|
||||
name: "validate as per location setting, as that takes precedence, and always if it has never been validated before regardless of the frequency setting",
|
||||
bslValidationFrequency: &metav1.Duration{Duration: 1 * time.Hour},
|
||||
defaultLocationInfo: DefaultBackupLocationInfo{
|
||||
StoreValidationFrequency: 0,
|
||||
},
|
||||
ready: true,
|
||||
},
|
||||
{
|
||||
name: "don't validate as per location setting, as it is set to zero and that takes precedence",
|
||||
bslValidationFrequency: &metav1.Duration{Duration: 0},
|
||||
defaultLocationInfo: DefaultBackupLocationInfo{
|
||||
StoreValidationFrequency: 1,
|
||||
},
|
||||
ready: false,
|
||||
},
|
||||
{
|
||||
name: "validate as per default setting when location setting is not set",
|
||||
defaultLocationInfo: DefaultBackupLocationInfo{
|
||||
StoreValidationFrequency: 1,
|
||||
},
|
||||
ready: true,
|
||||
},
|
||||
{
|
||||
name: "don't validate when default setting is set to zero and the location setting is not set",
|
||||
defaultLocationInfo: DefaultBackupLocationInfo{
|
||||
StoreValidationFrequency: 0,
|
||||
},
|
||||
ready: false,
|
||||
},
|
||||
{
|
||||
name: "don't validate when now is before the NEXT validation time (validation frequency + last validation time)",
|
||||
bslValidationFrequency: &metav1.Duration{Duration: 1 * time.Second},
|
||||
lastValidationTime: &metav1.Time{Time: time.Now()},
|
||||
defaultLocationInfo: DefaultBackupLocationInfo{
|
||||
StoreValidationFrequency: 0,
|
||||
},
|
||||
ready: false,
|
||||
},
|
||||
{
|
||||
name: "validate when now is equal to the NEXT validation time (validation frequency + last validation time)",
|
||||
bslValidationFrequency: &metav1.Duration{Duration: 1 * time.Second},
|
||||
lastValidationTime: &metav1.Time{Time: time.Now().Add(-1 * time.Second)},
|
||||
defaultLocationInfo: DefaultBackupLocationInfo{
|
||||
StoreValidationFrequency: 0,
|
||||
},
|
||||
ready: true,
|
||||
},
|
||||
{
|
||||
name: "validate when now is after the NEXT validation time (validation frequency + last validation time)",
|
||||
bslValidationFrequency: &metav1.Duration{Duration: 1 * time.Second},
|
||||
lastValidationTime: &metav1.Time{Time: time.Now().Add(-2 * time.Second)},
|
||||
defaultLocationInfo: DefaultBackupLocationInfo{
|
||||
StoreValidationFrequency: 0,
|
||||
},
|
||||
ready: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
log := velerotest.NewLogger()
|
||||
|
||||
g.Expect(IsReadyToValidate(tt.bslValidationFrequency, tt.lastValidationTime, tt.defaultLocationInfo, log)).To(BeIdenticalTo(tt.ready))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestListBackupStorageLocations(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
backupLocations *velerov1api.BackupStorageLocationList
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
name: "1 existing location does not return an error",
|
||||
backupLocations: &velerov1api.BackupStorageLocationList{
|
||||
Items: []velerov1api.BackupStorageLocation{
|
||||
*builder.ForBackupStorageLocation("ns-1", "location-1").Result(),
|
||||
},
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "multiple existing location does not return an error",
|
||||
backupLocations: &velerov1api.BackupStorageLocationList{
|
||||
Items: []velerov1api.BackupStorageLocation{
|
||||
*builder.ForBackupStorageLocation("ns-1", "location-1").Result(),
|
||||
*builder.ForBackupStorageLocation("ns-1", "location-2").Result(),
|
||||
*builder.ForBackupStorageLocation("ns-1", "location-3").Result(),
|
||||
},
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "no existing locations returns an error",
|
||||
backupLocations: &velerov1api.BackupStorageLocationList{},
|
||||
expectError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
client := fake.NewFakeClientWithScheme(scheme.Scheme, tt.backupLocations)
|
||||
if tt.expectError {
|
||||
_, err := ListBackupStorageLocations(context.Background(), client, "ns-1")
|
||||
g.Expect(err).NotTo(BeNil())
|
||||
} else {
|
||||
_, err := ListBackupStorageLocations(context.Background(), client, "ns-1")
|
||||
g.Expect(err).To(BeNil())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user