support multiple dependencyInterpreter lua script for one gvk
Signed-off-by: changzhen <changzhen5@huawei.com>
This commit is contained in:
parent
37cca1cd8d
commit
5ed2100ee1
|
@ -19,7 +19,7 @@ type LuaScriptAccessor interface {
|
||||||
GetStatusReflectionLuaScript() string
|
GetStatusReflectionLuaScript() string
|
||||||
GetStatusAggregationLuaScript() string
|
GetStatusAggregationLuaScript() string
|
||||||
GetHealthInterpretationLuaScript() string
|
GetHealthInterpretationLuaScript() string
|
||||||
GetDependencyInterpretationLuaScript() string
|
GetDependencyInterpretationLuaScripts() []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// CustomAccessor provides a common interface to get custom interpreter configuration.
|
// CustomAccessor provides a common interface to get custom interpreter configuration.
|
||||||
|
@ -34,7 +34,7 @@ type resourceCustomAccessor struct {
|
||||||
statusReflection *configv1alpha1.StatusReflection
|
statusReflection *configv1alpha1.StatusReflection
|
||||||
statusAggregation *configv1alpha1.StatusAggregation
|
statusAggregation *configv1alpha1.StatusAggregation
|
||||||
healthInterpretation *configv1alpha1.HealthInterpretation
|
healthInterpretation *configv1alpha1.HealthInterpretation
|
||||||
dependencyInterpretation *configv1alpha1.DependencyInterpretation
|
dependencyInterpretations []*configv1alpha1.DependencyInterpretation
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewResourceCustomAccessor creates an accessor for resource interpreter customization.
|
// NewResourceCustomAccessor creates an accessor for resource interpreter customization.
|
||||||
|
@ -63,7 +63,7 @@ func (a *resourceCustomAccessor) Merge(rules configv1alpha1.CustomizationRules)
|
||||||
a.setHealthInterpretation(rules.HealthInterpretation)
|
a.setHealthInterpretation(rules.HealthInterpretation)
|
||||||
}
|
}
|
||||||
if rules.DependencyInterpretation != nil {
|
if rules.DependencyInterpretation != nil {
|
||||||
a.setDependencyInterpretation(rules.DependencyInterpretation)
|
a.appendDependencyInterpretation(rules.DependencyInterpretation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,11 +109,18 @@ func (a *resourceCustomAccessor) GetHealthInterpretationLuaScript() string {
|
||||||
return a.healthInterpretation.LuaScript
|
return a.healthInterpretation.LuaScript
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *resourceCustomAccessor) GetDependencyInterpretationLuaScript() string {
|
func (a *resourceCustomAccessor) GetDependencyInterpretationLuaScripts() []string {
|
||||||
if a.dependencyInterpretation == nil {
|
if a.dependencyInterpretations == nil {
|
||||||
return ""
|
return nil
|
||||||
}
|
}
|
||||||
return a.dependencyInterpretation.LuaScript
|
|
||||||
|
var scripts []string
|
||||||
|
for _, interpretation := range a.dependencyInterpretations {
|
||||||
|
if interpretation.LuaScript != "" {
|
||||||
|
scripts = append(scripts, interpretation.LuaScript)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return scripts
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *resourceCustomAccessor) setRetain(retention *configv1alpha1.LocalValueRetention) {
|
func (a *resourceCustomAccessor) setRetain(retention *configv1alpha1.LocalValueRetention) {
|
||||||
|
@ -182,13 +189,6 @@ func (a *resourceCustomAccessor) setHealthInterpretation(healthInterpretation *c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *resourceCustomAccessor) setDependencyInterpretation(dependencyInterpretation *configv1alpha1.DependencyInterpretation) {
|
func (a *resourceCustomAccessor) appendDependencyInterpretation(dependencyInterpretation *configv1alpha1.DependencyInterpretation) {
|
||||||
if a.dependencyInterpretation == nil {
|
a.dependencyInterpretations = append(a.dependencyInterpretations, dependencyInterpretation)
|
||||||
a.dependencyInterpretation = dependencyInterpretation
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if dependencyInterpretation.LuaScript != "" && a.dependencyInterpretation.LuaScript == "" {
|
|
||||||
a.dependencyInterpretation.LuaScript = dependencyInterpretation.LuaScript
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ var resourceInterpreterCustomizationsGVR = schema.GroupVersionResource{
|
||||||
|
|
||||||
// ConfigManager can list custom resource interpreter.
|
// ConfigManager can list custom resource interpreter.
|
||||||
type ConfigManager interface {
|
type ConfigManager interface {
|
||||||
LuaScriptAccessors() map[schema.GroupVersionKind]CustomAccessor
|
CustomAccessors() map[schema.GroupVersionKind]CustomAccessor
|
||||||
HasSynced() bool
|
HasSynced() bool
|
||||||
LoadConfig(customizations []*configv1alpha1.ResourceInterpreterCustomization)
|
LoadConfig(customizations []*configv1alpha1.ResourceInterpreterCustomization)
|
||||||
}
|
}
|
||||||
|
@ -37,8 +37,8 @@ type interpreterConfigManager struct {
|
||||||
configuration atomic.Value
|
configuration atomic.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
// LuaScriptAccessors returns all cached configurations.
|
// CustomAccessors returns all cached configurations.
|
||||||
func (configManager *interpreterConfigManager) LuaScriptAccessors() map[schema.GroupVersionKind]CustomAccessor {
|
func (configManager *interpreterConfigManager) CustomAccessors() map[schema.GroupVersionKind]CustomAccessor {
|
||||||
return configManager.configuration.Load().(map[schema.GroupVersionKind]CustomAccessor)
|
return configManager.configuration.Load().(map[schema.GroupVersionKind]CustomAccessor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -122,7 +122,7 @@ func Test_interpreterConfigManager_LuaScriptAccessors(t *testing.T) {
|
||||||
t.Errorf("informer has not been synced")
|
t.Errorf("informer has not been synced")
|
||||||
}
|
}
|
||||||
|
|
||||||
gotAccessors := configManager.LuaScriptAccessors()
|
gotAccessors := configManager.CustomAccessors()
|
||||||
for gvk, gotAccessor := range gotAccessors {
|
for gvk, gotAccessor := range gotAccessors {
|
||||||
wantAccessor, ok := tt.want[gvk]
|
wantAccessor, ok := tt.want[gvk]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
|
@ -32,114 +32,185 @@ func NewConfigurableInterpreter(informer genericmanager.SingleClusterInformerMan
|
||||||
|
|
||||||
// HookEnabled tells if any hook exist for specific resource gvk and operation type.
|
// HookEnabled tells if any hook exist for specific resource gvk and operation type.
|
||||||
func (c *ConfigurableInterpreter) HookEnabled(kind schema.GroupVersionKind, operationType configv1alpha1.InterpreterOperation) bool {
|
func (c *ConfigurableInterpreter) HookEnabled(kind schema.GroupVersionKind, operationType configv1alpha1.InterpreterOperation) bool {
|
||||||
_, exist := c.getInterpreter(kind, operationType)
|
accessor, exist := c.getCustomAccessor(kind)
|
||||||
|
if !exist {
|
||||||
return exist
|
return exist
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if operationType == configv1alpha1.InterpreterOperationInterpretDependency {
|
||||||
|
scripts := accessor.GetDependencyInterpretationLuaScripts()
|
||||||
|
return scripts != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var script string
|
||||||
|
switch operationType {
|
||||||
|
case configv1alpha1.InterpreterOperationAggregateStatus:
|
||||||
|
script = accessor.GetStatusAggregationLuaScript()
|
||||||
|
case configv1alpha1.InterpreterOperationInterpretHealth:
|
||||||
|
script = accessor.GetHealthInterpretationLuaScript()
|
||||||
|
case configv1alpha1.InterpreterOperationInterpretReplica:
|
||||||
|
script = accessor.GetReplicaResourceLuaScript()
|
||||||
|
case configv1alpha1.InterpreterOperationInterpretStatus:
|
||||||
|
script = accessor.GetStatusReflectionLuaScript()
|
||||||
|
case configv1alpha1.InterpreterOperationRetain:
|
||||||
|
script = accessor.GetRetentionLuaScript()
|
||||||
|
case configv1alpha1.InterpreterOperationReviseReplica:
|
||||||
|
script = accessor.GetReplicaRevisionLuaScript()
|
||||||
|
}
|
||||||
|
return len(script) > 0
|
||||||
|
}
|
||||||
|
|
||||||
// GetReplicas returns the desired replicas of the object as well as the requirements of each replica.
|
// GetReplicas returns the desired replicas of the object as well as the requirements of each replica.
|
||||||
func (c *ConfigurableInterpreter) GetReplicas(object *unstructured.Unstructured) (replicas int32, requires *workv1alpha2.ReplicaRequirements, enabled bool, err error) {
|
func (c *ConfigurableInterpreter) GetReplicas(object *unstructured.Unstructured) (replicas int32, requires *workv1alpha2.ReplicaRequirements, enabled bool, err error) {
|
||||||
klog.V(4).Infof("Get replicas for object: %v %s/%s with configurable interpreter.", object.GroupVersionKind(), object.GetNamespace(), object.GetName())
|
klog.V(4).Infof("Get replicas for object: %v %s/%s with configurable interpreter.", object.GroupVersionKind(), object.GetNamespace(), object.GetName())
|
||||||
luaScript, enabled := c.getInterpreter(object.GroupVersionKind(), configv1alpha1.InterpreterOperationInterpretReplica)
|
|
||||||
|
accessor, enabled := c.getCustomAccessor(object.GroupVersionKind())
|
||||||
if !enabled {
|
if !enabled {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
replicas, requires, err = c.luaVM.GetReplicas(object, luaScript)
|
|
||||||
|
script := accessor.GetReplicaResourceLuaScript()
|
||||||
|
if len(script) == 0 {
|
||||||
|
enabled = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
replicas, requires, err = c.luaVM.GetReplicas(object, script)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReviseReplica revises the replica of the given object.
|
// ReviseReplica revises the replica of the given object.
|
||||||
func (c *ConfigurableInterpreter) ReviseReplica(object *unstructured.Unstructured, replica int64) (revised *unstructured.Unstructured, enabled bool, err error) {
|
func (c *ConfigurableInterpreter) ReviseReplica(object *unstructured.Unstructured, replica int64) (revised *unstructured.Unstructured, enabled bool, err error) {
|
||||||
klog.V(4).Infof("Revise replicas for object: %v %s/%s with configurable interpreter.", object.GroupVersionKind(), object.GetNamespace(), object.GetName())
|
klog.V(4).Infof("Revise replicas for object: %v %s/%s with configurable interpreter.", object.GroupVersionKind(), object.GetNamespace(), object.GetName())
|
||||||
luaScript, enabled := c.getInterpreter(object.GroupVersionKind(), configv1alpha1.InterpreterOperationReviseReplica)
|
|
||||||
|
accessor, enabled := c.getCustomAccessor(object.GroupVersionKind())
|
||||||
if !enabled {
|
if !enabled {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
revised, err = c.luaVM.ReviseReplica(object, replica, luaScript)
|
|
||||||
|
script := accessor.GetReplicaRevisionLuaScript()
|
||||||
|
if len(script) == 0 {
|
||||||
|
enabled = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
revised, err = c.luaVM.ReviseReplica(object, replica, script)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retain returns the objects that based on the "desired" object but with values retained from the "observed" object.
|
// Retain returns the objects that based on the "desired" object but with values retained from the "observed" object.
|
||||||
func (c *ConfigurableInterpreter) Retain(desired *unstructured.Unstructured, observed *unstructured.Unstructured) (retained *unstructured.Unstructured, enabled bool, err error) {
|
func (c *ConfigurableInterpreter) Retain(desired *unstructured.Unstructured, observed *unstructured.Unstructured) (retained *unstructured.Unstructured, enabled bool, err error) {
|
||||||
klog.V(4).Infof("Retain object: %v %s/%s with configurable interpreter.", desired.GroupVersionKind(), desired.GetNamespace(), desired.GetName())
|
klog.V(4).Infof("Retain object: %v %s/%s with configurable interpreter.", desired.GroupVersionKind(), desired.GetNamespace(), desired.GetName())
|
||||||
luaScript, enabled := c.getInterpreter(desired.GroupVersionKind(), configv1alpha1.InterpreterOperationRetain)
|
|
||||||
|
accessor, enabled := c.getCustomAccessor(desired.GroupVersionKind())
|
||||||
if !enabled {
|
if !enabled {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
retained, err = c.luaVM.Retain(desired, observed, luaScript)
|
|
||||||
|
script := accessor.GetRetentionLuaScript()
|
||||||
|
if len(script) == 0 {
|
||||||
|
enabled = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
retained, err = c.luaVM.Retain(desired, observed, script)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// AggregateStatus returns the objects that based on the 'object' but with status aggregated.
|
// AggregateStatus returns the objects that based on the 'object' but with status aggregated.
|
||||||
func (c *ConfigurableInterpreter) AggregateStatus(object *unstructured.Unstructured, aggregatedStatusItems []workv1alpha2.AggregatedStatusItem) (status *unstructured.Unstructured, enabled bool, err error) {
|
func (c *ConfigurableInterpreter) AggregateStatus(object *unstructured.Unstructured, aggregatedStatusItems []workv1alpha2.AggregatedStatusItem) (status *unstructured.Unstructured, enabled bool, err error) {
|
||||||
klog.V(4).Infof("Aggregate status of object: %v %s/%s with configurable interpreter.", object.GroupVersionKind(), object.GetNamespace(), object.GetName())
|
klog.V(4).Infof("Aggregate status of object: %v %s/%s with configurable interpreter.", object.GroupVersionKind(), object.GetNamespace(), object.GetName())
|
||||||
luaScript, enabled := c.getInterpreter(object.GroupVersionKind(), configv1alpha1.InterpreterOperationAggregateStatus)
|
accessor, enabled := c.getCustomAccessor(object.GroupVersionKind())
|
||||||
if !enabled {
|
if !enabled {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
status, err = c.luaVM.AggregateStatus(object, aggregatedStatusItems, luaScript)
|
|
||||||
|
script := accessor.GetStatusAggregationLuaScript()
|
||||||
|
if len(script) == 0 {
|
||||||
|
enabled = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
status, err = c.luaVM.AggregateStatus(object, aggregatedStatusItems, script)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDependencies returns the dependent resources of the given object.
|
// GetDependencies returns the dependent resources of the given object.
|
||||||
func (c *ConfigurableInterpreter) GetDependencies(object *unstructured.Unstructured) (dependencies []configv1alpha1.DependentObjectReference, enabled bool, err error) {
|
func (c *ConfigurableInterpreter) GetDependencies(object *unstructured.Unstructured) (dependencies []configv1alpha1.DependentObjectReference, enabled bool, err error) {
|
||||||
klog.V(4).Infof("Get dependencies of object: %v %s/%s with configurable interpreter.", object.GroupVersionKind(), object.GetNamespace(), object.GetName())
|
klog.V(4).Infof("Get dependencies of object: %v %s/%s with configurable interpreter.", object.GroupVersionKind(), object.GetNamespace(), object.GetName())
|
||||||
luaScript, enabled := c.getInterpreter(object.GroupVersionKind(), configv1alpha1.InterpreterOperationInterpretDependency)
|
|
||||||
|
accessor, enabled := c.getCustomAccessor(object.GroupVersionKind())
|
||||||
if !enabled {
|
if !enabled {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
dependencies, err = c.luaVM.GetDependencies(object, luaScript)
|
|
||||||
|
scripts := accessor.GetDependencyInterpretationLuaScripts()
|
||||||
|
if scripts == nil {
|
||||||
|
enabled = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
referenceSet := newDependencySet()
|
||||||
|
for _, luaScript := range scripts {
|
||||||
|
var references []configv1alpha1.DependentObjectReference
|
||||||
|
references, err = c.luaVM.GetDependencies(object, luaScript)
|
||||||
|
if err != nil {
|
||||||
|
klog.Errorf("Failed to get DependentObjectReferences from object: %v %s/%s, error: %v",
|
||||||
|
object.GroupVersionKind(), object.GetNamespace(), object.GetName(), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
referenceSet.insert(references...)
|
||||||
|
}
|
||||||
|
dependencies = referenceSet.list()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReflectStatus returns the status of the object.
|
// ReflectStatus returns the status of the object.
|
||||||
func (c *ConfigurableInterpreter) ReflectStatus(object *unstructured.Unstructured) (status *runtime.RawExtension, enabled bool, err error) {
|
func (c *ConfigurableInterpreter) ReflectStatus(object *unstructured.Unstructured) (status *runtime.RawExtension, enabled bool, err error) {
|
||||||
klog.V(4).Infof("Reflect status of object: %v %s/%s with configurable interpreter.", object.GroupVersionKind(), object.GetNamespace(), object.GetName())
|
klog.V(4).Infof("Reflect status of object: %v %s/%s with configurable interpreter.", object.GroupVersionKind(), object.GetNamespace(), object.GetName())
|
||||||
luaScript, enabled := c.getInterpreter(object.GroupVersionKind(), configv1alpha1.InterpreterOperationInterpretStatus)
|
|
||||||
|
accessor, enabled := c.getCustomAccessor(object.GroupVersionKind())
|
||||||
if !enabled {
|
if !enabled {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
status, err = c.luaVM.ReflectStatus(object, luaScript)
|
|
||||||
|
script := accessor.GetStatusReflectionLuaScript()
|
||||||
|
if len(script) == 0 {
|
||||||
|
enabled = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
status, err = c.luaVM.ReflectStatus(object, script)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// InterpretHealth returns the health state of the object.
|
// InterpretHealth returns the health state of the object.
|
||||||
func (c *ConfigurableInterpreter) InterpretHealth(object *unstructured.Unstructured) (health bool, enabled bool, err error) {
|
func (c *ConfigurableInterpreter) InterpretHealth(object *unstructured.Unstructured) (health bool, enabled bool, err error) {
|
||||||
klog.V(4).Infof("Get health status of object: %v %s/%s with configurable interpreter.", object.GroupVersionKind(), object.GetNamespace(), object.GetName())
|
klog.V(4).Infof("Get health status of object: %v %s/%s with configurable interpreter.", object.GroupVersionKind(), object.GetNamespace(), object.GetName())
|
||||||
luaScript, enabled := c.getInterpreter(object.GroupVersionKind(), configv1alpha1.InterpreterOperationInterpretHealth)
|
|
||||||
|
accessor, enabled := c.getCustomAccessor(object.GroupVersionKind())
|
||||||
if !enabled {
|
if !enabled {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
health, err = c.luaVM.InterpretHealth(object, luaScript)
|
|
||||||
|
script := accessor.GetHealthInterpretationLuaScript()
|
||||||
|
if len(script) == 0 {
|
||||||
|
enabled = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConfigurableInterpreter) getInterpreter(kind schema.GroupVersionKind, operationType configv1alpha1.InterpreterOperation) (string, bool) {
|
health, err = c.luaVM.InterpretHealth(object, script)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConfigurableInterpreter) getCustomAccessor(kind schema.GroupVersionKind) (configmanager.CustomAccessor, bool) {
|
||||||
if !c.configManager.HasSynced() {
|
if !c.configManager.HasSynced() {
|
||||||
klog.Errorf("not yet ready to handle request")
|
klog.Errorf("not yet ready to handle request")
|
||||||
return "", false
|
return nil, false
|
||||||
}
|
}
|
||||||
accessors, exist := c.configManager.LuaScriptAccessors()[kind]
|
|
||||||
if !exist {
|
accessor, exist := c.configManager.CustomAccessors()[kind]
|
||||||
return "", false
|
return accessor, exist
|
||||||
}
|
|
||||||
var script string
|
|
||||||
switch operationType {
|
|
||||||
case configv1alpha1.InterpreterOperationAggregateStatus:
|
|
||||||
script = accessors.GetStatusAggregationLuaScript()
|
|
||||||
case configv1alpha1.InterpreterOperationInterpretHealth:
|
|
||||||
script = accessors.GetHealthInterpretationLuaScript()
|
|
||||||
case configv1alpha1.InterpreterOperationInterpretDependency:
|
|
||||||
script = accessors.GetDependencyInterpretationLuaScript()
|
|
||||||
case configv1alpha1.InterpreterOperationInterpretReplica:
|
|
||||||
script = accessors.GetReplicaResourceLuaScript()
|
|
||||||
case configv1alpha1.InterpreterOperationInterpretStatus:
|
|
||||||
script = accessors.GetStatusReflectionLuaScript()
|
|
||||||
case configv1alpha1.InterpreterOperationRetain:
|
|
||||||
script = accessors.GetRetentionLuaScript()
|
|
||||||
case configv1alpha1.InterpreterOperationReviseReplica:
|
|
||||||
script = accessors.GetReplicaRevisionLuaScript()
|
|
||||||
}
|
|
||||||
return script, len(script) > 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadConfig loads and stores rules from customizations
|
// LoadConfig loads and stores rules from customizations
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
package configurableinterpreter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
configv1alpha1 "github.com/karmada-io/karmada/pkg/apis/config/v1alpha1"
|
||||||
|
)
|
||||||
|
|
||||||
|
type dependencySet map[configv1alpha1.DependentObjectReference]struct{}
|
||||||
|
|
||||||
|
func newDependencySet(items ...configv1alpha1.DependentObjectReference) dependencySet {
|
||||||
|
s := make(dependencySet, len(items))
|
||||||
|
s.insert(items...)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s dependencySet) insert(items ...configv1alpha1.DependentObjectReference) dependencySet {
|
||||||
|
for _, item := range items {
|
||||||
|
s[item] = struct{}{}
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s dependencySet) list() []configv1alpha1.DependentObjectReference {
|
||||||
|
keys := make([]configv1alpha1.DependentObjectReference, len(s))
|
||||||
|
index := 0
|
||||||
|
for key := range s {
|
||||||
|
keys[index] = key
|
||||||
|
index++
|
||||||
|
}
|
||||||
|
sort.Slice(keys, func(i, j int) bool {
|
||||||
|
return fmt.Sprintf("%s", keys[i]) < fmt.Sprintf("%s", keys[j])
|
||||||
|
})
|
||||||
|
return keys
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
package configurableinterpreter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
configv1alpha1 "github.com/karmada-io/karmada/pkg/apis/config/v1alpha1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_dependencySet_list(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
s dependencySet
|
||||||
|
want []configv1alpha1.DependentObjectReference
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty set",
|
||||||
|
s: newDependencySet(),
|
||||||
|
want: []configv1alpha1.DependentObjectReference{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "new with items",
|
||||||
|
s: newDependencySet([]configv1alpha1.DependentObjectReference{
|
||||||
|
{APIVersion: "v1", Kind: "Secret", Namespace: "foo", Name: "foo"},
|
||||||
|
}...),
|
||||||
|
want: []configv1alpha1.DependentObjectReference{
|
||||||
|
{APIVersion: "v1", Kind: "Secret", Namespace: "foo", Name: "foo"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "insert with different items",
|
||||||
|
s: newDependencySet([]configv1alpha1.DependentObjectReference{
|
||||||
|
{APIVersion: "v1", Kind: "Secret", Namespace: "foo", Name: "foo"},
|
||||||
|
}...).insert(
|
||||||
|
[]configv1alpha1.DependentObjectReference{
|
||||||
|
{APIVersion: "v1", Kind: "Configmap", Namespace: "foo", Name: "foo"},
|
||||||
|
}...),
|
||||||
|
want: []configv1alpha1.DependentObjectReference{
|
||||||
|
{APIVersion: "v1", Kind: "Configmap", Namespace: "foo", Name: "foo"},
|
||||||
|
{APIVersion: "v1", Kind: "Secret", Namespace: "foo", Name: "foo"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "insert with same items",
|
||||||
|
s: newDependencySet([]configv1alpha1.DependentObjectReference{
|
||||||
|
{APIVersion: "v1", Kind: "Secret", Namespace: "foo", Name: "foo"},
|
||||||
|
}...).insert(
|
||||||
|
[]configv1alpha1.DependentObjectReference{
|
||||||
|
{APIVersion: "v1", Kind: "Configmap", Namespace: "foo", Name: "foo"},
|
||||||
|
}...).insert(
|
||||||
|
[]configv1alpha1.DependentObjectReference{
|
||||||
|
{APIVersion: "v1", Kind: "Secret", Namespace: "foo", Name: "foo"},
|
||||||
|
{APIVersion: "apps/v1", Kind: "Deployment", Namespace: "foo", Name: "foo"},
|
||||||
|
}...),
|
||||||
|
want: []configv1alpha1.DependentObjectReference{
|
||||||
|
{APIVersion: "apps/v1", Kind: "Deployment", Namespace: "foo", Name: "foo"},
|
||||||
|
{APIVersion: "v1", Kind: "Configmap", Namespace: "foo", Name: "foo"},
|
||||||
|
{APIVersion: "v1", Kind: "Secret", Namespace: "foo", Name: "foo"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := tt.s.list(); !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("dependencySet.list() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,10 @@ func validateCustomizationRule(oldRules, newRules *configv1alpha1.ResourceInterp
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
for _, rule := range interpreter.AllResourceInterpreterCustomizationRules {
|
for _, rule := range interpreter.AllResourceInterpreterCustomizationRules {
|
||||||
|
// skip InterpretDependency operation because it supports multiple rules.
|
||||||
|
if rule.Name() == string(configv1alpha1.InterpreterOperationInterpretDependency) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
oldScript := rule.GetScript(oldRules)
|
oldScript := rule.GetScript(oldRules)
|
||||||
newScript := rule.GetScript(newRules)
|
newScript := rule.GetScript(newRules)
|
||||||
if oldScript != "" && newScript != "" {
|
if oldScript != "" && newScript != "" {
|
||||||
|
|
|
@ -256,7 +256,7 @@ func Test_validateCustomizationRule(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantErr: true,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
|
|
@ -282,6 +282,7 @@ var _ = framework.SerialDescribe("Resource interpreter customization testing", f
|
||||||
// We only need to test any one of the member clusters.
|
// We only need to test any one of the member clusters.
|
||||||
var targetCluster string
|
var targetCluster string
|
||||||
|
|
||||||
|
ginkgo.When("Apply single ResourceInterpreterCustomization without DependencyInterpretation operation", func() {
|
||||||
ginkgo.BeforeEach(func() {
|
ginkgo.BeforeEach(func() {
|
||||||
targetCluster = framework.ClusterNames()[rand.Intn(len(framework.ClusterNames()))]
|
targetCluster = framework.ClusterNames()[rand.Intn(len(framework.ClusterNames()))]
|
||||||
deployment = testhelper.NewDeployment(testNamespace, deploymentNamePrefix+rand.String(RandomStrLength))
|
deployment = testhelper.NewDeployment(testNamespace, deploymentNamePrefix+rand.String(RandomStrLength))
|
||||||
|
@ -594,15 +595,49 @@ end `,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
ginkgo.When("Apply multi ResourceInterpreterCustomization with DependencyInterpretation operation", func() {
|
||||||
|
var customizationAnother *configv1alpha1.ResourceInterpreterCustomization
|
||||||
|
|
||||||
|
var configMapName string
|
||||||
|
var configMap *corev1.ConfigMap
|
||||||
|
|
||||||
ginkgo.Context("InterpreterOperation DependencyInterpretation testing", func() {
|
|
||||||
var saName string
|
var saName string
|
||||||
var sa *corev1.ServiceAccount
|
var sa *corev1.ServiceAccount
|
||||||
|
|
||||||
ginkgo.BeforeEach(func() {
|
ginkgo.BeforeEach(func() {
|
||||||
|
targetCluster = framework.ClusterNames()[rand.Intn(len(framework.ClusterNames()))]
|
||||||
|
|
||||||
|
deployment = testhelper.NewDeployment(testNamespace, deploymentNamePrefix+rand.String(RandomStrLength))
|
||||||
|
|
||||||
|
configMapName = configMapNamePrefix + rand.String(RandomStrLength)
|
||||||
|
configMap = testhelper.NewConfigMap(testNamespace, configMapName, map[string]string{"user": "karmada"})
|
||||||
|
deployment.Spec.Template.Spec.Volumes = []corev1.Volume{{
|
||||||
|
Name: "vol-configmap",
|
||||||
|
VolumeSource: corev1.VolumeSource{
|
||||||
|
ConfigMap: &corev1.ConfigMapVolumeSource{
|
||||||
|
LocalObjectReference: corev1.LocalObjectReference{
|
||||||
|
Name: configMapName,
|
||||||
|
}}}}}
|
||||||
|
|
||||||
saName = saNamePrefix + rand.String(RandomStrLength)
|
saName = saNamePrefix + rand.String(RandomStrLength)
|
||||||
sa = testhelper.NewServiceaccount(testNamespace, saName)
|
sa = testhelper.NewServiceaccount(testNamespace, saName)
|
||||||
deployment = testhelper.NewDeploymentWithServiceAccount(testNamespace, deployment.Name, saName)
|
deployment.Spec.Template.Spec.ServiceAccountName = saName
|
||||||
|
|
||||||
|
policy = testhelper.NewPropagationPolicy(testNamespace, deployment.Name, []policyv1alpha1.ResourceSelector{
|
||||||
|
{
|
||||||
|
APIVersion: deployment.APIVersion,
|
||||||
|
Kind: deployment.Kind,
|
||||||
|
Name: deployment.Name,
|
||||||
|
},
|
||||||
|
}, policyv1alpha1.Placement{
|
||||||
|
ClusterAffinity: &policyv1alpha1.ClusterAffinity{
|
||||||
|
ClusterNames: []string{targetCluster},
|
||||||
|
},
|
||||||
|
})
|
||||||
policy.Spec.PropagateDeps = true
|
policy.Spec.PropagateDeps = true
|
||||||
|
|
||||||
customization = testhelper.NewResourceInterpreterCustomization(
|
customization = testhelper.NewResourceInterpreterCustomization(
|
||||||
"interpreter-customization"+rand.String(RandomStrLength),
|
"interpreter-customization"+rand.String(RandomStrLength),
|
||||||
configv1alpha1.CustomizationTarget{
|
configv1alpha1.CustomizationTarget{
|
||||||
|
@ -632,25 +667,84 @@ function GetDependencies(desiredObj)
|
||||||
end `,
|
end `,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
customizationAnother = testhelper.NewResourceInterpreterCustomization(
|
||||||
|
"interpreter-customization"+rand.String(RandomStrLength),
|
||||||
|
configv1alpha1.CustomizationTarget{
|
||||||
|
APIVersion: "apps/v1",
|
||||||
|
Kind: "Deployment",
|
||||||
|
},
|
||||||
|
configv1alpha1.CustomizationRules{
|
||||||
|
DependencyInterpretation: &configv1alpha1.DependencyInterpretation{
|
||||||
|
LuaScript: `
|
||||||
|
function GetDependencies(desiredObj)
|
||||||
|
dependentSas = {}
|
||||||
|
refs = {}
|
||||||
|
if desiredObj.spec.template.spec.volumes == nil then
|
||||||
|
return refs
|
||||||
|
end
|
||||||
|
local idx = 1
|
||||||
|
for index, volume in pairs(desiredObj.spec.template.spec.volumes) do
|
||||||
|
if volume.configMap ~= nil then
|
||||||
|
dependObj = {}
|
||||||
|
dependObj.apiVersion = 'v1'
|
||||||
|
dependObj.kind = 'ConfigMap'
|
||||||
|
dependObj.name = volume.configMap.name
|
||||||
|
dependObj.namespace = desiredObj.metadata.namespace
|
||||||
|
refs[idx] = dependObj
|
||||||
|
idx = idx + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return refs
|
||||||
|
end `,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
ginkgo.It("DependencyInterpretation testing", func() {
|
})
|
||||||
ginkgo.By("check if the serviceAccount is propagated automatically", func() {
|
|
||||||
|
ginkgo.JustBeforeEach(func() {
|
||||||
|
framework.CreateResourceInterpreterCustomization(karmadaClient, customization)
|
||||||
|
framework.CreateResourceInterpreterCustomization(karmadaClient, customizationAnother)
|
||||||
|
// Wait for resource interpreter informer synced.
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
framework.CreateServiceAccount(kubeClient, sa)
|
framework.CreateServiceAccount(kubeClient, sa)
|
||||||
|
framework.CreateConfigMap(kubeClient, configMap)
|
||||||
|
|
||||||
|
framework.CreatePropagationPolicy(karmadaClient, policy)
|
||||||
|
framework.CreateDeployment(kubeClient, deployment)
|
||||||
|
|
||||||
ginkgo.DeferCleanup(func() {
|
ginkgo.DeferCleanup(func() {
|
||||||
framework.RemoveServiceAccount(kubeClient, sa.GetNamespace(), sa.GetName())
|
framework.RemoveServiceAccount(kubeClient, sa.Namespace, sa.Name)
|
||||||
|
framework.RemoveConfigMap(kubeClient, configMap.Namespace, configMap.Name)
|
||||||
|
|
||||||
|
framework.RemoveDeployment(kubeClient, deployment.Namespace, deployment.Name)
|
||||||
|
framework.RemovePropagationPolicy(karmadaClient, policy.Namespace, policy.Name)
|
||||||
|
|
||||||
|
framework.DeleteResourceInterpreterCustomization(karmadaClient, customization.Name)
|
||||||
|
framework.DeleteResourceInterpreterCustomization(karmadaClient, customizationAnother.Name)
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
ginkgo.Context("InterpreterOperation DependencyInterpretation testing", func() {
|
||||||
|
ginkgo.It("DependencyInterpretation testing", func() {
|
||||||
|
ginkgo.By("check if the resources is propagated automatically", func() {
|
||||||
framework.WaitDeploymentPresentOnClusterFitWith(targetCluster, deployment.Namespace, deployment.Name,
|
framework.WaitDeploymentPresentOnClusterFitWith(targetCluster, deployment.Namespace, deployment.Name,
|
||||||
func(deployment *appsv1.Deployment) bool {
|
func(deployment *appsv1.Deployment) bool {
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
framework.WaitServiceAccountPresentOnClusterFitWith(targetCluster, deployment.Namespace, sa.GetName(),
|
framework.WaitServiceAccountPresentOnClusterFitWith(targetCluster, sa.Namespace, sa.Name,
|
||||||
func(sa *corev1.ServiceAccount) bool {
|
func(sa *corev1.ServiceAccount) bool {
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
framework.WaitConfigMapPresentOnClusterFitWith(targetCluster, configMap.Namespace, configMap.Name,
|
||||||
|
func(configmap *corev1.ConfigMap) bool {
|
||||||
|
return true
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue