support users can define multiple resourceinterpretercustomization
Signed-off-by: changzhen <changzhen5@huawei.com>
This commit is contained in:
parent
4870c30f9d
commit
b1977be9e5
|
@ -1,15 +1,12 @@
|
||||||
package configmanager
|
package configmanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
||||||
|
|
||||||
configv1alpha1 "github.com/karmada-io/karmada/pkg/apis/config/v1alpha1"
|
configv1alpha1 "github.com/karmada-io/karmada/pkg/apis/config/v1alpha1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CustomConfiguration provides base information about custom interpreter configuration
|
// CustomConfiguration provides base information about custom interpreter configuration
|
||||||
type CustomConfiguration interface {
|
type CustomConfiguration interface {
|
||||||
Name() string
|
Merge(rules configv1alpha1.CustomizationRules)
|
||||||
TargetResource() schema.GroupVersionKind
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// LuaScriptAccessor provides a common interface to get custom interpreter lua script
|
// LuaScriptAccessor provides a common interface to get custom interpreter lua script
|
||||||
|
@ -38,22 +35,35 @@ type resourceCustomAccessor struct {
|
||||||
statusAggregation *configv1alpha1.StatusAggregation
|
statusAggregation *configv1alpha1.StatusAggregation
|
||||||
healthInterpretation *configv1alpha1.HealthInterpretation
|
healthInterpretation *configv1alpha1.HealthInterpretation
|
||||||
dependencyInterpretation *configv1alpha1.DependencyInterpretation
|
dependencyInterpretation *configv1alpha1.DependencyInterpretation
|
||||||
configurationName string
|
|
||||||
configurationTargetGVK schema.GroupVersionKind
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewResourceCustomAccessorAccessor creates an accessor for resource interpreter customization
|
// NewResourceCustomAccessor creates an accessor for resource interpreter customization.
|
||||||
func NewResourceCustomAccessorAccessor(customization *configv1alpha1.ResourceInterpreterCustomization) CustomAccessor {
|
func NewResourceCustomAccessor() CustomAccessor {
|
||||||
return &resourceCustomAccessor{
|
return &resourceCustomAccessor{}
|
||||||
retention: customization.Spec.Customizations.Retention,
|
}
|
||||||
replicaResource: customization.Spec.Customizations.ReplicaResource,
|
|
||||||
replicaRevision: customization.Spec.Customizations.ReplicaRevision,
|
// Merge merges the given CustomizationRules with the current rules, ignore if duplicates occur.
|
||||||
statusReflection: customization.Spec.Customizations.StatusReflection,
|
func (a *resourceCustomAccessor) Merge(rules configv1alpha1.CustomizationRules) {
|
||||||
statusAggregation: customization.Spec.Customizations.StatusAggregation,
|
if rules.Retention != nil {
|
||||||
healthInterpretation: customization.Spec.Customizations.HealthInterpretation,
|
a.setRetain(rules.Retention)
|
||||||
dependencyInterpretation: customization.Spec.Customizations.DependencyInterpretation,
|
}
|
||||||
configurationName: customization.Name,
|
if rules.ReplicaResource != nil {
|
||||||
configurationTargetGVK: schema.FromAPIVersionAndKind(customization.Spec.Target.APIVersion, customization.Spec.Target.Kind),
|
a.setReplicaResource(rules.ReplicaResource)
|
||||||
|
}
|
||||||
|
if rules.ReplicaRevision != nil {
|
||||||
|
a.setReplicaRevision(rules.ReplicaRevision)
|
||||||
|
}
|
||||||
|
if rules.StatusReflection != nil {
|
||||||
|
a.setStatusReflection(rules.StatusReflection)
|
||||||
|
}
|
||||||
|
if rules.StatusAggregation != nil {
|
||||||
|
a.setStatusAggregation(rules.StatusAggregation)
|
||||||
|
}
|
||||||
|
if rules.HealthInterpretation != nil {
|
||||||
|
a.setHealthInterpretation(rules.HealthInterpretation)
|
||||||
|
}
|
||||||
|
if rules.DependencyInterpretation != nil {
|
||||||
|
a.setDependencyInterpretation(rules.DependencyInterpretation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,10 +116,79 @@ func (a *resourceCustomAccessor) GetDependencyInterpretationLuaScript() string {
|
||||||
return a.dependencyInterpretation.LuaScript
|
return a.dependencyInterpretation.LuaScript
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *resourceCustomAccessor) Name() string {
|
func (a *resourceCustomAccessor) setRetain(retention *configv1alpha1.LocalValueRetention) {
|
||||||
return a.configurationName
|
if a.retention == nil {
|
||||||
|
a.retention = retention
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if retention.LuaScript != "" && a.retention.LuaScript == "" {
|
||||||
|
a.retention.LuaScript = retention.LuaScript
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *resourceCustomAccessor) TargetResource() schema.GroupVersionKind {
|
func (a *resourceCustomAccessor) setReplicaResource(replicaResource *configv1alpha1.ReplicaResourceRequirement) {
|
||||||
return a.configurationTargetGVK
|
if a.replicaResource == nil {
|
||||||
|
a.replicaResource = replicaResource
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if replicaResource.LuaScript != "" && a.replicaResource.LuaScript == "" {
|
||||||
|
a.replicaResource.LuaScript = replicaResource.LuaScript
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *resourceCustomAccessor) setReplicaRevision(replicaRevision *configv1alpha1.ReplicaRevision) {
|
||||||
|
if a.replicaRevision == nil {
|
||||||
|
a.replicaRevision = replicaRevision
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if replicaRevision.LuaScript != "" && a.replicaRevision.LuaScript == "" {
|
||||||
|
a.replicaRevision.LuaScript = replicaRevision.LuaScript
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *resourceCustomAccessor) setStatusReflection(statusReflection *configv1alpha1.StatusReflection) {
|
||||||
|
if a.statusReflection == nil {
|
||||||
|
a.statusReflection = statusReflection
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if statusReflection.LuaScript != "" && a.statusReflection.LuaScript == "" {
|
||||||
|
a.statusReflection.LuaScript = statusReflection.LuaScript
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *resourceCustomAccessor) setStatusAggregation(statusAggregation *configv1alpha1.StatusAggregation) {
|
||||||
|
if a.statusAggregation == nil {
|
||||||
|
a.statusAggregation = statusAggregation
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if statusAggregation.LuaScript != "" && a.statusAggregation.LuaScript == "" {
|
||||||
|
a.statusAggregation.LuaScript = statusAggregation.LuaScript
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *resourceCustomAccessor) setHealthInterpretation(healthInterpretation *configv1alpha1.HealthInterpretation) {
|
||||||
|
if a.healthInterpretation == nil {
|
||||||
|
a.healthInterpretation = healthInterpretation
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if healthInterpretation.LuaScript != "" && a.healthInterpretation.LuaScript == "" {
|
||||||
|
a.healthInterpretation.LuaScript = healthInterpretation.LuaScript
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *resourceCustomAccessor) setDependencyInterpretation(dependencyInterpretation *configv1alpha1.DependencyInterpretation) {
|
||||||
|
if a.dependencyInterpretation == nil {
|
||||||
|
a.dependencyInterpretation = dependencyInterpretation
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if dependencyInterpretation.LuaScript != "" && a.dependencyInterpretation.LuaScript == "" {
|
||||||
|
a.dependencyInterpretation.LuaScript = dependencyInterpretation.LuaScript
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package configmanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
|
@ -82,17 +83,34 @@ func (configManager *interpreterConfigManager) updateConfiguration() {
|
||||||
utilruntime.HandleError(fmt.Errorf("error updating configuration: %v", err))
|
utilruntime.HandleError(fmt.Errorf("error updating configuration: %v", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
configs := make(map[schema.GroupVersionKind]CustomAccessor, len(configurations))
|
|
||||||
|
|
||||||
for _, c := range configurations {
|
configs := make([]*configv1alpha1.ResourceInterpreterCustomization, len(configurations))
|
||||||
|
for index, c := range configurations {
|
||||||
config := &configv1alpha1.ResourceInterpreterCustomization{}
|
config := &configv1alpha1.ResourceInterpreterCustomization{}
|
||||||
if err = helper.ConvertToTypedObject(c, config); err != nil {
|
if err = helper.ConvertToTypedObject(c, config); err != nil {
|
||||||
klog.Errorf("Failed to transform ResourceInterpreterCustomization: %w", err)
|
klog.Errorf("Failed to transform ResourceInterpreterCustomization: %w", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
key := schema.FromAPIVersionAndKind(config.Spec.Target.APIVersion, config.Spec.Target.Kind)
|
configs[index] = config
|
||||||
configs[key] = NewResourceCustomAccessorAccessor(config)
|
|
||||||
}
|
}
|
||||||
configManager.configuration.Store(configs)
|
|
||||||
|
sort.Slice(configs, func(i, j int) bool {
|
||||||
|
return configs[i].Name < configs[j].Name
|
||||||
|
})
|
||||||
|
|
||||||
|
accessors := make(map[schema.GroupVersionKind]CustomAccessor)
|
||||||
|
for _, config := range configs {
|
||||||
|
key := schema.FromAPIVersionAndKind(config.Spec.Target.APIVersion, config.Spec.Target.Kind)
|
||||||
|
|
||||||
|
var accessor CustomAccessor
|
||||||
|
var ok bool
|
||||||
|
if accessor, ok = accessors[key]; !ok {
|
||||||
|
accessor = NewResourceCustomAccessor()
|
||||||
|
}
|
||||||
|
accessor.Merge(config.Spec.Customizations)
|
||||||
|
accessors[key] = accessor
|
||||||
|
}
|
||||||
|
|
||||||
|
configManager.configuration.Store(accessors)
|
||||||
configManager.initialSynced.Store(true)
|
configManager.initialSynced.Store(true)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,132 @@
|
||||||
|
package configmanager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
appsv1 "k8s.io/api/apps/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/client-go/dynamic/fake"
|
||||||
|
|
||||||
|
configv1alpha1 "github.com/karmada-io/karmada/pkg/apis/config/v1alpha1"
|
||||||
|
"github.com/karmada-io/karmada/pkg/util/fedinformer/genericmanager"
|
||||||
|
"github.com/karmada-io/karmada/pkg/util/gclient"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_interpreterConfigManager_LuaScriptAccessors(t *testing.T) {
|
||||||
|
customization01 := &configv1alpha1.ResourceInterpreterCustomization{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: "customization01"},
|
||||||
|
Spec: configv1alpha1.ResourceInterpreterCustomizationSpec{
|
||||||
|
Target: configv1alpha1.CustomizationTarget{
|
||||||
|
APIVersion: appsv1.SchemeGroupVersion.String(),
|
||||||
|
Kind: "Deployment",
|
||||||
|
},
|
||||||
|
Customizations: configv1alpha1.CustomizationRules{
|
||||||
|
Retention: &configv1alpha1.LocalValueRetention{LuaScript: "a=0"},
|
||||||
|
ReplicaResource: &configv1alpha1.ReplicaResourceRequirement{LuaScript: "b=0"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
customization02 := &configv1alpha1.ResourceInterpreterCustomization{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: "customization02"},
|
||||||
|
Spec: configv1alpha1.ResourceInterpreterCustomizationSpec{
|
||||||
|
Target: configv1alpha1.CustomizationTarget{
|
||||||
|
APIVersion: appsv1.SchemeGroupVersion.String(),
|
||||||
|
Kind: "Deployment",
|
||||||
|
},
|
||||||
|
Customizations: configv1alpha1.CustomizationRules{
|
||||||
|
ReplicaRevision: &configv1alpha1.ReplicaRevision{LuaScript: "c=0"},
|
||||||
|
StatusReflection: &configv1alpha1.StatusReflection{LuaScript: "d=0"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
customization03 := &configv1alpha1.ResourceInterpreterCustomization{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: "customization03"},
|
||||||
|
Spec: configv1alpha1.ResourceInterpreterCustomizationSpec{
|
||||||
|
Target: configv1alpha1.CustomizationTarget{
|
||||||
|
APIVersion: appsv1.SchemeGroupVersion.String(),
|
||||||
|
Kind: "Deployment",
|
||||||
|
},
|
||||||
|
Customizations: configv1alpha1.CustomizationRules{
|
||||||
|
ReplicaResource: &configv1alpha1.ReplicaResourceRequirement{LuaScript: "b=1"},
|
||||||
|
ReplicaRevision: &configv1alpha1.ReplicaRevision{LuaScript: "c=1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
deploymentGVK := schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}
|
||||||
|
|
||||||
|
type args struct {
|
||||||
|
customizations []runtime.Object
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want map[schema.GroupVersionKind]CustomAccessor
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "single ResourceInterpreterCustomization",
|
||||||
|
args: args{[]runtime.Object{customization01}},
|
||||||
|
want: map[schema.GroupVersionKind]CustomAccessor{
|
||||||
|
deploymentGVK: &resourceCustomAccessor{
|
||||||
|
retention: &configv1alpha1.LocalValueRetention{LuaScript: "a=0"},
|
||||||
|
replicaResource: &configv1alpha1.ReplicaResourceRequirement{LuaScript: "b=0"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multi ResourceInterpreterCustomization with no redundant operation",
|
||||||
|
args: args{[]runtime.Object{customization01, customization02}},
|
||||||
|
want: map[schema.GroupVersionKind]CustomAccessor{
|
||||||
|
deploymentGVK: &resourceCustomAccessor{
|
||||||
|
retention: &configv1alpha1.LocalValueRetention{LuaScript: "a=0"},
|
||||||
|
replicaResource: &configv1alpha1.ReplicaResourceRequirement{LuaScript: "b=0"},
|
||||||
|
replicaRevision: &configv1alpha1.ReplicaRevision{LuaScript: "c=0"},
|
||||||
|
statusReflection: &configv1alpha1.StatusReflection{LuaScript: "d=0"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multi ResourceInterpreterCustomization with redundant operation ",
|
||||||
|
args: args{[]runtime.Object{customization03, customization02, customization01}},
|
||||||
|
want: map[schema.GroupVersionKind]CustomAccessor{
|
||||||
|
deploymentGVK: &resourceCustomAccessor{
|
||||||
|
retention: &configv1alpha1.LocalValueRetention{LuaScript: "a=0"},
|
||||||
|
replicaResource: &configv1alpha1.ReplicaResourceRequirement{LuaScript: "b=0"},
|
||||||
|
replicaRevision: &configv1alpha1.ReplicaRevision{LuaScript: "c=0"},
|
||||||
|
statusReflection: &configv1alpha1.StatusReflection{LuaScript: "d=0"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
stopCh := make(chan struct{})
|
||||||
|
defer close(stopCh)
|
||||||
|
|
||||||
|
client := fake.NewSimpleDynamicClient(gclient.NewSchema(), tt.args.customizations...)
|
||||||
|
informer := genericmanager.NewSingleClusterInformerManager(client, 0, stopCh)
|
||||||
|
configManager := NewInterpreterConfigManager(informer)
|
||||||
|
|
||||||
|
informer.Start()
|
||||||
|
defer informer.Stop()
|
||||||
|
|
||||||
|
informer.WaitForCacheSync()
|
||||||
|
|
||||||
|
if !configManager.HasSynced() {
|
||||||
|
t.Errorf("informer has not been synced")
|
||||||
|
}
|
||||||
|
gotAccessors := configManager.LuaScriptAccessors()
|
||||||
|
for gvk, gotAccessor := range gotAccessors {
|
||||||
|
wantAccessor, ok := tt.want[gvk]
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("Can not find the target gvk %v", gvk)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(gotAccessor, wantAccessor) {
|
||||||
|
t.Errorf("LuaScriptAccessors() = %v, want %v", gotAccessor, wantAccessor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue