Merge branch 'main' into vgdp-ms-pvr-data-path
commit
8b7a31b006
|
@ -58,3 +58,8 @@ debug.test*
|
||||||
|
|
||||||
# make lint cache
|
# make lint cache
|
||||||
.cache/
|
.cache/
|
||||||
|
|
||||||
|
# Go telemetry directory created when container sets HOME to working directory
|
||||||
|
# This happens because Makefile uses 'docker run -w /github.com/vmware-tanzu/velero'
|
||||||
|
# and Go's os.UserConfigDir() falls back to $HOME/.config when XDG_CONFIG_HOME is unset
|
||||||
|
.config/
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Skip VS and VSC not created by backup.
|
|
@ -285,7 +285,6 @@ func (p *pvcBackupItemAction) Execute(
|
||||||
vs,
|
vs,
|
||||||
p.crClient,
|
p.crClient,
|
||||||
p.log,
|
p.log,
|
||||||
true,
|
|
||||||
backup.Spec.CSISnapshotTimeout.Duration,
|
backup.Spec.CSISnapshotTimeout.Duration,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -96,22 +96,6 @@ func (p *volumeSnapshotBackupItemAction) Execute(
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// determine if we are backing up a VolumeSnapshot that was created by velero while
|
|
||||||
// performing backup of a CSI backed PVC.
|
|
||||||
// For VolumeSnapshots that were created during the backup of a CSI backed PVC,
|
|
||||||
// we will wait for the VolumeSnapshotContents to be available.
|
|
||||||
// For VolumeSnapshots created outside of velero, we expect the VolumeSnapshotContent
|
|
||||||
// to be available prior to backing up the VolumeSnapshot. In case of a failure,
|
|
||||||
// backup should be re-attempted after the CSI driver has reconciled the VolumeSnapshot.
|
|
||||||
// existence of the velerov1api.BackupNameLabel indicates that the VolumeSnapshot was
|
|
||||||
// created while backing up a CSI backed PVC.
|
|
||||||
|
|
||||||
// We want to await reconciliation of only those VolumeSnapshots created during the
|
|
||||||
// ongoing backup. For this we will wait only if the backup label exists on the
|
|
||||||
// VolumeSnapshot object and the backup name is the same as that of the value of the
|
|
||||||
// backup label.
|
|
||||||
backupOngoing := vs.Labels[velerov1api.BackupNameLabel] == label.GetValidName(backup.Name)
|
|
||||||
|
|
||||||
p.log.Infof("Getting VolumesnapshotContent for Volumesnapshot %s/%s",
|
p.log.Infof("Getting VolumesnapshotContent for Volumesnapshot %s/%s",
|
||||||
vs.Namespace, vs.Name)
|
vs.Namespace, vs.Name)
|
||||||
|
|
||||||
|
@ -119,7 +103,6 @@ func (p *volumeSnapshotBackupItemAction) Execute(
|
||||||
vs,
|
vs,
|
||||||
p.crClient,
|
p.crClient,
|
||||||
p.log,
|
p.log,
|
||||||
backupOngoing,
|
|
||||||
backup.Spec.CSISnapshotTimeout.Duration,
|
backup.Spec.CSISnapshotTimeout.Duration,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -171,42 +154,40 @@ func (p *volumeSnapshotBackupItemAction) Execute(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if backupOngoing {
|
p.log.Infof("Patching VolumeSnapshotContent %s with velero BackupNameLabel",
|
||||||
p.log.Infof("Patching VolumeSnapshotContent %s with velero BackupNameLabel",
|
vsc.Name)
|
||||||
vsc.Name)
|
// If we created the VolumeSnapshotContent object during this ongoing backup,
|
||||||
// If we created the VolumeSnapshotContent object during this ongoing backup,
|
// we would have created it with a DeletionPolicy of Retain.
|
||||||
// we would have created it with a DeletionPolicy of Retain.
|
// But, we want to retain these VolumeSnapshotContent ONLY for the lifetime
|
||||||
// But, we want to retain these VolumeSnapshotContent ONLY for the lifetime
|
// of the backup. To that effect, during velero backup
|
||||||
// of the backup. To that effect, during velero backup
|
// deletion, we will update the DeletionPolicy of the VolumeSnapshotContent
|
||||||
// deletion, we will update the DeletionPolicy of the VolumeSnapshotContent
|
// and then delete the VolumeSnapshot object which will cascade delete the
|
||||||
// and then delete the VolumeSnapshot object which will cascade delete the
|
// VolumeSnapshotContent and the associated snapshot in the storage
|
||||||
// VolumeSnapshotContent and the associated snapshot in the storage
|
// provider (handled by the CSI driver and the CSI common controller).
|
||||||
// provider (handled by the CSI driver and the CSI common controller).
|
// However, in the event that the VolumeSnapshot object is deleted outside
|
||||||
// However, in the event that the VolumeSnapshot object is deleted outside
|
// of the backup deletion process, it is possible that the dynamically created
|
||||||
// of the backup deletion process, it is possible that the dynamically created
|
// VolumeSnapshotContent object will be left as an orphaned and non-discoverable
|
||||||
// VolumeSnapshotContent object will be left as an orphaned and non-discoverable
|
// resource in the cluster as well as in the storage provider. To avoid piling
|
||||||
// resource in the cluster as well as in the storage provider. To avoid piling
|
// up of such orphaned resources, we will want to discover and delete the
|
||||||
// up of such orphaned resources, we will want to discover and delete the
|
// dynamically created VolumeSnapshotContent. We do that by adding
|
||||||
// dynamically created VolumeSnapshotContent. We do that by adding
|
// the "velero.io/backup-name" label on the VolumeSnapshotContent.
|
||||||
// the "velero.io/backup-name" label on the VolumeSnapshotContent.
|
// Further, we want to add this label only on VolumeSnapshotContents that
|
||||||
// Further, we want to add this label only on VolumeSnapshotContents that
|
// were created during an ongoing velero backup.
|
||||||
// were created during an ongoing velero backup.
|
originVSC := vsc.DeepCopy()
|
||||||
originVSC := vsc.DeepCopy()
|
kubeutil.AddLabels(
|
||||||
kubeutil.AddLabels(
|
&vsc.ObjectMeta,
|
||||||
&vsc.ObjectMeta,
|
map[string]string{
|
||||||
map[string]string{
|
velerov1api.BackupNameLabel: label.GetValidName(backup.Name),
|
||||||
velerov1api.BackupNameLabel: label.GetValidName(backup.Name),
|
},
|
||||||
},
|
)
|
||||||
)
|
|
||||||
|
|
||||||
if vscPatchError := p.crClient.Patch(
|
if vscPatchError := p.crClient.Patch(
|
||||||
context.TODO(),
|
context.TODO(),
|
||||||
vsc,
|
vsc,
|
||||||
crclient.MergeFrom(originVSC),
|
crclient.MergeFrom(originVSC),
|
||||||
); vscPatchError != nil {
|
); vscPatchError != nil {
|
||||||
p.log.Warnf("Failed to patch VolumeSnapshotContent %s: %v",
|
p.log.Warnf("Failed to patch VolumeSnapshotContent %s: %v",
|
||||||
vsc.Name, vscPatchError)
|
vsc.Name, vscPatchError)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,20 +225,18 @@ func (p *volumeSnapshotBackupItemAction) Execute(
|
||||||
var itemToUpdate []velero.ResourceIdentifier
|
var itemToUpdate []velero.ResourceIdentifier
|
||||||
|
|
||||||
// Only return Async operation for VSC created for this backup.
|
// Only return Async operation for VSC created for this backup.
|
||||||
if backupOngoing {
|
// The operationID is of the form <namespace>/<volumesnapshot-name>/<started-time>
|
||||||
// The operationID is of the form <namespace>/<volumesnapshot-name>/<started-time>
|
operationID = vs.Namespace + "/" + vs.Name + "/" + time.Now().Format(time.RFC3339)
|
||||||
operationID = vs.Namespace + "/" + vs.Name + "/" + time.Now().Format(time.RFC3339)
|
itemToUpdate = []velero.ResourceIdentifier{
|
||||||
itemToUpdate = []velero.ResourceIdentifier{
|
{
|
||||||
{
|
GroupResource: kuberesource.VolumeSnapshots,
|
||||||
GroupResource: kuberesource.VolumeSnapshots,
|
Namespace: vs.Namespace,
|
||||||
Namespace: vs.Namespace,
|
Name: vs.Name,
|
||||||
Name: vs.Name,
|
},
|
||||||
},
|
{
|
||||||
{
|
GroupResource: kuberesource.VolumeSnapshotContents,
|
||||||
GroupResource: kuberesource.VolumeSnapshotContents,
|
Name: vsc.Name,
|
||||||
Name: vsc.Name,
|
},
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &unstructured.Unstructured{Object: vsMap},
|
return &unstructured.Unstructured{Object: vsMap},
|
||||||
|
|
|
@ -49,23 +49,6 @@ func TestVSExecute(t *testing.T) {
|
||||||
expectedAdditionalItems []velero.ResourceIdentifier
|
expectedAdditionalItems []velero.ResourceIdentifier
|
||||||
expectedItemToUpdate []velero.ResourceIdentifier
|
expectedItemToUpdate []velero.ResourceIdentifier
|
||||||
}{
|
}{
|
||||||
{
|
|
||||||
name: "VS not created by backup, has no status. Backup is finalizing",
|
|
||||||
backup: builder.ForBackup("velero", "backup").
|
|
||||||
Phase(velerov1api.BackupPhaseFinalizing).Result(),
|
|
||||||
vs: builder.ForVolumeSnapshot("velero", "vs").
|
|
||||||
VolumeSnapshotClass("class").Result(),
|
|
||||||
expectedErr: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "VS is not created by the backup, associated VSC not exists",
|
|
||||||
backup: builder.ForBackup("velero", "backup").
|
|
||||||
Phase(velerov1api.BackupPhaseInProgress).Result(),
|
|
||||||
vs: builder.ForVolumeSnapshot("velero", "vs").
|
|
||||||
VolumeSnapshotClass("class").Status().
|
|
||||||
BoundVolumeSnapshotContentName("vsc").Result(),
|
|
||||||
expectedErr: `error getting volume snapshot content from API: volumesnapshotcontents.snapshot.storage.k8s.io "vsc" not found`,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "Normal case",
|
name: "Normal case",
|
||||||
backup: builder.ForBackup("velero", "backup").
|
backup: builder.ForBackup("velero", "backup").
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"slices"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
snapshotv1api "github.com/kubernetes-csi/external-snapshotter/client/v7/apis/volumesnapshot/v1"
|
snapshotv1api "github.com/kubernetes-csi/external-snapshotter/client/v7/apis/volumesnapshot/v1"
|
||||||
|
@ -31,6 +32,7 @@ import (
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
kerrors "k8s.io/apimachinery/pkg/util/errors"
|
kerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||||
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
"k8s.io/utils/clock"
|
"k8s.io/utils/clock"
|
||||||
ctrl "sigs.k8s.io/controller-runtime"
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
|
@ -63,6 +65,20 @@ const (
|
||||||
backupResyncPeriod = time.Minute
|
backupResyncPeriod = time.Minute
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var autoExcludeNamespaceScopedResources = []string{
|
||||||
|
// CSI VolumeSnapshot and VolumeSnapshotContent are intermediate resources.
|
||||||
|
// Velero only handle the VS and VSC created during backup,
|
||||||
|
// not during resource collecting.
|
||||||
|
"volumesnapshots.snapshot.storage.k8s.io",
|
||||||
|
}
|
||||||
|
|
||||||
|
var autoExcludeClusterScopedResources = []string{
|
||||||
|
// CSI VolumeSnapshot and VolumeSnapshotContent are intermediate resources.
|
||||||
|
// Velero only handle the VS and VSC created during backup,
|
||||||
|
// not during resource collecting.
|
||||||
|
"volumesnapshotcontents.snapshot.storage.k8s.io",
|
||||||
|
}
|
||||||
|
|
||||||
type backupReconciler struct {
|
type backupReconciler struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
logger logrus.FieldLogger
|
logger logrus.FieldLogger
|
||||||
|
@ -481,19 +497,51 @@ func (b *backupReconciler) prepareBackupRequest(backup *velerov1api.Backup, logg
|
||||||
request.Status.ValidationErrors = append(request.Status.ValidationErrors, validatedError)
|
request.Status.ValidationErrors = append(request.Status.ValidationErrors, validatedError)
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate the included/excluded resources
|
if collections.UseOldResourceFilters(request.Spec) {
|
||||||
for _, err := range collections.ValidateIncludesExcludes(request.Spec.IncludedResources, request.Spec.ExcludedResources) {
|
// validate the included/excluded resources
|
||||||
request.Status.ValidationErrors = append(request.Status.ValidationErrors, fmt.Sprintf("Invalid included/excluded resource lists: %v", err))
|
ieErr := collections.ValidateIncludesExcludes(request.Spec.IncludedResources, request.Spec.ExcludedResources)
|
||||||
}
|
if len(ieErr) > 0 {
|
||||||
|
for _, err := range ieErr {
|
||||||
|
request.Status.ValidationErrors = append(request.Status.ValidationErrors, fmt.Sprintf("Invalid included/excluded resource lists: %v", err))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
request.Spec.IncludedResources, request.Spec.ExcludedResources =
|
||||||
|
modifyResourceIncludeExclude(
|
||||||
|
request.Spec.IncludedResources,
|
||||||
|
request.Spec.ExcludedResources,
|
||||||
|
append(autoExcludeNamespaceScopedResources, autoExcludeClusterScopedResources...),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// validate the cluster-scoped included/excluded resources
|
||||||
|
clusterErr := collections.ValidateScopedIncludesExcludes(request.Spec.IncludedClusterScopedResources, request.Spec.ExcludedClusterScopedResources)
|
||||||
|
if len(clusterErr) > 0 {
|
||||||
|
for _, err := range clusterErr {
|
||||||
|
request.Status.ValidationErrors = append(request.Status.ValidationErrors, fmt.Sprintf("Invalid cluster-scoped included/excluded resource lists: %s", err))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
request.Spec.IncludedClusterScopedResources, request.Spec.ExcludedClusterScopedResources =
|
||||||
|
modifyResourceIncludeExclude(
|
||||||
|
request.Spec.IncludedClusterScopedResources,
|
||||||
|
request.Spec.ExcludedClusterScopedResources,
|
||||||
|
autoExcludeClusterScopedResources,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// validate the cluster-scoped included/excluded resources
|
// validate the namespace-scoped included/excluded resources
|
||||||
for _, err := range collections.ValidateScopedIncludesExcludes(request.Spec.IncludedClusterScopedResources, request.Spec.ExcludedClusterScopedResources) {
|
namespaceErr := collections.ValidateScopedIncludesExcludes(request.Spec.IncludedNamespaceScopedResources, request.Spec.ExcludedNamespaceScopedResources)
|
||||||
request.Status.ValidationErrors = append(request.Status.ValidationErrors, fmt.Sprintf("Invalid cluster-scoped included/excluded resource lists: %s", err))
|
if len(namespaceErr) > 0 {
|
||||||
}
|
for _, err := range namespaceErr {
|
||||||
|
request.Status.ValidationErrors = append(request.Status.ValidationErrors, fmt.Sprintf("Invalid namespace-scoped included/excluded resource lists: %s", err))
|
||||||
// validate the namespace-scoped included/excluded resources
|
}
|
||||||
for _, err := range collections.ValidateScopedIncludesExcludes(request.Spec.IncludedNamespaceScopedResources, request.Spec.ExcludedNamespaceScopedResources) {
|
} else {
|
||||||
request.Status.ValidationErrors = append(request.Status.ValidationErrors, fmt.Sprintf("Invalid namespace-scoped included/excluded resource lists: %s", err))
|
request.Spec.IncludedNamespaceScopedResources, request.Spec.ExcludedNamespaceScopedResources =
|
||||||
|
modifyResourceIncludeExclude(
|
||||||
|
request.Spec.IncludedNamespaceScopedResources,
|
||||||
|
request.Spec.ExcludedNamespaceScopedResources,
|
||||||
|
autoExcludeNamespaceScopedResources,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate the included/excluded namespaces
|
// validate the included/excluded namespaces
|
||||||
|
@ -932,3 +980,25 @@ func oldAndNewFilterParametersUsedTogether(backupSpec velerov1api.BackupSpec) bo
|
||||||
|
|
||||||
return haveOldResourceFilterParameters && haveNewResourceFilterParameters
|
return haveOldResourceFilterParameters && haveNewResourceFilterParameters
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func modifyResourceIncludeExclude(include, exclude, addedExclude []string) (modifiedInclude, modifiedExclude []string) {
|
||||||
|
modifiedInclude = include
|
||||||
|
modifiedExclude = exclude
|
||||||
|
|
||||||
|
excludeStrSet := sets.NewString(exclude...)
|
||||||
|
for _, ex := range addedExclude {
|
||||||
|
if !excludeStrSet.Has(ex) {
|
||||||
|
modifiedExclude = append(modifiedExclude, ex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, exElem := range modifiedExclude {
|
||||||
|
for inIndex, inElem := range modifiedInclude {
|
||||||
|
if inElem == exElem {
|
||||||
|
modifiedInclude = slices.Delete(modifiedInclude, inIndex, inIndex+1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return modifiedInclude, modifiedExclude
|
||||||
|
}
|
||||||
|
|
|
@ -708,6 +708,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
||||||
StorageLocation: defaultBackupLocation.Name,
|
StorageLocation: defaultBackupLocation.Name,
|
||||||
DefaultVolumesToFsBackup: boolptr.True(),
|
DefaultVolumesToFsBackup: boolptr.True(),
|
||||||
SnapshotMoveData: boolptr.False(),
|
SnapshotMoveData: boolptr.False(),
|
||||||
|
ExcludedResources: append(autoExcludeNamespaceScopedResources, autoExcludeClusterScopedResources...),
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
|
@ -745,6 +746,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
||||||
StorageLocation: "alt-loc",
|
StorageLocation: "alt-loc",
|
||||||
DefaultVolumesToFsBackup: boolptr.False(),
|
DefaultVolumesToFsBackup: boolptr.False(),
|
||||||
SnapshotMoveData: boolptr.False(),
|
SnapshotMoveData: boolptr.False(),
|
||||||
|
ExcludedResources: append(autoExcludeNamespaceScopedResources, autoExcludeClusterScopedResources...),
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
|
@ -786,6 +788,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
||||||
StorageLocation: "read-write",
|
StorageLocation: "read-write",
|
||||||
DefaultVolumesToFsBackup: boolptr.True(),
|
DefaultVolumesToFsBackup: boolptr.True(),
|
||||||
SnapshotMoveData: boolptr.False(),
|
SnapshotMoveData: boolptr.False(),
|
||||||
|
ExcludedResources: append(autoExcludeNamespaceScopedResources, autoExcludeClusterScopedResources...),
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
|
@ -824,6 +827,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
||||||
StorageLocation: defaultBackupLocation.Name,
|
StorageLocation: defaultBackupLocation.Name,
|
||||||
DefaultVolumesToFsBackup: boolptr.False(),
|
DefaultVolumesToFsBackup: boolptr.False(),
|
||||||
SnapshotMoveData: boolptr.False(),
|
SnapshotMoveData: boolptr.False(),
|
||||||
|
ExcludedResources: append(autoExcludeNamespaceScopedResources, autoExcludeClusterScopedResources...),
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
|
@ -862,6 +866,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
||||||
StorageLocation: defaultBackupLocation.Name,
|
StorageLocation: defaultBackupLocation.Name,
|
||||||
DefaultVolumesToFsBackup: boolptr.True(),
|
DefaultVolumesToFsBackup: boolptr.True(),
|
||||||
SnapshotMoveData: boolptr.False(),
|
SnapshotMoveData: boolptr.False(),
|
||||||
|
ExcludedResources: append(autoExcludeNamespaceScopedResources, autoExcludeClusterScopedResources...),
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
|
@ -901,6 +906,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
||||||
StorageLocation: defaultBackupLocation.Name,
|
StorageLocation: defaultBackupLocation.Name,
|
||||||
DefaultVolumesToFsBackup: boolptr.False(),
|
DefaultVolumesToFsBackup: boolptr.False(),
|
||||||
SnapshotMoveData: boolptr.False(),
|
SnapshotMoveData: boolptr.False(),
|
||||||
|
ExcludedResources: append(autoExcludeNamespaceScopedResources, autoExcludeClusterScopedResources...),
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
|
@ -940,6 +946,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
||||||
StorageLocation: defaultBackupLocation.Name,
|
StorageLocation: defaultBackupLocation.Name,
|
||||||
DefaultVolumesToFsBackup: boolptr.True(),
|
DefaultVolumesToFsBackup: boolptr.True(),
|
||||||
SnapshotMoveData: boolptr.False(),
|
SnapshotMoveData: boolptr.False(),
|
||||||
|
ExcludedResources: append(autoExcludeNamespaceScopedResources, autoExcludeClusterScopedResources...),
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
|
@ -979,6 +986,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
||||||
StorageLocation: defaultBackupLocation.Name,
|
StorageLocation: defaultBackupLocation.Name,
|
||||||
DefaultVolumesToFsBackup: boolptr.True(),
|
DefaultVolumesToFsBackup: boolptr.True(),
|
||||||
SnapshotMoveData: boolptr.False(),
|
SnapshotMoveData: boolptr.False(),
|
||||||
|
ExcludedResources: append(autoExcludeNamespaceScopedResources, autoExcludeClusterScopedResources...),
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
|
@ -1018,6 +1026,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
||||||
StorageLocation: defaultBackupLocation.Name,
|
StorageLocation: defaultBackupLocation.Name,
|
||||||
DefaultVolumesToFsBackup: boolptr.False(),
|
DefaultVolumesToFsBackup: boolptr.False(),
|
||||||
SnapshotMoveData: boolptr.False(),
|
SnapshotMoveData: boolptr.False(),
|
||||||
|
ExcludedResources: append(autoExcludeNamespaceScopedResources, autoExcludeClusterScopedResources...),
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
|
@ -1058,6 +1067,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
||||||
StorageLocation: defaultBackupLocation.Name,
|
StorageLocation: defaultBackupLocation.Name,
|
||||||
DefaultVolumesToFsBackup: boolptr.True(),
|
DefaultVolumesToFsBackup: boolptr.True(),
|
||||||
SnapshotMoveData: boolptr.False(),
|
SnapshotMoveData: boolptr.False(),
|
||||||
|
ExcludedResources: append(autoExcludeNamespaceScopedResources, autoExcludeClusterScopedResources...),
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFailed,
|
Phase: velerov1api.BackupPhaseFailed,
|
||||||
|
@ -1098,6 +1108,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
||||||
StorageLocation: defaultBackupLocation.Name,
|
StorageLocation: defaultBackupLocation.Name,
|
||||||
DefaultVolumesToFsBackup: boolptr.True(),
|
DefaultVolumesToFsBackup: boolptr.True(),
|
||||||
SnapshotMoveData: boolptr.False(),
|
SnapshotMoveData: boolptr.False(),
|
||||||
|
ExcludedResources: append(autoExcludeNamespaceScopedResources, autoExcludeClusterScopedResources...),
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFailed,
|
Phase: velerov1api.BackupPhaseFailed,
|
||||||
|
@ -1138,6 +1149,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
||||||
StorageLocation: defaultBackupLocation.Name,
|
StorageLocation: defaultBackupLocation.Name,
|
||||||
DefaultVolumesToFsBackup: boolptr.False(),
|
DefaultVolumesToFsBackup: boolptr.False(),
|
||||||
SnapshotMoveData: boolptr.True(),
|
SnapshotMoveData: boolptr.True(),
|
||||||
|
ExcludedResources: append(autoExcludeNamespaceScopedResources, autoExcludeClusterScopedResources...),
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
|
@ -1179,6 +1191,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
||||||
StorageLocation: defaultBackupLocation.Name,
|
StorageLocation: defaultBackupLocation.Name,
|
||||||
DefaultVolumesToFsBackup: boolptr.False(),
|
DefaultVolumesToFsBackup: boolptr.False(),
|
||||||
SnapshotMoveData: boolptr.False(),
|
SnapshotMoveData: boolptr.False(),
|
||||||
|
ExcludedResources: append(autoExcludeNamespaceScopedResources, autoExcludeClusterScopedResources...),
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
|
@ -1220,6 +1233,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
||||||
StorageLocation: defaultBackupLocation.Name,
|
StorageLocation: defaultBackupLocation.Name,
|
||||||
DefaultVolumesToFsBackup: boolptr.False(),
|
DefaultVolumesToFsBackup: boolptr.False(),
|
||||||
SnapshotMoveData: boolptr.False(),
|
SnapshotMoveData: boolptr.False(),
|
||||||
|
ExcludedResources: append(autoExcludeNamespaceScopedResources, autoExcludeClusterScopedResources...),
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
|
@ -1261,6 +1275,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
||||||
StorageLocation: defaultBackupLocation.Name,
|
StorageLocation: defaultBackupLocation.Name,
|
||||||
DefaultVolumesToFsBackup: boolptr.False(),
|
DefaultVolumesToFsBackup: boolptr.False(),
|
||||||
SnapshotMoveData: boolptr.True(),
|
SnapshotMoveData: boolptr.True(),
|
||||||
|
ExcludedResources: append(autoExcludeNamespaceScopedResources, autoExcludeClusterScopedResources...),
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
|
@ -1303,6 +1318,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
||||||
StorageLocation: defaultBackupLocation.Name,
|
StorageLocation: defaultBackupLocation.Name,
|
||||||
DefaultVolumesToFsBackup: boolptr.False(),
|
DefaultVolumesToFsBackup: boolptr.False(),
|
||||||
SnapshotMoveData: boolptr.False(),
|
SnapshotMoveData: boolptr.False(),
|
||||||
|
ExcludedResources: append(autoExcludeNamespaceScopedResources, autoExcludeClusterScopedResources...),
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
|
@ -1344,6 +1360,105 @@ func TestProcessBackupCompletions(t *testing.T) {
|
||||||
StorageLocation: defaultBackupLocation.Name,
|
StorageLocation: defaultBackupLocation.Name,
|
||||||
DefaultVolumesToFsBackup: boolptr.False(),
|
DefaultVolumesToFsBackup: boolptr.False(),
|
||||||
SnapshotMoveData: boolptr.True(),
|
SnapshotMoveData: boolptr.True(),
|
||||||
|
ExcludedResources: append(autoExcludeNamespaceScopedResources, autoExcludeClusterScopedResources...),
|
||||||
|
},
|
||||||
|
Status: velerov1api.BackupStatus{
|
||||||
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
|
Version: 1,
|
||||||
|
FormatVersion: "1.1.0",
|
||||||
|
StartTimestamp: ×tamp,
|
||||||
|
Expiration: ×tamp,
|
||||||
|
CSIVolumeSnapshotsAttempted: 0,
|
||||||
|
CSIVolumeSnapshotsCompleted: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
volumeSnapshot: builder.ForVolumeSnapshot("velero", "testVS").VolumeSnapshotClass("testClass").Status().BoundVolumeSnapshotContentName("testVSC").RestoreSize("10G").SourcePVC("testPVC").ObjectMeta(builder.WithLabels(velerov1api.BackupNameLabel, "backup-1")).Result(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "backup with namespace-scoped and cluster-scoped resource filters",
|
||||||
|
backup: builder.ForBackup(velerov1api.DefaultNamespace, "backup-1").
|
||||||
|
ExcludedClusterScopedResources("clusterroles").
|
||||||
|
IncludedClusterScopedResources("storageclasses").
|
||||||
|
ExcludedNamespaceScopedResources("secrets").
|
||||||
|
IncludedNamespaceScopedResources("pods").Result(),
|
||||||
|
backupLocation: defaultBackupLocation,
|
||||||
|
defaultVolumesToFsBackup: false,
|
||||||
|
defaultSnapshotMoveData: true,
|
||||||
|
expectedResult: &velerov1api.Backup{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "Backup",
|
||||||
|
APIVersion: "velero.io/v1",
|
||||||
|
},
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Namespace: velerov1api.DefaultNamespace,
|
||||||
|
Name: "backup-1",
|
||||||
|
Annotations: map[string]string{
|
||||||
|
"velero.io/source-cluster-k8s-major-version": "1",
|
||||||
|
"velero.io/source-cluster-k8s-minor-version": "16",
|
||||||
|
"velero.io/source-cluster-k8s-gitversion": "v1.16.4",
|
||||||
|
"velero.io/resource-timeout": "0s",
|
||||||
|
},
|
||||||
|
Labels: map[string]string{
|
||||||
|
"velero.io/storage-location": "loc-1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: velerov1api.BackupSpec{
|
||||||
|
StorageLocation: defaultBackupLocation.Name,
|
||||||
|
DefaultVolumesToFsBackup: boolptr.False(),
|
||||||
|
SnapshotMoveData: boolptr.True(),
|
||||||
|
IncludedClusterScopedResources: []string{"storageclasses"},
|
||||||
|
ExcludedClusterScopedResources: append([]string{"clusterroles"}, autoExcludeClusterScopedResources...),
|
||||||
|
IncludedNamespaceScopedResources: []string{"pods"},
|
||||||
|
ExcludedNamespaceScopedResources: append([]string{"secrets"}, autoExcludeNamespaceScopedResources...),
|
||||||
|
},
|
||||||
|
Status: velerov1api.BackupStatus{
|
||||||
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
|
Version: 1,
|
||||||
|
FormatVersion: "1.1.0",
|
||||||
|
StartTimestamp: ×tamp,
|
||||||
|
Expiration: ×tamp,
|
||||||
|
CSIVolumeSnapshotsAttempted: 0,
|
||||||
|
CSIVolumeSnapshotsCompleted: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
volumeSnapshot: builder.ForVolumeSnapshot("velero", "testVS").VolumeSnapshotClass("testClass").Status().BoundVolumeSnapshotContentName("testVSC").RestoreSize("10G").SourcePVC("testPVC").ObjectMeta(builder.WithLabels(velerov1api.BackupNameLabel, "backup-1")).Result(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "backup's include filter overlap with default exclude resources",
|
||||||
|
backup: builder.ForBackup(velerov1api.DefaultNamespace, "backup-1").
|
||||||
|
ExcludedClusterScopedResources("clusterroles").
|
||||||
|
IncludedClusterScopedResources("storageclasses", "volumesnapshotcontents.snapshot.storage.k8s.io").
|
||||||
|
ExcludedNamespaceScopedResources("secrets").
|
||||||
|
IncludedNamespaceScopedResources("pods", "volumesnapshots.snapshot.storage.k8s.io").Result(),
|
||||||
|
backupLocation: defaultBackupLocation,
|
||||||
|
defaultVolumesToFsBackup: false,
|
||||||
|
defaultSnapshotMoveData: true,
|
||||||
|
expectedResult: &velerov1api.Backup{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "Backup",
|
||||||
|
APIVersion: "velero.io/v1",
|
||||||
|
},
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Namespace: velerov1api.DefaultNamespace,
|
||||||
|
Name: "backup-1",
|
||||||
|
Annotations: map[string]string{
|
||||||
|
"velero.io/source-cluster-k8s-major-version": "1",
|
||||||
|
"velero.io/source-cluster-k8s-minor-version": "16",
|
||||||
|
"velero.io/source-cluster-k8s-gitversion": "v1.16.4",
|
||||||
|
"velero.io/resource-timeout": "0s",
|
||||||
|
},
|
||||||
|
Labels: map[string]string{
|
||||||
|
"velero.io/storage-location": "loc-1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: velerov1api.BackupSpec{
|
||||||
|
StorageLocation: defaultBackupLocation.Name,
|
||||||
|
DefaultVolumesToFsBackup: boolptr.False(),
|
||||||
|
SnapshotMoveData: boolptr.True(),
|
||||||
|
IncludedClusterScopedResources: []string{"storageclasses"},
|
||||||
|
ExcludedClusterScopedResources: append([]string{"clusterroles"}, autoExcludeClusterScopedResources...),
|
||||||
|
IncludedNamespaceScopedResources: []string{"pods"},
|
||||||
|
ExcludedNamespaceScopedResources: append([]string{"secrets"}, autoExcludeNamespaceScopedResources...),
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
|
|
|
@ -588,32 +588,8 @@ func WaitUntilVSCHandleIsReady(
|
||||||
volSnap *snapshotv1api.VolumeSnapshot,
|
volSnap *snapshotv1api.VolumeSnapshot,
|
||||||
crClient crclient.Client,
|
crClient crclient.Client,
|
||||||
log logrus.FieldLogger,
|
log logrus.FieldLogger,
|
||||||
shouldWait bool,
|
|
||||||
csiSnapshotTimeout time.Duration,
|
csiSnapshotTimeout time.Duration,
|
||||||
) (*snapshotv1api.VolumeSnapshotContent, error) {
|
) (*snapshotv1api.VolumeSnapshotContent, error) {
|
||||||
if !shouldWait {
|
|
||||||
if volSnap.Status == nil ||
|
|
||||||
volSnap.Status.BoundVolumeSnapshotContentName == nil {
|
|
||||||
// volumesnapshot hasn't been reconciled and we're
|
|
||||||
// not waiting for it.
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
vsc := new(snapshotv1api.VolumeSnapshotContent)
|
|
||||||
err := crClient.Get(
|
|
||||||
context.TODO(),
|
|
||||||
crclient.ObjectKey{
|
|
||||||
Name: *volSnap.Status.BoundVolumeSnapshotContentName,
|
|
||||||
},
|
|
||||||
vsc,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil,
|
|
||||||
errors.Wrap(err,
|
|
||||||
"error getting volume snapshot content from API")
|
|
||||||
}
|
|
||||||
return vsc, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// We'll wait 10m for the VSC to be reconciled polling
|
// We'll wait 10m for the VSC to be reconciled polling
|
||||||
// every 5s unless backup's csiSnapshotTimeout is set
|
// every 5s unless backup's csiSnapshotTimeout is set
|
||||||
interval := 5 * time.Second
|
interval := 5 * time.Second
|
||||||
|
|
|
@ -1646,26 +1646,22 @@ func TestWaitUntilVSCHandleIsReady(t *testing.T) {
|
||||||
name string
|
name string
|
||||||
volSnap *snapshotv1api.VolumeSnapshot
|
volSnap *snapshotv1api.VolumeSnapshot
|
||||||
exepctedVSC *snapshotv1api.VolumeSnapshotContent
|
exepctedVSC *snapshotv1api.VolumeSnapshotContent
|
||||||
wait bool
|
|
||||||
expectError bool
|
expectError bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "waitEnabled should find volumesnapshotcontent for volumesnapshot",
|
name: "waitEnabled should find volumesnapshotcontent for volumesnapshot",
|
||||||
volSnap: validVS,
|
volSnap: validVS,
|
||||||
exepctedVSC: vscObj,
|
exepctedVSC: vscObj,
|
||||||
wait: true,
|
|
||||||
expectError: false,
|
expectError: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "waitEnabled should not find volumesnapshotcontent for volumesnapshot with non-existing snapshotcontent name in status.BoundVolumeSnapshotContentName",
|
name: "waitEnabled should not find volumesnapshotcontent for volumesnapshot with non-existing snapshotcontent name in status.BoundVolumeSnapshotContentName",
|
||||||
volSnap: vsWithVSCNotFound,
|
volSnap: vsWithVSCNotFound,
|
||||||
exepctedVSC: nil,
|
exepctedVSC: nil,
|
||||||
wait: true,
|
|
||||||
expectError: true,
|
expectError: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "waitEnabled should not find volumesnapshotcontent for a non-existent volumesnapshot",
|
name: "waitEnabled should not find volumesnapshotcontent for a non-existent volumesnapshot",
|
||||||
wait: true,
|
|
||||||
exepctedVSC: nil,
|
exepctedVSC: nil,
|
||||||
expectError: true,
|
expectError: true,
|
||||||
volSnap: &snapshotv1api.VolumeSnapshot{
|
volSnap: &snapshotv1api.VolumeSnapshot{
|
||||||
|
@ -1678,46 +1674,11 @@ func TestWaitUntilVSCHandleIsReady(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "waitDisabled should not find volumesnapshotcontent when volumesnapshot status is nil",
|
|
||||||
wait: false,
|
|
||||||
expectError: false,
|
|
||||||
exepctedVSC: nil,
|
|
||||||
volSnap: vsWithNilStatus,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "waitDisabled should not find volumesnapshotcontent when volumesnapshot status.BoundVolumeSnapshotContentName is nil",
|
|
||||||
wait: false,
|
|
||||||
expectError: false,
|
|
||||||
exepctedVSC: nil,
|
|
||||||
volSnap: vsWithNilStatusField,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "waitDisabled should find volumesnapshotcontent when volumesnapshotcontent status is nil",
|
|
||||||
wait: false,
|
|
||||||
expectError: false,
|
|
||||||
exepctedVSC: vscWithNilStatus,
|
|
||||||
volSnap: vsForNilStatusVsc,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "waitDisabled should find volumesnapshotcontent when volumesnapshotcontent status.SnapshotHandle is nil",
|
|
||||||
wait: false,
|
|
||||||
expectError: false,
|
|
||||||
exepctedVSC: vscWithNilStatusField,
|
|
||||||
volSnap: vsForNilStatusFieldVsc,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "waitDisabled should not find a non-existent volumesnapshotcontent",
|
|
||||||
wait: false,
|
|
||||||
exepctedVSC: nil,
|
|
||||||
expectError: true,
|
|
||||||
volSnap: vsWithVSCNotFound,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
actualVSC, actualError := WaitUntilVSCHandleIsReady(tc.volSnap, fakeClient, logrus.New().WithField("fake", "test"), tc.wait, 0)
|
actualVSC, actualError := WaitUntilVSCHandleIsReady(tc.volSnap, fakeClient, logrus.New().WithField("fake", "test"), 0)
|
||||||
if tc.expectError && actualError == nil {
|
if tc.expectError && actualError == nil {
|
||||||
assert.Error(t, actualError)
|
assert.Error(t, actualError)
|
||||||
assert.Nil(t, actualVSC)
|
assert.Nil(t, actualVSC)
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
appsv1api "k8s.io/api/apps/v1"
|
appsv1api "k8s.io/api/apps/v1"
|
||||||
corev1api "k8s.io/api/core/v1"
|
corev1api "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
@ -210,39 +211,21 @@ func TestGetAffinityFromVeleroServer(t *testing.T) {
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
got := GetAffinityFromVeleroServer(test.deploy)
|
got := GetAffinityFromVeleroServer(test.deploy)
|
||||||
|
if test.want != nil {
|
||||||
if got == nil {
|
require.NotNilf(t, got, "expected affinity to be %v, got nil", test.want)
|
||||||
if test.want != nil {
|
if test.want.NodeAffinity != nil {
|
||||||
t.Errorf("expected affinity to be %v, got nil", test.want)
|
require.NotNilf(t, got.NodeAffinity, "expected node affinity to be %v, got nil", test.want.NodeAffinity)
|
||||||
|
if test.want.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution != nil {
|
||||||
|
require.NotNilf(t, got.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution, "expected required during scheduling ignored during execution to be %v, got nil", test.want.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution)
|
||||||
|
assert.Truef(t, reflect.DeepEqual(got.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution, test.want.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution), "expected required during scheduling ignored during execution to be %v, got %v", test.want.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution, got.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution)
|
||||||
|
} else {
|
||||||
|
assert.Nilf(t, got.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution, "expected required during scheduling ignored during execution to be nil, got %v", got.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert.Nilf(t, got.NodeAffinity, "expected node affinity to be nil, got %v", got.NodeAffinity)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if test.want == nil {
|
assert.Nilf(t, got, "expected affinity to be nil, got %v", got)
|
||||||
t.Errorf("expected affinity to be nil, got %v", got)
|
|
||||||
} else {
|
|
||||||
if got.NodeAffinity == nil {
|
|
||||||
if test.want.NodeAffinity != nil {
|
|
||||||
t.Errorf("expected node affinity to be %v, got nil", test.want.NodeAffinity)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if test.want.NodeAffinity == nil {
|
|
||||||
t.Errorf("expected node affinity to be nil, got %v", got.NodeAffinity)
|
|
||||||
} else {
|
|
||||||
if got.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution == nil {
|
|
||||||
if test.want.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution != nil {
|
|
||||||
t.Errorf("expected required during scheduling ignored during execution to be %v, got nil", test.want.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if test.want.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution == nil {
|
|
||||||
t.Errorf("expected required during scheduling ignored during execution to be nil, got %v", got.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution)
|
|
||||||
} else {
|
|
||||||
if !reflect.DeepEqual(got.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution, test.want.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution) {
|
|
||||||
t.Errorf("expected required during scheduling ignored during execution to be %v, got %v", test.want.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution, got.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,6 +178,12 @@ Additionally, you may want to update the the default File System Backup operatio
|
||||||
- --fs-backup-timeout=240m
|
- --fs-backup-timeout=240m
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Ephemeral-storage Requests and Limits
|
||||||
|
|
||||||
|
Velero does not set ephemeral-storage limits during installation. Limits and requests can be edited after install for clusters that monitor and restrict ephemeral-storage usage.
|
||||||
|
|
||||||
|
Plugins will use ephemeral-storage. There needs to be a sufficient requests and limit set to account for plugins and the additional ephemeral-storage used to maintain credentials and cache space for datamovers. Object storage plugins will fit comfortably into an allocation of 100MB of ephemeral-storage.
|
||||||
|
|
||||||
## Configure more than one storage location for backups or volume snapshots
|
## Configure more than one storage location for backups or volume snapshots
|
||||||
|
|
||||||
Velero supports any number of backup storage locations and volume snapshot locations. For more details, see [about locations](locations.md).
|
Velero supports any number of backup storage locations and volume snapshot locations. For more details, see [about locations](locations.md).
|
||||||
|
|
|
@ -178,6 +178,12 @@ Additionally, you may want to update the the default File System Backup operatio
|
||||||
- --fs-backup-timeout=240m
|
- --fs-backup-timeout=240m
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Ephemeral-storage Requests and Limits
|
||||||
|
|
||||||
|
Velero does not set ephemeral-storage limits during installation. Limits and requests can be edited after install for clusters that monitor and restrict ephemeral-storage usage.
|
||||||
|
|
||||||
|
Plugins will use ephemeral-storage. There needs to be a sufficient requests and limit set to account for plugins and the additional ephemeral-storage used to maintain credentials and cache space for datamovers. Object storage plugins will fit comfortably into an allocation of 100MB of ephemeral-storage.
|
||||||
|
|
||||||
## Configure more than one storage location for backups or volume snapshots
|
## Configure more than one storage location for backups or volume snapshots
|
||||||
|
|
||||||
Velero supports any number of backup storage locations and volume snapshot locations. For more details, see [about locations](locations.md).
|
Velero supports any number of backup storage locations and volume snapshot locations. For more details, see [about locations](locations.md).
|
||||||
|
|
Loading…
Reference in New Issue