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
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
configv1alpha1 "github.com/karmada-io/karmada/pkg/apis/config/v1alpha1"
|
||||
)
|
||||
|
||||
// CustomConfiguration provides base information about custom interpreter configuration
|
||||
type CustomConfiguration interface {
|
||||
Name() string
|
||||
TargetResource() schema.GroupVersionKind
|
||||
Merge(rules configv1alpha1.CustomizationRules)
|
||||
}
|
||||
|
||||
// LuaScriptAccessor provides a common interface to get custom interpreter lua script
|
||||
|
@ -38,22 +35,35 @@ type resourceCustomAccessor struct {
|
|||
statusAggregation *configv1alpha1.StatusAggregation
|
||||
healthInterpretation *configv1alpha1.HealthInterpretation
|
||||
dependencyInterpretation *configv1alpha1.DependencyInterpretation
|
||||
configurationName string
|
||||
configurationTargetGVK schema.GroupVersionKind
|
||||
}
|
||||
|
||||
// NewResourceCustomAccessorAccessor creates an accessor for resource interpreter customization
|
||||
func NewResourceCustomAccessorAccessor(customization *configv1alpha1.ResourceInterpreterCustomization) CustomAccessor {
|
||||
return &resourceCustomAccessor{
|
||||
retention: customization.Spec.Customizations.Retention,
|
||||
replicaResource: customization.Spec.Customizations.ReplicaResource,
|
||||
replicaRevision: customization.Spec.Customizations.ReplicaRevision,
|
||||
statusReflection: customization.Spec.Customizations.StatusReflection,
|
||||
statusAggregation: customization.Spec.Customizations.StatusAggregation,
|
||||
healthInterpretation: customization.Spec.Customizations.HealthInterpretation,
|
||||
dependencyInterpretation: customization.Spec.Customizations.DependencyInterpretation,
|
||||
configurationName: customization.Name,
|
||||
configurationTargetGVK: schema.FromAPIVersionAndKind(customization.Spec.Target.APIVersion, customization.Spec.Target.Kind),
|
||||
// NewResourceCustomAccessor creates an accessor for resource interpreter customization.
|
||||
func NewResourceCustomAccessor() CustomAccessor {
|
||||
return &resourceCustomAccessor{}
|
||||
}
|
||||
|
||||
// Merge merges the given CustomizationRules with the current rules, ignore if duplicates occur.
|
||||
func (a *resourceCustomAccessor) Merge(rules configv1alpha1.CustomizationRules) {
|
||||
if rules.Retention != nil {
|
||||
a.setRetain(rules.Retention)
|
||||
}
|
||||
if rules.ReplicaResource != nil {
|
||||
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
|
||||
}
|
||||
|
||||
func (a *resourceCustomAccessor) Name() string {
|
||||
return a.configurationName
|
||||
func (a *resourceCustomAccessor) setRetain(retention *configv1alpha1.LocalValueRetention) {
|
||||
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 {
|
||||
return a.configurationTargetGVK
|
||||
func (a *resourceCustomAccessor) setReplicaResource(replicaResource *configv1alpha1.ReplicaResourceRequirement) {
|
||||
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 (
|
||||
"fmt"
|
||||
"sort"
|
||||
"sync/atomic"
|
||||
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
|
@ -82,17 +83,34 @@ func (configManager *interpreterConfigManager) updateConfiguration() {
|
|||
utilruntime.HandleError(fmt.Errorf("error updating configuration: %v", err))
|
||||
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{}
|
||||
if err = helper.ConvertToTypedObject(c, config); err != nil {
|
||||
klog.Errorf("Failed to transform ResourceInterpreterCustomization: %w", err)
|
||||
return
|
||||
}
|
||||
key := schema.FromAPIVersionAndKind(config.Spec.Target.APIVersion, config.Spec.Target.Kind)
|
||||
configs[key] = NewResourceCustomAccessorAccessor(config)
|
||||
configs[index] = 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)
|
||||
}
|
||||
|
|
|
@ -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