diff --git a/changelogs/unreleased/9870-shubham-pampattiwar b/changelogs/unreleased/9870-shubham-pampattiwar new file mode 100644 index 000000000..76e44931c --- /dev/null +++ b/changelogs/unreleased/9870-shubham-pampattiwar @@ -0,0 +1 @@ +Fix backup performance regression when using includedNamespaces ["*"] by restoring cross-namespace API listing optimization diff --git a/pkg/backup/backup_test.go b/pkg/backup/backup_test.go index 072f3cd51..5607db9dd 100644 --- a/pkg/backup/backup_test.go +++ b/pkg/backup/backup_test.go @@ -5407,6 +5407,8 @@ func TestBackupNamespaces(t *testing.T) { want: []string{ "resources/namespaces/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", }, }, { @@ -5424,6 +5426,29 @@ func TestBackupNamespaces(t *testing.T) { }, want: []string{}, }, + { + name: "Wildcard star with excluded namespaces test", + backup: defaultBackup().IncludedNamespaces("*").ExcludedNamespaces("ns-2").Result(), + apiResources: []*test.APIResource{ + test.Namespaces( + builder.ForNamespace("ns-1").Phase(corev1api.NamespaceActive).Result(), + builder.ForNamespace("ns-2").Phase(corev1api.NamespaceActive).Result(), + builder.ForNamespace("ns-3").Phase(corev1api.NamespaceActive).Result(), + ), + test.Deployments( + builder.ForDeployment("ns-1", "deploy-1").Result(), + builder.ForDeployment("ns-2", "deploy-2").Result(), + ), + }, + want: []string{ + "resources/namespaces/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", + "resources/deployments.apps/namespaces/ns-1/deploy-1.json", + "resources/deployments.apps/v1-preferredversion/namespaces/ns-1/deploy-1.json", + }, + }, { name: "Default namespace filter test", backup: defaultBackup().Result(), @@ -5440,6 +5465,10 @@ func TestBackupNamespaces(t *testing.T) { want: []string{ "resources/namespaces/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/v1-preferredversion/namespaces/ns-1/deploy-1.json", }, diff --git a/pkg/backup/item_collector.go b/pkg/backup/item_collector.go index 34c42e2a2..15efca2db 100644 --- a/pkg/backup/item_collector.go +++ b/pkg/backup/item_collector.go @@ -497,7 +497,8 @@ func (r *itemCollector) getResourceItems( kind: resource.Kind, }) - if item.GetNamespace() != "" { + if item.GetNamespace() != "" && + r.backupRequest.NamespaceIncludesExcludes.ShouldInclude(item.GetNamespace()) { log.Debugf("Track namespace %s in nsTracker", item.GetNamespace()) r.nsTracker.track(item.GetNamespace()) } @@ -633,15 +634,18 @@ func coreGroupResourcePriority(resource string) int { } // getNamespacesToList examines ie and resolves the includes and excludes to a full list of -// namespaces to list. If ie is nil, the result is just "" (list across all namespaces). -// 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. +// namespaces to list. If ie is nil or it includes *, the result is just "" (list across all +// namespaces). Otherwise, the result is a list of every included namespace minus all excluded ones. func getNamespacesToList(ie *collections.NamespaceIncludesExcludes) []string { if ie == nil { return []string{""} } + if ie.ShouldInclude("*") { + // "" means all namespaces + return []string{""} + } + var list []string for _, n := range ie.GetIncludes() { if ie.ShouldInclude(n) { diff --git a/pkg/util/collections/includes_excludes_test.go b/pkg/util/collections/includes_excludes_test.go index 867397cbb..241fc9fea 100644 --- a/pkg/util/collections/includes_excludes_test.go +++ b/pkg/util/collections/includes_excludes_test.go @@ -1063,13 +1063,13 @@ func TestExpandIncludesExcludes(t *testing.T) { fromBackup: true, }, { - name: "asterisk alone - should expand", + name: "asterisk alone - should not expand", includes: []string{"*"}, excludes: []string{}, activeNamespaces: []string{"default", "kube-system", "test"}, - expectedIncludes: []string{"default", "kube-system", "test"}, + expectedIncludes: []string{"*"}, expectedExcludes: []string{}, - expectedWildcardExpanded: true, + expectedWildcardExpanded: false, expectError: false, fromBackup: true, }, diff --git a/pkg/util/wildcard/expand.go b/pkg/util/wildcard/expand.go index 2d35e5dd5..d34d8f805 100644 --- a/pkg/util/wildcard/expand.go +++ b/pkg/util/wildcard/expand.go @@ -26,6 +26,13 @@ func ShouldExpandWildcards(includes []string, excludes []string, fromBackup bool wildcardFound := false for _, include := range includes { + // "*" alone means "match all" - don't expand, so that + // getNamespacesToList can use a single cross-namespace API call + // instead of per-namespace calls. + if include == "*" { + return false + } + if containsWildcardPattern(include) { wildcardFound = true } diff --git a/pkg/util/wildcard/expand_test.go b/pkg/util/wildcard/expand_test.go index 9851106da..36053ff64 100644 --- a/pkg/util/wildcard/expand_test.go +++ b/pkg/util/wildcard/expand_test.go @@ -23,11 +23,11 @@ func TestShouldExpandWildcards(t *testing.T) { expected: false, }, { - name: "includes has star - should expand", + name: "includes has star - should not expand", includes: []string{"*"}, excludes: []string{"ns1"}, fromBackup: true, - expected: true, + expected: false, }, { excludes: []string{"ns3", "ns4"}, @@ -35,18 +35,18 @@ func TestShouldExpandWildcards(t *testing.T) { expected: false, }, { - name: "includes has star - should expand", + name: "includes has star with wildcard excludes - should not expand", includes: []string{"*"}, - excludes: []string{"ns1"}, + excludes: []string{"ns*"}, fromBackup: true, - expected: true, + expected: false, }, { - name: "includes has star after a wildcard pattern - should expand", + name: "includes has star after a wildcard pattern - should not expand", includes: []string{"ns*", "*"}, excludes: []string{"ns1"}, fromBackup: true, - expected: true, + expected: false, }, { name: "includes has wildcard pattern", @@ -70,11 +70,11 @@ func TestShouldExpandWildcards(t *testing.T) { expected: true, }, { - name: "includes has star and wildcard - should expand", + name: "includes has star and wildcard - should not expand", includes: []string{"*", "ns*"}, excludes: []string{}, fromBackup: true, - expected: true, + expected: false, }, { name: "double asterisk should be detected as wildcard",