mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-07-28 02:52:41 +00:00
Remove wildcard check from getNamespacesToList.
Expand wildcard in namespace filter only for backup scenario. Restore doesn't need that now, because restore has logic to rely on IncludeEverything function to check whether cluster-scoped resources should be restored. Expand wildcard will break the logic. Signed-off-by: Xun Jiang <xun.jiang@broadcom.com>
This commit is contained in:
committed by
Xun Jiang/Bruce Jiang
parent
bf9e1f8fd7
commit
8ac8f49b5c
@@ -0,0 +1 @@
|
|||||||
|
Remove wildcard check from getNamespacesToList.
|
||||||
@@ -187,7 +187,7 @@ func getNamespaceIncludesExcludesAndArgoCDNamespaces(backup *velerov1api.Backup,
|
|||||||
Excludes(backup.Spec.ExcludedNamespaces...)
|
Excludes(backup.Spec.ExcludedNamespaces...)
|
||||||
|
|
||||||
// Expand wildcards if needed
|
// Expand wildcards if needed
|
||||||
if err := includesExcludes.ExpandIncludesExcludes(); err != nil {
|
if err := includesExcludes.ExpandIncludesExcludes(true); err != nil {
|
||||||
return nil, []string{}, err
|
return nil, []string{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,7 +286,7 @@ func (kb *kubernetesBackupper) BackupWithResolvers(
|
|||||||
expandedExcludes := backupRequest.NamespaceIncludesExcludes.GetExcludes()
|
expandedExcludes := backupRequest.NamespaceIncludesExcludes.GetExcludes()
|
||||||
|
|
||||||
// Get the final namespace list after wildcard expansion
|
// Get the final namespace list after wildcard expansion
|
||||||
wildcardResult, err := backupRequest.NamespaceIncludesExcludes.ResolveNamespaceList()
|
wildcardResult, err := backupRequest.NamespaceIncludesExcludes.ResolveNamespaceList(true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Errorf("error resolving namespace list")
|
log.WithError(err).Errorf("error resolving namespace list")
|
||||||
return err
|
return err
|
||||||
@@ -410,7 +410,7 @@ func (kb *kubernetesBackupper) BackupWithResolvers(
|
|||||||
|
|
||||||
// Resolve namespaces for PVC-to-Pod cache building in volumehelper.
|
// Resolve namespaces for PVC-to-Pod cache building in volumehelper.
|
||||||
// See issue #9179 for details.
|
// See issue #9179 for details.
|
||||||
namespaces, err := backupRequest.NamespaceIncludesExcludes.ResolveNamespaceList()
|
namespaces, err := backupRequest.NamespaceIncludesExcludes.ResolveNamespaceList(true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Error("Failed to resolve namespace list for PVC-to-Pod cache")
|
log.WithError(err).Error("Failed to resolve namespace list for PVC-to-Pod cache")
|
||||||
return err
|
return err
|
||||||
|
|||||||
+10
-31
@@ -36,6 +36,7 @@ import (
|
|||||||
"github.com/stretchr/testify/mock"
|
"github.com/stretchr/testify/mock"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
corev1api "k8s.io/api/core/v1"
|
corev1api "k8s.io/api/core/v1"
|
||||||
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
@@ -281,8 +282,8 @@ func TestBackupOldResourceFiltering(t *testing.T) {
|
|||||||
Result(),
|
Result(),
|
||||||
apiResources: []*test.APIResource{
|
apiResources: []*test.APIResource{
|
||||||
test.Pods(
|
test.Pods(
|
||||||
builder.ForPod("foo", "bar").Result(),
|
builder.ForPod("foo", "bar").Phase(corev1api.PodRunning).Result(),
|
||||||
builder.ForPod("zoo", "raz").Result(),
|
builder.ForPod("zoo", "raz").Phase(corev1api.PodRunning).Result(),
|
||||||
),
|
),
|
||||||
test.Deployments(
|
test.Deployments(
|
||||||
builder.ForDeployment("foo", "bar").Result(),
|
builder.ForDeployment("foo", "bar").Result(),
|
||||||
@@ -980,28 +981,6 @@ func TestCRDInclusion(t *testing.T) {
|
|||||||
"resources/volumesnapshotlocations.velero.io/v1-preferredversion/namespaces/foo/vsl-1.json",
|
"resources/volumesnapshotlocations.velero.io/v1-preferredversion/namespaces/foo/vsl-1.json",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "include cluster resources=auto includes CRDs with CRs when backing up selected namespaces",
|
|
||||||
backup: defaultBackup().
|
|
||||||
IncludedNamespaces("foo").
|
|
||||||
Result(),
|
|
||||||
apiResources: []*test.APIResource{
|
|
||||||
test.CRDs(
|
|
||||||
builder.ForCustomResourceDefinitionV1Beta1("backups.velero.io").Result(),
|
|
||||||
builder.ForCustomResourceDefinitionV1Beta1("volumesnapshotlocations.velero.io").Result(),
|
|
||||||
builder.ForCustomResourceDefinitionV1Beta1("test.velero.io").Result(),
|
|
||||||
),
|
|
||||||
test.VSLs(
|
|
||||||
builder.ForVolumeSnapshotLocation("foo", "vsl-1").Result(),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
want: []string{
|
|
||||||
"resources/customresourcedefinitions.apiextensions.k8s.io/cluster/volumesnapshotlocations.velero.io.json",
|
|
||||||
"resources/volumesnapshotlocations.velero.io/namespaces/foo/vsl-1.json",
|
|
||||||
"resources/customresourcedefinitions.apiextensions.k8s.io/v1beta1-preferredversion/cluster/volumesnapshotlocations.velero.io.json",
|
|
||||||
"resources/volumesnapshotlocations.velero.io/v1-preferredversion/namespaces/foo/vsl-1.json",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "include-cluster-resources=false excludes all CRDs when backing up selected namespaces",
|
name: "include-cluster-resources=false excludes all CRDs when backing up selected namespaces",
|
||||||
backup: defaultBackup().
|
backup: defaultBackup().
|
||||||
@@ -4296,6 +4275,12 @@ func (h *harness) addItems(t *testing.T, resource *test.APIResource) {
|
|||||||
unstructuredObj := &unstructured.Unstructured{Object: obj}
|
unstructuredObj := &unstructured.Unstructured{Object: obj}
|
||||||
|
|
||||||
if resource.Namespaced {
|
if resource.Namespaced {
|
||||||
|
namespace := &corev1api.Namespace{ObjectMeta: metav1.ObjectMeta{Name: item.GetNamespace()}}
|
||||||
|
err = h.backupper.kbClient.Create(t.Context(), namespace)
|
||||||
|
if err != nil && !apierrors.IsAlreadyExists(err) {
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
_, err = h.DynamicClient.Resource(resource.GVR()).Namespace(item.GetNamespace()).Create(t.Context(), unstructuredObj, metav1.CreateOptions{})
|
_, err = h.DynamicClient.Resource(resource.GVR()).Namespace(item.GetNamespace()).Create(t.Context(), unstructuredObj, metav1.CreateOptions{})
|
||||||
} else {
|
} else {
|
||||||
_, err = h.DynamicClient.Resource(resource.GVR()).Create(t.Context(), unstructuredObj, metav1.CreateOptions{})
|
_, err = h.DynamicClient.Resource(resource.GVR()).Create(t.Context(), unstructuredObj, metav1.CreateOptions{})
|
||||||
@@ -4346,7 +4331,7 @@ func newSnapshotLocation(ns, name, provider string) *velerov1.VolumeSnapshotLoca
|
|||||||
}
|
}
|
||||||
|
|
||||||
func defaultBackup() *builder.BackupBuilder {
|
func defaultBackup() *builder.BackupBuilder {
|
||||||
return builder.ForBackup(velerov1.DefaultNamespace, "backup-1").DefaultVolumesToFsBackup(false)
|
return builder.ForBackup(velerov1.DefaultNamespace, "backup-1").DefaultVolumesToFsBackup(false).IncludedNamespaces("*")
|
||||||
}
|
}
|
||||||
|
|
||||||
func toUnstructuredOrFail(t *testing.T, obj any) map[string]any {
|
func toUnstructuredOrFail(t *testing.T, obj any) map[string]any {
|
||||||
@@ -5422,8 +5407,6 @@ func TestBackupNamespaces(t *testing.T) {
|
|||||||
want: []string{
|
want: []string{
|
||||||
"resources/namespaces/cluster/ns-1.json",
|
"resources/namespaces/cluster/ns-1.json",
|
||||||
"resources/namespaces/v1-preferredversion/cluster/ns-1.json",
|
"resources/namespaces/v1-preferredversion/cluster/ns-1.json",
|
||||||
"resources/namespaces/cluster/ns-3.json",
|
|
||||||
"resources/namespaces/v1-preferredversion/cluster/ns-3.json",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -5457,10 +5440,6 @@ func TestBackupNamespaces(t *testing.T) {
|
|||||||
want: []string{
|
want: []string{
|
||||||
"resources/namespaces/cluster/ns-1.json",
|
"resources/namespaces/cluster/ns-1.json",
|
||||||
"resources/namespaces/v1-preferredversion/cluster/ns-1.json",
|
"resources/namespaces/v1-preferredversion/cluster/ns-1.json",
|
||||||
"resources/namespaces/cluster/ns-2.json",
|
|
||||||
"resources/namespaces/v1-preferredversion/cluster/ns-2.json",
|
|
||||||
"resources/namespaces/cluster/ns-3.json",
|
|
||||||
"resources/namespaces/v1-preferredversion/cluster/ns-3.json",
|
|
||||||
"resources/deployments.apps/namespaces/ns-1/deploy-1.json",
|
"resources/deployments.apps/namespaces/ns-1/deploy-1.json",
|
||||||
"resources/deployments.apps/v1-preferredversion/namespaces/ns-1/deploy-1.json",
|
"resources/deployments.apps/v1-preferredversion/namespaces/ns-1/deploy-1.json",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -633,22 +633,19 @@ func coreGroupResourcePriority(resource string) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getNamespacesToList examines ie and resolves the includes and excludes to a full list of
|
// getNamespacesToList examines ie and resolves the includes and excludes to a full list of
|
||||||
// namespaces to list. If ie is nil or it includes *, the result is just "" (list across all
|
// namespaces to list. If ie is nil, the result is just "" (list across all namespaces).
|
||||||
// namespaces). Otherwise, the result is a list of every included namespace minus all excluded ones.
|
// Otherwise, the result is a list of every included namespace minus all excluded ones.
|
||||||
|
// Because the namespace IE filter is expanded from 1.18, there is no need to consider
|
||||||
|
// wildcard characters anymore.
|
||||||
func getNamespacesToList(ie *collections.NamespaceIncludesExcludes) []string {
|
func getNamespacesToList(ie *collections.NamespaceIncludesExcludes) []string {
|
||||||
if ie == nil {
|
if ie == nil {
|
||||||
return []string{""}
|
return []string{""}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ie.ShouldInclude("*") {
|
|
||||||
// "" means all namespaces
|
|
||||||
return []string{""}
|
|
||||||
}
|
|
||||||
|
|
||||||
var list []string
|
var list []string
|
||||||
for _, i := range ie.GetIncludes() {
|
for _, n := range ie.GetIncludes() {
|
||||||
if ie.ShouldInclude(i) {
|
if ie.ShouldInclude(n) {
|
||||||
list = append(list, i)
|
list = append(list, n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -575,6 +575,14 @@ func (b *backupReconciler) prepareBackupRequest(ctx context.Context, backup *vel
|
|||||||
request.Status.ValidationErrors = append(request.Status.ValidationErrors, fmt.Sprintf("Invalid included/excluded namespace lists: %v", err))
|
request.Status.ValidationErrors = append(request.Status.ValidationErrors, fmt.Sprintf("Invalid included/excluded namespace lists: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if included namespaces is empty, default to wildcard to include all namespaces
|
||||||
|
// This is useful for later wildcard expansion logic.
|
||||||
|
// This also align the behavior between backup creation from CLI and from API,
|
||||||
|
// as CLI will default to wildcard if included namespaces is not specified.
|
||||||
|
if request.Spec.IncludedNamespaces == nil {
|
||||||
|
request.Spec.IncludedNamespaces = []string{"*"}
|
||||||
|
}
|
||||||
|
|
||||||
// validate that only one exists orLabelSelector or just labelSelector (singular)
|
// validate that only one exists orLabelSelector or just labelSelector (singular)
|
||||||
if request.Spec.OrLabelSelectors != nil && request.Spec.LabelSelector != nil {
|
if request.Spec.OrLabelSelectors != nil && request.Spec.LabelSelector != nil {
|
||||||
request.Status.ValidationErrors = append(request.Status.ValidationErrors, "encountered labelSelector as well as orLabelSelectors in backup spec, only one can be specified")
|
request.Status.ValidationErrors = append(request.Status.ValidationErrors, "encountered labelSelector as well as orLabelSelectors in backup spec, only one can be specified")
|
||||||
|
|||||||
@@ -713,6 +713,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||||||
SnapshotMoveData: boolptr.False(),
|
SnapshotMoveData: boolptr.False(),
|
||||||
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
||||||
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
||||||
|
IncludedNamespaces: []string{"*"},
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
@@ -752,6 +753,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||||||
SnapshotMoveData: boolptr.False(),
|
SnapshotMoveData: boolptr.False(),
|
||||||
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
||||||
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
||||||
|
IncludedNamespaces: []string{"*"},
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
@@ -795,6 +797,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||||||
SnapshotMoveData: boolptr.False(),
|
SnapshotMoveData: boolptr.False(),
|
||||||
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
||||||
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
||||||
|
IncludedNamespaces: []string{"*"},
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
@@ -835,6 +838,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||||||
SnapshotMoveData: boolptr.False(),
|
SnapshotMoveData: boolptr.False(),
|
||||||
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
||||||
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
||||||
|
IncludedNamespaces: []string{"*"},
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
@@ -875,6 +879,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||||||
SnapshotMoveData: boolptr.False(),
|
SnapshotMoveData: boolptr.False(),
|
||||||
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
||||||
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
||||||
|
IncludedNamespaces: []string{"*"},
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
@@ -916,6 +921,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||||||
SnapshotMoveData: boolptr.False(),
|
SnapshotMoveData: boolptr.False(),
|
||||||
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
||||||
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
||||||
|
IncludedNamespaces: []string{"*"},
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
@@ -957,6 +963,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||||||
SnapshotMoveData: boolptr.False(),
|
SnapshotMoveData: boolptr.False(),
|
||||||
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
||||||
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
||||||
|
IncludedNamespaces: []string{"*"},
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
@@ -998,6 +1005,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||||||
SnapshotMoveData: boolptr.False(),
|
SnapshotMoveData: boolptr.False(),
|
||||||
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
||||||
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
||||||
|
IncludedNamespaces: []string{"*"},
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
@@ -1039,6 +1047,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||||||
SnapshotMoveData: boolptr.False(),
|
SnapshotMoveData: boolptr.False(),
|
||||||
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
||||||
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
||||||
|
IncludedNamespaces: []string{"*"},
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
@@ -1081,6 +1090,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||||||
SnapshotMoveData: boolptr.False(),
|
SnapshotMoveData: boolptr.False(),
|
||||||
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
||||||
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
||||||
|
IncludedNamespaces: []string{"*"},
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFailed,
|
Phase: velerov1api.BackupPhaseFailed,
|
||||||
@@ -1123,6 +1133,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||||||
SnapshotMoveData: boolptr.False(),
|
SnapshotMoveData: boolptr.False(),
|
||||||
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
||||||
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
||||||
|
IncludedNamespaces: []string{"*"},
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFailed,
|
Phase: velerov1api.BackupPhaseFailed,
|
||||||
@@ -1165,6 +1176,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||||||
SnapshotMoveData: boolptr.True(),
|
SnapshotMoveData: boolptr.True(),
|
||||||
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
||||||
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
||||||
|
IncludedNamespaces: []string{"*"},
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
@@ -1208,6 +1220,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||||||
SnapshotMoveData: boolptr.False(),
|
SnapshotMoveData: boolptr.False(),
|
||||||
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
||||||
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
||||||
|
IncludedNamespaces: []string{"*"},
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
@@ -1251,6 +1264,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||||||
SnapshotMoveData: boolptr.False(),
|
SnapshotMoveData: boolptr.False(),
|
||||||
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
||||||
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
||||||
|
IncludedNamespaces: []string{"*"},
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
@@ -1294,6 +1308,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||||||
SnapshotMoveData: boolptr.True(),
|
SnapshotMoveData: boolptr.True(),
|
||||||
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
||||||
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
||||||
|
IncludedNamespaces: []string{"*"},
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
@@ -1338,6 +1353,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||||||
SnapshotMoveData: boolptr.False(),
|
SnapshotMoveData: boolptr.False(),
|
||||||
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
||||||
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
||||||
|
IncludedNamespaces: []string{"*"},
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
@@ -1381,6 +1397,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||||||
SnapshotMoveData: boolptr.True(),
|
SnapshotMoveData: boolptr.True(),
|
||||||
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
ExcludedClusterScopedResources: autoExcludeClusterScopedResources,
|
||||||
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
ExcludedNamespaceScopedResources: autoExcludeNamespaceScopedResources,
|
||||||
|
IncludedNamespaces: []string{"*"},
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
@@ -1430,6 +1447,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||||||
ExcludedClusterScopedResources: append([]string{"clusterroles"}, autoExcludeClusterScopedResources...),
|
ExcludedClusterScopedResources: append([]string{"clusterroles"}, autoExcludeClusterScopedResources...),
|
||||||
IncludedNamespaceScopedResources: []string{"pods"},
|
IncludedNamespaceScopedResources: []string{"pods"},
|
||||||
ExcludedNamespaceScopedResources: append([]string{"secrets"}, autoExcludeNamespaceScopedResources...),
|
ExcludedNamespaceScopedResources: append([]string{"secrets"}, autoExcludeNamespaceScopedResources...),
|
||||||
|
IncludedNamespaces: []string{"*"},
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
@@ -1479,6 +1497,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||||||
ExcludedClusterScopedResources: append([]string{"clusterroles"}, autoExcludeClusterScopedResources...),
|
ExcludedClusterScopedResources: append([]string{"clusterroles"}, autoExcludeClusterScopedResources...),
|
||||||
IncludedNamespaceScopedResources: []string{"pods"},
|
IncludedNamespaceScopedResources: []string{"pods"},
|
||||||
ExcludedNamespaceScopedResources: append([]string{"secrets"}, autoExcludeNamespaceScopedResources...),
|
ExcludedNamespaceScopedResources: append([]string{"secrets"}, autoExcludeNamespaceScopedResources...),
|
||||||
|
IncludedNamespaces: []string{"*"},
|
||||||
},
|
},
|
||||||
Status: velerov1api.BackupStatus{
|
Status: velerov1api.BackupStatus{
|
||||||
Phase: velerov1api.BackupPhaseFinalizing,
|
Phase: velerov1api.BackupPhaseFinalizing,
|
||||||
|
|||||||
@@ -200,7 +200,7 @@ func (r *backupQueueReconciler) checkForEarlierRunnableBackups(backup *velerov1a
|
|||||||
func namespacesForBackup(backup *velerov1api.Backup, clusterNamespaces []string) []string {
|
func namespacesForBackup(backup *velerov1api.Backup, clusterNamespaces []string) []string {
|
||||||
// Ignore error here. If a backup has invalid namespace wildcards, the backup controller
|
// Ignore error here. If a backup has invalid namespace wildcards, the backup controller
|
||||||
// will validate and fail it. Consider the ns list empty for conflict detection purposes.
|
// will validate and fail it. Consider the ns list empty for conflict detection purposes.
|
||||||
nsList, err := collections.NewNamespaceIncludesExcludes().Includes(backup.Spec.IncludedNamespaces...).Excludes(backup.Spec.ExcludedNamespaces...).ActiveNamespaces(clusterNamespaces).ResolveNamespaceList()
|
nsList, err := collections.NewNamespaceIncludesExcludes().Includes(backup.Spec.IncludedNamespaces...).Excludes(backup.Spec.ExcludedNamespaces...).ActiveNamespaces(clusterNamespaces).ResolveNamespaceList(true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []string{}
|
return []string{}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2407,7 +2407,7 @@ func extractNamespacesFromBackup(backupResources map[string]*archive.ResourceIte
|
|||||||
// expandNamespaceWildcards expands wildcard patterns in namespace includes/excludes
|
// expandNamespaceWildcards expands wildcard patterns in namespace includes/excludes
|
||||||
// and updates the restore context with the expanded patterns and status
|
// and updates the restore context with the expanded patterns and status
|
||||||
func (ctx *restoreContext) expandNamespaceWildcards(backupResources map[string]*archive.ResourceItems) error {
|
func (ctx *restoreContext) expandNamespaceWildcards(backupResources map[string]*archive.ResourceItems) error {
|
||||||
if !wildcard.ShouldExpandWildcards(ctx.restore.Spec.IncludedNamespaces, ctx.restore.Spec.ExcludedNamespaces) {
|
if !wildcard.ShouldExpandWildcards(ctx.restore.Spec.IncludedNamespaces, ctx.restore.Spec.ExcludedNamespaces, false) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -93,15 +93,6 @@ func TestExpandNamespaceWildcards(t *testing.T) {
|
|||||||
expectedExcludeMatches: []string{"app-test"},
|
expectedExcludeMatches: []string{"app-test"},
|
||||||
expectedWildcardResult: []string{"app-dev", "app-prod"},
|
expectedWildcardResult: []string{"app-dev", "app-prod"},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "Error: wildcard * in excludes",
|
|
||||||
includeNamespaces: []string{"test*"},
|
|
||||||
excludeNamespaces: []string{"*"},
|
|
||||||
backupResources: map[string]*archive.ResourceItems{
|
|
||||||
"namespaces": {ItemsByNamespace: map[string][]string{"test1": {}}},
|
|
||||||
},
|
|
||||||
expectedError: "wildcard '*' is not allowed in restore excludes",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "Empty backup - no matches",
|
name: "Empty backup - no matches",
|
||||||
includeNamespaces: []string{"test*"},
|
includeNamespaces: []string{"test*"},
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package collections
|
package collections
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/vmware-tanzu/velero/internal/resourcepolicies"
|
"github.com/vmware-tanzu/velero/internal/resourcepolicies"
|
||||||
@@ -149,15 +150,18 @@ func (nie *NamespaceIncludesExcludes) ShouldInclude(s string) bool {
|
|||||||
// IncludeEverything returns true if the includes list is empty or '*'
|
// IncludeEverything returns true if the includes list is empty or '*'
|
||||||
// and the excludes list is empty, or false otherwise.
|
// and the excludes list is empty, or false otherwise.
|
||||||
func (nie *NamespaceIncludesExcludes) IncludeEverything() bool {
|
func (nie *NamespaceIncludesExcludes) IncludeEverything() bool {
|
||||||
return nie.includesExcludes.IncludeEverything()
|
return nie.includesExcludes.excludes.Len() == 0 &&
|
||||||
|
(nie.includesExcludes.includes.Len() == 0 ||
|
||||||
|
(nie.includesExcludes.includes.Len() == 1 && nie.includesExcludes.includes.Has("*")) ||
|
||||||
|
slices.Equal(nie.includesExcludes.includes.List(), nie.activeNamespaces))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempts to expand wildcard patterns, if any, in the includes and excludes lists.
|
// Attempts to expand wildcard patterns, if any, in the includes and excludes lists.
|
||||||
func (nie *NamespaceIncludesExcludes) ExpandIncludesExcludes() error {
|
func (nie *NamespaceIncludesExcludes) ExpandIncludesExcludes(fromBackup bool) error {
|
||||||
includes := nie.GetIncludes()
|
includes := nie.GetIncludes()
|
||||||
excludes := nie.GetExcludes()
|
excludes := nie.GetExcludes()
|
||||||
|
|
||||||
if wildcard.ShouldExpandWildcards(includes, excludes) {
|
if wildcard.ShouldExpandWildcards(includes, excludes, fromBackup) {
|
||||||
expandedIncludes, expandedExcludes, err := wildcard.ExpandWildcards(
|
expandedIncludes, expandedExcludes, err := wildcard.ExpandWildcards(
|
||||||
nie.activeNamespaces, includes, excludes)
|
nie.activeNamespaces, includes, excludes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -174,10 +178,10 @@ func (nie *NamespaceIncludesExcludes) ExpandIncludesExcludes() error {
|
|||||||
|
|
||||||
// ResolveNamespaceList returns a list of all namespaces which will be backed up.
|
// ResolveNamespaceList returns a list of all namespaces which will be backed up.
|
||||||
// The second return value indicates whether wildcard expansion was performed.
|
// The second return value indicates whether wildcard expansion was performed.
|
||||||
func (nie *NamespaceIncludesExcludes) ResolveNamespaceList() ([]string, error) {
|
func (nie *NamespaceIncludesExcludes) ResolveNamespaceList(fromBackup bool) ([]string, error) {
|
||||||
// Check if this is being called by non-backup processing e.g. backup queue controller
|
// Check if this is being called by non-backup processing e.g. backup queue controller
|
||||||
if !nie.wildcardExpanded {
|
if !nie.wildcardExpanded {
|
||||||
err := nie.ExpandIncludesExcludes()
|
err := nie.ExpandIncludesExcludes(fromBackup)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1049,6 +1049,7 @@ func TestExpandIncludesExcludes(t *testing.T) {
|
|||||||
expectedExcludes []string
|
expectedExcludes []string
|
||||||
expectedWildcardExpanded bool
|
expectedWildcardExpanded bool
|
||||||
expectError bool
|
expectError bool
|
||||||
|
fromBackup bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "no wildcards - should not expand",
|
name: "no wildcards - should not expand",
|
||||||
@@ -1059,16 +1060,18 @@ func TestExpandIncludesExcludes(t *testing.T) {
|
|||||||
expectedExcludes: []string{"kube-public"},
|
expectedExcludes: []string{"kube-public"},
|
||||||
expectedWildcardExpanded: false,
|
expectedWildcardExpanded: false,
|
||||||
expectError: false,
|
expectError: false,
|
||||||
|
fromBackup: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "asterisk alone - should not expand",
|
name: "asterisk alone - should expand",
|
||||||
includes: []string{"*"},
|
includes: []string{"*"},
|
||||||
excludes: []string{},
|
excludes: []string{},
|
||||||
activeNamespaces: []string{"default", "kube-system", "test"},
|
activeNamespaces: []string{"default", "kube-system", "test"},
|
||||||
expectedIncludes: []string{"*"},
|
expectedIncludes: []string{"default", "kube-system", "test"},
|
||||||
expectedExcludes: []string{},
|
expectedExcludes: []string{},
|
||||||
expectedWildcardExpanded: false,
|
expectedWildcardExpanded: true,
|
||||||
expectError: false,
|
expectError: false,
|
||||||
|
fromBackup: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "wildcard in includes - should expand",
|
name: "wildcard in includes - should expand",
|
||||||
@@ -1079,6 +1082,7 @@ func TestExpandIncludesExcludes(t *testing.T) {
|
|||||||
expectedExcludes: []string{},
|
expectedExcludes: []string{},
|
||||||
expectedWildcardExpanded: true,
|
expectedWildcardExpanded: true,
|
||||||
expectError: false,
|
expectError: false,
|
||||||
|
fromBackup: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "wildcard in excludes - should expand",
|
name: "wildcard in excludes - should expand",
|
||||||
@@ -1089,6 +1093,7 @@ func TestExpandIncludesExcludes(t *testing.T) {
|
|||||||
expectedExcludes: []string{"kube-test", "app-test"},
|
expectedExcludes: []string{"kube-test", "app-test"},
|
||||||
expectedWildcardExpanded: true,
|
expectedWildcardExpanded: true,
|
||||||
expectError: false,
|
expectError: false,
|
||||||
|
fromBackup: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "wildcards in both includes and excludes",
|
name: "wildcards in both includes and excludes",
|
||||||
@@ -1099,6 +1104,7 @@ func TestExpandIncludesExcludes(t *testing.T) {
|
|||||||
expectedExcludes: []string{"kube-test", "app-test"},
|
expectedExcludes: []string{"kube-test", "app-test"},
|
||||||
expectedWildcardExpanded: true,
|
expectedWildcardExpanded: true,
|
||||||
expectError: false,
|
expectError: false,
|
||||||
|
fromBackup: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "wildcard pattern matches nothing",
|
name: "wildcard pattern matches nothing",
|
||||||
@@ -1109,6 +1115,7 @@ func TestExpandIncludesExcludes(t *testing.T) {
|
|||||||
expectedExcludes: []string{},
|
expectedExcludes: []string{},
|
||||||
expectedWildcardExpanded: true,
|
expectedWildcardExpanded: true,
|
||||||
expectError: false,
|
expectError: false,
|
||||||
|
fromBackup: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "mix of wildcards and non-wildcards in includes",
|
name: "mix of wildcards and non-wildcards in includes",
|
||||||
@@ -1119,6 +1126,7 @@ func TestExpandIncludesExcludes(t *testing.T) {
|
|||||||
expectedExcludes: []string{},
|
expectedExcludes: []string{},
|
||||||
expectedWildcardExpanded: true,
|
expectedWildcardExpanded: true,
|
||||||
expectError: false,
|
expectError: false,
|
||||||
|
fromBackup: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "question mark wildcard",
|
name: "question mark wildcard",
|
||||||
@@ -1129,6 +1137,7 @@ func TestExpandIncludesExcludes(t *testing.T) {
|
|||||||
expectedExcludes: []string{},
|
expectedExcludes: []string{},
|
||||||
expectedWildcardExpanded: true,
|
expectedWildcardExpanded: true,
|
||||||
expectError: false,
|
expectError: false,
|
||||||
|
fromBackup: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "empty activeNamespaces with wildcards",
|
name: "empty activeNamespaces with wildcards",
|
||||||
@@ -1139,6 +1148,7 @@ func TestExpandIncludesExcludes(t *testing.T) {
|
|||||||
expectedExcludes: []string{},
|
expectedExcludes: []string{},
|
||||||
expectedWildcardExpanded: true,
|
expectedWildcardExpanded: true,
|
||||||
expectError: false,
|
expectError: false,
|
||||||
|
fromBackup: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "invalid wildcard pattern - consecutive asterisks",
|
name: "invalid wildcard pattern - consecutive asterisks",
|
||||||
@@ -1149,6 +1159,7 @@ func TestExpandIncludesExcludes(t *testing.T) {
|
|||||||
expectedExcludes: []string{},
|
expectedExcludes: []string{},
|
||||||
expectedWildcardExpanded: false,
|
expectedWildcardExpanded: false,
|
||||||
expectError: true,
|
expectError: true,
|
||||||
|
fromBackup: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1159,7 +1170,7 @@ func TestExpandIncludesExcludes(t *testing.T) {
|
|||||||
Includes(tc.includes...).
|
Includes(tc.includes...).
|
||||||
Excludes(tc.excludes...)
|
Excludes(tc.excludes...)
|
||||||
|
|
||||||
err := nie.ExpandIncludesExcludes()
|
err := nie.ExpandIncludesExcludes(tc.fromBackup)
|
||||||
|
|
||||||
if tc.expectError {
|
if tc.expectError {
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
@@ -1192,6 +1203,7 @@ func TestResolveNamespaceList(t *testing.T) {
|
|||||||
activeNamespaces []string
|
activeNamespaces []string
|
||||||
expectedNamespaces []string
|
expectedNamespaces []string
|
||||||
preExpandWildcards bool
|
preExpandWildcards bool
|
||||||
|
fromBackup bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "no includes/excludes - all active namespaces",
|
name: "no includes/excludes - all active namespaces",
|
||||||
@@ -1199,6 +1211,7 @@ func TestResolveNamespaceList(t *testing.T) {
|
|||||||
excludes: []string{},
|
excludes: []string{},
|
||||||
activeNamespaces: []string{"default", "kube-system", "test"},
|
activeNamespaces: []string{"default", "kube-system", "test"},
|
||||||
expectedNamespaces: []string{"default", "kube-system", "test"},
|
expectedNamespaces: []string{"default", "kube-system", "test"},
|
||||||
|
fromBackup: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "asterisk includes - all active namespaces",
|
name: "asterisk includes - all active namespaces",
|
||||||
@@ -1206,6 +1219,7 @@ func TestResolveNamespaceList(t *testing.T) {
|
|||||||
excludes: []string{},
|
excludes: []string{},
|
||||||
activeNamespaces: []string{"default", "kube-system", "test"},
|
activeNamespaces: []string{"default", "kube-system", "test"},
|
||||||
expectedNamespaces: []string{"default", "kube-system", "test"},
|
expectedNamespaces: []string{"default", "kube-system", "test"},
|
||||||
|
fromBackup: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "specific includes - only those namespaces",
|
name: "specific includes - only those namespaces",
|
||||||
@@ -1213,6 +1227,7 @@ func TestResolveNamespaceList(t *testing.T) {
|
|||||||
excludes: []string{},
|
excludes: []string{},
|
||||||
activeNamespaces: []string{"default", "kube-system", "test"},
|
activeNamespaces: []string{"default", "kube-system", "test"},
|
||||||
expectedNamespaces: []string{"default", "test"},
|
expectedNamespaces: []string{"default", "test"},
|
||||||
|
fromBackup: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "includes with excludes",
|
name: "includes with excludes",
|
||||||
@@ -1220,6 +1235,7 @@ func TestResolveNamespaceList(t *testing.T) {
|
|||||||
excludes: []string{"kube-system"},
|
excludes: []string{"kube-system"},
|
||||||
activeNamespaces: []string{"default", "kube-system", "test"},
|
activeNamespaces: []string{"default", "kube-system", "test"},
|
||||||
expectedNamespaces: []string{"default", "test"},
|
expectedNamespaces: []string{"default", "test"},
|
||||||
|
fromBackup: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "wildcard includes - expands and filters",
|
name: "wildcard includes - expands and filters",
|
||||||
@@ -1227,6 +1243,7 @@ func TestResolveNamespaceList(t *testing.T) {
|
|||||||
excludes: []string{},
|
excludes: []string{},
|
||||||
activeNamespaces: []string{"default", "kube-system", "kube-public", "test"},
|
activeNamespaces: []string{"default", "kube-system", "kube-public", "test"},
|
||||||
expectedNamespaces: []string{"kube-system", "kube-public"},
|
expectedNamespaces: []string{"kube-system", "kube-public"},
|
||||||
|
fromBackup: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "wildcard includes with wildcard excludes",
|
name: "wildcard includes with wildcard excludes",
|
||||||
@@ -1234,6 +1251,7 @@ func TestResolveNamespaceList(t *testing.T) {
|
|||||||
excludes: []string{"*-test"},
|
excludes: []string{"*-test"},
|
||||||
activeNamespaces: []string{"app-prod", "app-dev", "app-test", "default"},
|
activeNamespaces: []string{"app-prod", "app-dev", "app-test", "default"},
|
||||||
expectedNamespaces: []string{"app-prod", "app-dev"},
|
expectedNamespaces: []string{"app-prod", "app-dev"},
|
||||||
|
fromBackup: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "wildcard matches nothing - empty result",
|
name: "wildcard matches nothing - empty result",
|
||||||
@@ -1241,6 +1259,7 @@ func TestResolveNamespaceList(t *testing.T) {
|
|||||||
excludes: []string{},
|
excludes: []string{},
|
||||||
activeNamespaces: []string{"default", "kube-system"},
|
activeNamespaces: []string{"default", "kube-system"},
|
||||||
expectedNamespaces: []string{},
|
expectedNamespaces: []string{},
|
||||||
|
fromBackup: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "empty active namespaces",
|
name: "empty active namespaces",
|
||||||
@@ -1248,6 +1267,7 @@ func TestResolveNamespaceList(t *testing.T) {
|
|||||||
excludes: []string{},
|
excludes: []string{},
|
||||||
activeNamespaces: []string{},
|
activeNamespaces: []string{},
|
||||||
expectedNamespaces: []string{},
|
expectedNamespaces: []string{},
|
||||||
|
fromBackup: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "includes namespace not in active namespaces",
|
name: "includes namespace not in active namespaces",
|
||||||
@@ -1255,6 +1275,7 @@ func TestResolveNamespaceList(t *testing.T) {
|
|||||||
excludes: []string{},
|
excludes: []string{},
|
||||||
activeNamespaces: []string{"default", "test"},
|
activeNamespaces: []string{"default", "test"},
|
||||||
expectedNamespaces: []string{"default"},
|
expectedNamespaces: []string{"default"},
|
||||||
|
fromBackup: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "excludes all namespaces from includes",
|
name: "excludes all namespaces from includes",
|
||||||
@@ -1262,6 +1283,7 @@ func TestResolveNamespaceList(t *testing.T) {
|
|||||||
excludes: []string{"default", "test"},
|
excludes: []string{"default", "test"},
|
||||||
activeNamespaces: []string{"default", "test", "prod"},
|
activeNamespaces: []string{"default", "test", "prod"},
|
||||||
expectedNamespaces: []string{},
|
expectedNamespaces: []string{},
|
||||||
|
fromBackup: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "pre-expanded wildcards - should not expand again",
|
name: "pre-expanded wildcards - should not expand again",
|
||||||
@@ -1270,6 +1292,7 @@ func TestResolveNamespaceList(t *testing.T) {
|
|||||||
activeNamespaces: []string{"default", "kube-system", "kube-public"},
|
activeNamespaces: []string{"default", "kube-system", "kube-public"},
|
||||||
expectedNamespaces: []string{"kube-system", "kube-public"},
|
expectedNamespaces: []string{"kube-system", "kube-public"},
|
||||||
preExpandWildcards: true,
|
preExpandWildcards: true,
|
||||||
|
fromBackup: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "question mark wildcard pattern",
|
name: "question mark wildcard pattern",
|
||||||
@@ -1277,6 +1300,7 @@ func TestResolveNamespaceList(t *testing.T) {
|
|||||||
excludes: []string{},
|
excludes: []string{},
|
||||||
activeNamespaces: []string{"ns-1", "ns-2", "ns-10", "default"},
|
activeNamespaces: []string{"ns-1", "ns-2", "ns-10", "default"},
|
||||||
expectedNamespaces: []string{"ns-1", "ns-2"},
|
expectedNamespaces: []string{"ns-1", "ns-2"},
|
||||||
|
fromBackup: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1289,11 +1313,11 @@ func TestResolveNamespaceList(t *testing.T) {
|
|||||||
|
|
||||||
// Pre-expand wildcards if requested
|
// Pre-expand wildcards if requested
|
||||||
if tc.preExpandWildcards {
|
if tc.preExpandWildcards {
|
||||||
err := nie.ExpandIncludesExcludes()
|
err := nie.ExpandIncludesExcludes(tc.fromBackup)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
namespaces, err := nie.ResolveNamespaceList()
|
namespaces, err := nie.ResolveNamespaceList(tc.fromBackup)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Convert to sets for order-independent comparison
|
// Convert to sets for order-independent comparison
|
||||||
@@ -1311,18 +1335,21 @@ func TestResolveNamespaceListError(t *testing.T) {
|
|||||||
includes []string
|
includes []string
|
||||||
excludes []string
|
excludes []string
|
||||||
activeNamespaces []string
|
activeNamespaces []string
|
||||||
|
fromBackup bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "invalid wildcard pattern in includes",
|
name: "invalid wildcard pattern in includes",
|
||||||
includes: []string{"kube-**"},
|
includes: []string{"kube-**"},
|
||||||
excludes: []string{},
|
excludes: []string{},
|
||||||
activeNamespaces: []string{"default"},
|
activeNamespaces: []string{"default"},
|
||||||
|
fromBackup: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "invalid wildcard pattern in excludes",
|
name: "invalid wildcard pattern in excludes",
|
||||||
includes: []string{"default"},
|
includes: []string{"default"},
|
||||||
excludes: []string{"test-**"},
|
excludes: []string{"test-**"},
|
||||||
activeNamespaces: []string{"default"},
|
activeNamespaces: []string{"default"},
|
||||||
|
fromBackup: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1333,7 +1360,7 @@ func TestResolveNamespaceListError(t *testing.T) {
|
|||||||
Includes(tc.includes...).
|
Includes(tc.includes...).
|
||||||
Excludes(tc.excludes...)
|
Excludes(tc.excludes...)
|
||||||
|
|
||||||
_, err := nie.ResolveNamespaceList()
|
_, err := nie.ResolveNamespaceList(tc.fromBackup)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -1347,6 +1374,7 @@ func TestNamespaceIncludesExcludesShouldIncludeAfterWildcardExpansion(t *testing
|
|||||||
activeNamespaces []string
|
activeNamespaces []string
|
||||||
testNamespace string
|
testNamespace string
|
||||||
expectedResult bool
|
expectedResult bool
|
||||||
|
fromBackup bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "wildcard expanded to empty includes - should not include anything",
|
name: "wildcard expanded to empty includes - should not include anything",
|
||||||
@@ -1355,6 +1383,7 @@ func TestNamespaceIncludesExcludesShouldIncludeAfterWildcardExpansion(t *testing
|
|||||||
activeNamespaces: []string{"default", "kube-system"},
|
activeNamespaces: []string{"default", "kube-system"},
|
||||||
testNamespace: "default",
|
testNamespace: "default",
|
||||||
expectedResult: false,
|
expectedResult: false,
|
||||||
|
fromBackup: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "wildcard expanded with matches - should include matched namespace",
|
name: "wildcard expanded with matches - should include matched namespace",
|
||||||
@@ -1363,6 +1392,7 @@ func TestNamespaceIncludesExcludesShouldIncludeAfterWildcardExpansion(t *testing
|
|||||||
activeNamespaces: []string{"default", "kube-system", "kube-public"},
|
activeNamespaces: []string{"default", "kube-system", "kube-public"},
|
||||||
testNamespace: "kube-system",
|
testNamespace: "kube-system",
|
||||||
expectedResult: true,
|
expectedResult: true,
|
||||||
|
fromBackup: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "wildcard expanded with matches - should not include unmatched namespace",
|
name: "wildcard expanded with matches - should not include unmatched namespace",
|
||||||
@@ -1371,6 +1401,7 @@ func TestNamespaceIncludesExcludesShouldIncludeAfterWildcardExpansion(t *testing
|
|||||||
activeNamespaces: []string{"default", "kube-system", "kube-public"},
|
activeNamespaces: []string{"default", "kube-system", "kube-public"},
|
||||||
testNamespace: "default",
|
testNamespace: "default",
|
||||||
expectedResult: false,
|
expectedResult: false,
|
||||||
|
fromBackup: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "no wildcard expansion - empty includes means include all",
|
name: "no wildcard expansion - empty includes means include all",
|
||||||
@@ -1379,6 +1410,7 @@ func TestNamespaceIncludesExcludesShouldIncludeAfterWildcardExpansion(t *testing
|
|||||||
activeNamespaces: []string{"default", "kube-system"},
|
activeNamespaces: []string{"default", "kube-system"},
|
||||||
testNamespace: "default",
|
testNamespace: "default",
|
||||||
expectedResult: true,
|
expectedResult: true,
|
||||||
|
fromBackup: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1389,7 +1421,7 @@ func TestNamespaceIncludesExcludesShouldIncludeAfterWildcardExpansion(t *testing
|
|||||||
Includes(tc.includes...).
|
Includes(tc.includes...).
|
||||||
Excludes(tc.excludes...)
|
Excludes(tc.excludes...)
|
||||||
|
|
||||||
err := nie.ExpandIncludesExcludes()
|
err := nie.ExpandIncludesExcludes(tc.fromBackup)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
result := nie.ShouldInclude(tc.testNamespace)
|
result := nie.ShouldInclude(tc.testNamespace)
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ func TestGetVolumesByPod(t *testing.T) {
|
|||||||
Volumes: []corev1api.Volume{
|
Volumes: []corev1api.Volume{
|
||||||
// PVB Volumes
|
// PVB Volumes
|
||||||
{Name: "pvbPV1"}, {Name: "pvbPV2"}, {Name: "pvbPV3"},
|
{Name: "pvbPV1"}, {Name: "pvbPV2"}, {Name: "pvbPV3"},
|
||||||
/// Excluded from PVB because volume mounting default service account token
|
/// Excluded from PVB because column mounting default service account token
|
||||||
{Name: "default-token-5xq45"},
|
{Name: "default-token-5xq45"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -8,14 +8,19 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ShouldExpandWildcards(includes []string, excludes []string) bool {
|
func ShouldExpandWildcards(includes []string, excludes []string, fromBackup bool) bool {
|
||||||
|
// Only expand wildcards if this is being called from a backup request.
|
||||||
|
// We don't want to expand wildcard patterns in restore request,
|
||||||
|
// because restore needs the IncludeEverything function to
|
||||||
|
// determine whether to restore cluster-scoped resources.
|
||||||
|
// Expand wildcards causes the IncludeEverything function to return false,
|
||||||
|
// which will cause restore to skip cluster-scoped resources.
|
||||||
|
if !fromBackup {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
wildcardFound := false
|
wildcardFound := false
|
||||||
for _, include := range includes {
|
for _, include := range includes {
|
||||||
// Special case: "*" alone means "match all" - don't expand
|
|
||||||
if include == "*" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if containsWildcardPattern(include) {
|
if containsWildcardPattern(include) {
|
||||||
wildcardFound = true
|
wildcardFound = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,106 +9,141 @@ import (
|
|||||||
|
|
||||||
func TestShouldExpandWildcards(t *testing.T) {
|
func TestShouldExpandWildcards(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
includes []string
|
includes []string
|
||||||
excludes []string
|
excludes []string
|
||||||
expected bool
|
fromBackup bool
|
||||||
|
expected bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "no wildcards",
|
name: "no wildcards",
|
||||||
includes: []string{"ns1", "ns2"},
|
includes: []string{"ns1", "ns2"},
|
||||||
excludes: []string{"ns3", "ns4"},
|
excludes: []string{"ns3", "ns4"},
|
||||||
expected: false,
|
fromBackup: true,
|
||||||
|
expected: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "includes has star - should not expand",
|
name: "includes has star - should expand",
|
||||||
includes: []string{"*"},
|
includes: []string{"*"},
|
||||||
excludes: []string{"ns1"},
|
excludes: []string{"ns1"},
|
||||||
expected: false,
|
fromBackup: true,
|
||||||
|
expected: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "includes has star after a wildcard pattern - should not expand",
|
excludes: []string{"ns3", "ns4"},
|
||||||
includes: []string{"ns*", "*"},
|
fromBackup: true,
|
||||||
excludes: []string{"ns1"},
|
expected: false,
|
||||||
expected: false,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "includes has wildcard pattern",
|
name: "includes has star - should expand",
|
||||||
includes: []string{"ns*"},
|
includes: []string{"*"},
|
||||||
excludes: []string{"ns1"},
|
excludes: []string{"ns1"},
|
||||||
expected: true,
|
fromBackup: true,
|
||||||
|
expected: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "excludes has wildcard pattern",
|
name: "includes has star after a wildcard pattern - should expand",
|
||||||
includes: []string{"ns1"},
|
includes: []string{"ns*", "*"},
|
||||||
excludes: []string{"ns*"},
|
excludes: []string{"ns1"},
|
||||||
expected: true,
|
fromBackup: true,
|
||||||
|
expected: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "both have wildcard patterns",
|
name: "includes has wildcard pattern",
|
||||||
includes: []string{"app-*"},
|
includes: []string{"ns*"},
|
||||||
excludes: []string{"test-*"},
|
excludes: []string{"ns1"},
|
||||||
expected: true,
|
fromBackup: true,
|
||||||
|
expected: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "includes has star and wildcard - star takes precedence",
|
name: "excludes has wildcard pattern",
|
||||||
includes: []string{"*", "ns*"},
|
includes: []string{"ns1"},
|
||||||
excludes: []string{},
|
excludes: []string{"ns*"},
|
||||||
expected: false,
|
fromBackup: true,
|
||||||
|
expected: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "double asterisk should be detected as wildcard",
|
name: "both have wildcard patterns",
|
||||||
includes: []string{"**"},
|
includes: []string{"app-*"},
|
||||||
excludes: []string{},
|
excludes: []string{"test-*"},
|
||||||
expected: true, // ** is a wildcard pattern (but will error during validation)
|
fromBackup: true,
|
||||||
|
expected: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "empty slices",
|
name: "includes has star and wildcard - should expand",
|
||||||
includes: []string{},
|
includes: []string{"*", "ns*"},
|
||||||
excludes: []string{},
|
excludes: []string{},
|
||||||
expected: false,
|
fromBackup: true,
|
||||||
|
expected: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "complex wildcard patterns",
|
name: "double asterisk should be detected as wildcard",
|
||||||
includes: []string{"*-prod"},
|
includes: []string{"**"},
|
||||||
excludes: []string{"test-*-staging"},
|
excludes: []string{},
|
||||||
expected: true,
|
fromBackup: true,
|
||||||
|
expected: true, // ** is a wildcard pattern (but will error during validation)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "question mark wildcard",
|
name: "empty slices",
|
||||||
includes: []string{"ns?"},
|
includes: []string{},
|
||||||
excludes: []string{},
|
excludes: []string{},
|
||||||
expected: true, // question mark is now considered a wildcard
|
fromBackup: true,
|
||||||
|
expected: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "character class wildcard",
|
name: "complex wildcard patterns",
|
||||||
includes: []string{"ns[abc]"},
|
includes: []string{"*-prod"},
|
||||||
excludes: []string{},
|
excludes: []string{"test-*-staging"},
|
||||||
expected: true, // character class is considered wildcard
|
fromBackup: true,
|
||||||
|
expected: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "brace alternatives wildcard",
|
name: "question mark wildcard",
|
||||||
includes: []string{"ns{prod,staging}"},
|
includes: []string{"ns?"},
|
||||||
excludes: []string{},
|
excludes: []string{},
|
||||||
expected: false, // brace alternatives are not supported
|
fromBackup: true,
|
||||||
|
expected: true, // question mark is now considered a wildcard
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "dot is literal - not wildcard",
|
name: "character class wildcard",
|
||||||
includes: []string{"app.prod"},
|
includes: []string{"ns[abc]"},
|
||||||
excludes: []string{},
|
excludes: []string{},
|
||||||
expected: false, // dot is literal, not wildcard
|
fromBackup: true,
|
||||||
|
expected: true, // character class is considered wildcard
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "plus is literal - not wildcard",
|
name: "brace alternatives wildcard",
|
||||||
includes: []string{"app+"},
|
includes: []string{"ns{prod,staging}"},
|
||||||
excludes: []string{},
|
excludes: []string{},
|
||||||
expected: false, // plus is literal, not wildcard
|
fromBackup: true,
|
||||||
|
expected: false, // brace alternatives are not supported
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "dot is literal - not wildcard",
|
||||||
|
includes: []string{"app.prod"},
|
||||||
|
excludes: []string{},
|
||||||
|
fromBackup: true,
|
||||||
|
expected: false, // dot is literal, not wildcard
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "plus is literal - not wildcard",
|
||||||
|
includes: []string{"app+"},
|
||||||
|
excludes: []string{},
|
||||||
|
fromBackup: true,
|
||||||
|
expected: false, // plus is literal, not wildcard
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "includes has a wildcard pattern from restore - should not expand",
|
||||||
|
includes: []string{"ns*"},
|
||||||
|
excludes: []string{"ns1"},
|
||||||
|
fromBackup: false,
|
||||||
|
expected: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
result := ShouldExpandWildcards(tt.includes, tt.excludes)
|
result := ShouldExpandWildcards(tt.includes, tt.excludes, tt.fromBackup)
|
||||||
assert.Equal(t, tt.expected, result)
|
assert.Equal(t, tt.expected, result)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user