Merge pull request #6065 from JimDevil/feat-search

fix(search/proxy/controller): resourceregistry merge ns
This commit is contained in:
karmada-bot 2025-01-22 12:44:50 +08:00 committed by GitHub
commit 07747ed3f7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 219 additions and 45 deletions

View File

@ -228,7 +228,14 @@ func (ctl *Controller) reconcile(util.QueueKey) error {
klog.Warningf("cluster %s is notReady", cluster.Name) klog.Warningf("cluster %s is notReady", cluster.Name)
continue continue
} }
ctl.mergeResourcesByClusters(resourcesByClusters, cluster, matchedResources)
}
}
return ctl.store.UpdateCache(resourcesByClusters, registeredResources)
}
func (ctl *Controller) mergeResourcesByClusters(resourcesByClusters map[string]map[schema.GroupVersionResource]*store.MultiNamespace, cluster *clusterv1alpha1.Cluster, matchedResources map[schema.GroupVersionResource]*store.MultiNamespace) {
if _, exist := resourcesByClusters[cluster.Name]; !exist { if _, exist := resourcesByClusters[cluster.Name]; !exist {
resourcesByClusters[cluster.Name] = make(map[schema.GroupVersionResource]*store.MultiNamespace) resourcesByClusters[cluster.Name] = make(map[schema.GroupVersionResource]*store.MultiNamespace)
} }
@ -243,14 +250,14 @@ func (ctl *Controller) reconcile(util.QueueKey) error {
klog.Warningf("Resource %s is not enabled for cluster %s", resource.String(), cluster) klog.Warningf("Resource %s is not enabled for cluster %s", resource.String(), cluster)
continue continue
} }
if ns, exist := resourcesByClusters[cluster.Name][resource]; !exist {
resourcesByClusters[cluster.Name][resource] = multiNS resourcesByClusters[cluster.Name][resource] = multiNS
} else {
resourcesByClusters[cluster.Name][resource] = ns.Merge(multiNS)
} }
} }
} }
return ctl.store.UpdateCache(resourcesByClusters, registeredResources)
}
type errorHTTPHandler struct { type errorHTTPHandler struct {
requestInfo *request.RequestInfo requestInfo *request.RequestInfo
err error err error

View File

@ -22,8 +22,6 @@ import (
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"reflect" "reflect"
"sort"
"strings"
"testing" "testing"
"time" "time"
@ -104,19 +102,26 @@ func TestController(t *testing.T) {
} }
func TestController_reconcile(t *testing.T) { func TestController_reconcile(t *testing.T) {
echoStrings := func(ss ...string) string { newMultiNs := func(namespaces ...string) *store.MultiNamespace {
sort.Strings(ss) multiNs := store.NewMultiNamespace()
return strings.Join(ss, ",") if len(namespaces) == 0 {
multiNs.Add(metav1.NamespaceAll)
return multiNs
}
for _, ns := range namespaces {
multiNs.Add(ns)
}
return multiNs
} }
tests := []struct { tests := []struct {
name string name string
input []runtime.Object input []runtime.Object
want map[string]string want map[string]map[string]*store.MultiNamespace
}{ }{
{ {
name: "all empty", name: "all empty",
input: []runtime.Object{}, input: []runtime.Object{},
want: map[string]string{}, want: map[string]map[string]*store.MultiNamespace{},
}, },
{ {
name: "resource registered, while cluster not registered", name: "resource registered, while cluster not registered",
@ -133,7 +138,7 @@ func TestController_reconcile(t *testing.T) {
}, },
}, },
}, },
want: map[string]string{}, want: map[string]map[string]*store.MultiNamespace{},
}, },
{ {
name: "pod and node are registered", name: "pod and node are registered",
@ -153,9 +158,15 @@ func TestController_reconcile(t *testing.T) {
}, },
}, },
}, },
want: map[string]string{ want: map[string]map[string]*store.MultiNamespace{
"cluster1": echoStrings("pods", "nodes"), "cluster1": {
"cluster2": echoStrings("pods", "nodes"), "pods": newMultiNs(),
"nodes": newMultiNs(),
},
"cluster2": {
"pods": newMultiNs(),
"nodes": newMultiNs(),
},
}, },
}, },
{ {
@ -178,9 +189,13 @@ func TestController_reconcile(t *testing.T) {
}, },
}, },
}, },
want: map[string]string{ want: map[string]map[string]*store.MultiNamespace{
"cluster1": echoStrings("pods"), "cluster1": {
"cluster2": echoStrings("nodes"), "pods": newMultiNs(),
},
"cluster2": {
"nodes": newMultiNs(),
},
}, },
}, },
{ {
@ -203,9 +218,14 @@ func TestController_reconcile(t *testing.T) {
}, },
}, },
}, },
want: map[string]string{ want: map[string]map[string]*store.MultiNamespace{
"cluster1": echoStrings("pods", "nodes"), "cluster1": {
"cluster2": echoStrings("nodes"), "pods": newMultiNs(),
"nodes": newMultiNs(),
},
"cluster2": {
"nodes": newMultiNs(),
},
}, },
}, },
{ {
@ -226,8 +246,10 @@ func TestController_reconcile(t *testing.T) {
}, },
}, },
}, },
want: map[string]string{ want: map[string]map[string]*store.MultiNamespace{
"cluster1": echoStrings("pods"), "cluster1": {
"pods": newMultiNs(),
},
}, },
}, },
{ {
@ -258,8 +280,10 @@ func TestController_reconcile(t *testing.T) {
}, },
}, },
}, },
want: map[string]string{ want: map[string]map[string]*store.MultiNamespace{
"cluster1": echoStrings("pods"), "cluster1": {
"pods": newMultiNs(),
},
}, },
}, },
{ {
@ -278,13 +302,47 @@ func TestController_reconcile(t *testing.T) {
}, },
}, },
}, },
want: map[string]string{}, want: map[string]map[string]*store.MultiNamespace{},
},
{
name: "register pod twice in two ResourceRegistries with different namespace",
input: []runtime.Object{
newCluster("cluster1"),
newCluster("cluster2"),
&searchv1alpha1.ResourceRegistry{
ObjectMeta: metav1.ObjectMeta{Name: "rr1"},
Spec: searchv1alpha1.ResourceRegistrySpec{
TargetCluster: policyv1alpha1.ClusterAffinity{
ClusterNames: []string{"cluster1"},
},
ResourceSelectors: []searchv1alpha1.ResourceSelector{
proxytest.PodSelectorWithNS1,
},
},
},
&searchv1alpha1.ResourceRegistry{
ObjectMeta: metav1.ObjectMeta{Name: "rr2"},
Spec: searchv1alpha1.ResourceRegistrySpec{
TargetCluster: policyv1alpha1.ClusterAffinity{
ClusterNames: []string{"cluster1"},
},
ResourceSelectors: []searchv1alpha1.ResourceSelector{
proxytest.PodSelectorWithNS2,
},
},
},
},
want: map[string]map[string]*store.MultiNamespace{
"cluster1": {
"pods": newMultiNs("ns1", "ns2"),
},
},
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
actual := map[string]string{} actual := map[string]map[string]*store.MultiNamespace{}
karmadaClientset := karmadafake.NewSimpleClientset(tt.input...) karmadaClientset := karmadafake.NewSimpleClientset(tt.input...)
karmadaFactory := karmadainformers.NewSharedInformerFactory(karmadaClientset, 0) karmadaFactory := karmadainformers.NewSharedInformerFactory(karmadaClientset, 0)
@ -295,11 +353,11 @@ func TestController_reconcile(t *testing.T) {
store: &proxytest.MockStore{ store: &proxytest.MockStore{
UpdateCacheFunc: func(m map[string]map[schema.GroupVersionResource]*store.MultiNamespace, _ map[schema.GroupVersionResource]struct{}) error { UpdateCacheFunc: func(m map[string]map[schema.GroupVersionResource]*store.MultiNamespace, _ map[schema.GroupVersionResource]struct{}) error {
for clusterName, resources := range m { for clusterName, resources := range m {
resourceNames := make([]string, 0, len(resources)) resourceCaches := map[string]*store.MultiNamespace{}
for resource := range resources { for resource, multiNs := range resources {
resourceNames = append(resourceNames, resource.Resource) resourceCaches[resource.Resource] = multiNs
} }
actual[clusterName] = echoStrings(resourceNames...) actual[clusterName] = resourceCaches
} }
if len(actual) != len(m) { if len(actual) != len(m) {
return fmt.Errorf("cluster duplicate: %#v", m) return fmt.Errorf("cluster duplicate: %#v", m)

View File

@ -284,6 +284,20 @@ type MultiNamespace struct {
namespaces sets.Set[string] namespaces sets.Set[string]
} }
// Merge merges multiNS into n.
func (n *MultiNamespace) Merge(multiNS *MultiNamespace) *MultiNamespace {
if n.allNamespaces || multiNS.allNamespaces {
n.allNamespaces = true
n.namespaces = nil
return n
}
if n.Equal(multiNS) {
return n
}
n.namespaces.Insert(multiNS.namespaces.Clone().UnsortedList()...)
return n
}
// NewMultiNamespace return a new empty MultiNamespace. // NewMultiNamespace return a new empty MultiNamespace.
func NewMultiNamespace() *MultiNamespace { func NewMultiNamespace() *MultiNamespace {
return &MultiNamespace{ return &MultiNamespace{

View File

@ -1082,3 +1082,93 @@ func TestMultiNamespace_Equal(t *testing.T) {
}) })
} }
} }
func TestMultiNamespace_Merge(t *testing.T) {
type fields struct {
allNamespaces bool
namespaces sets.Set[string]
}
type args struct {
multiNS *MultiNamespace
}
tests := []struct {
name string
fields fields
args args
want *MultiNamespace
}{
{
name: "all ns merge all ns",
fields: fields{
allNamespaces: true,
},
args: args{
multiNS: &MultiNamespace{
allNamespaces: true,
},
},
want: &MultiNamespace{
allNamespaces: true,
},
},
{
name: "all ns merge not all",
fields: fields{
allNamespaces: true,
},
args: args{
multiNS: &MultiNamespace{
allNamespaces: false,
namespaces: sets.New[string]("foo"),
},
},
want: &MultiNamespace{
allNamespaces: true,
},
},
{
name: "not all ns merge all",
fields: fields{
allNamespaces: false,
namespaces: sets.New[string]("foo"),
},
args: args{
multiNS: &MultiNamespace{
allNamespaces: true,
},
},
want: &MultiNamespace{
allNamespaces: true,
},
},
{
name: "not all ns merge not all ns",
fields: fields{
allNamespaces: false,
namespaces: sets.New[string]("foo", "zoo"),
},
args: args{
multiNS: &MultiNamespace{
allNamespaces: false,
namespaces: sets.New[string]("bar"),
},
},
want: &MultiNamespace{
allNamespaces: false,
namespaces: sets.New[string]("foo", "bar", "zoo"),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
n := &MultiNamespace{
allNamespaces: tt.fields.allNamespaces,
namespaces: tt.fields.namespaces,
}
got := n.Merge(tt.args.multiNS)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("MultiNamespace.Merge() = %v, want %v", got, tt.want)
}
})
}
}

View File

@ -36,6 +36,11 @@ var (
ClusterGVR = clusterv1alpha1.SchemeGroupVersion.WithResource("cluster") ClusterGVR = clusterv1alpha1.SchemeGroupVersion.WithResource("cluster")
PodSelector = searchv1alpha1.ResourceSelector{APIVersion: PodGVK.GroupVersion().String(), Kind: PodGVK.Kind} PodSelector = searchv1alpha1.ResourceSelector{APIVersion: PodGVK.GroupVersion().String(), Kind: PodGVK.Kind}
PodSelectorWithNS1 = searchv1alpha1.ResourceSelector{APIVersion: PodGVK.GroupVersion().String(), Kind: PodGVK.Kind, Namespace: "ns1"}
PodSelectorWithNS2 = searchv1alpha1.ResourceSelector{APIVersion: PodGVK.GroupVersion().String(), Kind: PodGVK.Kind, Namespace: "ns2"}
NodeSelector = searchv1alpha1.ResourceSelector{APIVersion: NodeGVK.GroupVersion().String(), Kind: NodeGVK.Kind} NodeSelector = searchv1alpha1.ResourceSelector{APIVersion: NodeGVK.GroupVersion().String(), Kind: NodeGVK.Kind}
RestMapper *meta.DefaultRESTMapper RestMapper *meta.DefaultRESTMapper