Merge pull request #2794 from jameszhangyukun/pr-interpret-interfaces

Resource Interpreter implements the interfaces
This commit is contained in:
karmada-bot 2022-11-16 17:43:59 +08:00 committed by GitHub
commit ba084975d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 248 additions and 203 deletions

View File

@ -58,31 +58,52 @@ func NewResourceCustomAccessorAccessor(customization *configv1alpha1.ResourceInt
}
func (a *resourceCustomAccessor) GetRetentionLuaScript() string {
if a.retention == nil {
return ""
}
return a.retention.LuaScript
}
func (a *resourceCustomAccessor) GetReplicaResourceLuaScript() string {
return a.replicaRevision.LuaScript
}
func (a *resourceCustomAccessor) GetReplicaRevisionLuaScript() string {
if a.replicaResource == nil {
return ""
}
return a.replicaResource.LuaScript
}
func (a *resourceCustomAccessor) GetReplicaRevisionLuaScript() string {
if a.replicaRevision == nil {
return ""
}
return a.replicaRevision.LuaScript
}
func (a *resourceCustomAccessor) GetStatusReflectionLuaScript() string {
if a.statusReflection == nil {
return ""
}
return a.statusReflection.LuaScript
}
func (a *resourceCustomAccessor) GetStatusAggregationLuaScript() string {
if a.statusAggregation == nil {
return ""
}
return a.statusAggregation.LuaScript
}
func (a *resourceCustomAccessor) GetHealthInterpretationLuaScript() string {
if a.healthInterpretation == nil {
return ""
}
return a.healthInterpretation.LuaScript
}
func (a *resourceCustomAccessor) GetDependencyInterpretationLuaScript() string {
return a.healthInterpretation.LuaScript
if a.dependencyInterpretation == nil {
return ""
}
return a.dependencyInterpretation.LuaScript
}
func (a *resourceCustomAccessor) Name() string {

View File

@ -24,7 +24,7 @@ var resourceInterpreterCustomizationsGVR = schema.GroupVersionResource{
// ConfigManager can list custom resource interpreter.
type ConfigManager interface {
LuaScriptAccessors() map[schema.GroupVersionKind]LuaScriptAccessor
LuaScriptAccessors() map[schema.GroupVersionKind]CustomAccessor
HasSynced() bool
}
@ -36,8 +36,8 @@ type interpreterConfigManager struct {
}
// LuaScriptAccessors returns all cached configurations.
func (configManager *interpreterConfigManager) LuaScriptAccessors() map[schema.GroupVersionKind]LuaScriptAccessor {
return configManager.configuration.Load().(map[schema.GroupVersionKind]LuaScriptAccessor)
func (configManager *interpreterConfigManager) LuaScriptAccessors() map[schema.GroupVersionKind]CustomAccessor {
return configManager.configuration.Load().(map[schema.GroupVersionKind]CustomAccessor)
}
// HasSynced returns true when the cache is synced.
@ -46,8 +46,13 @@ func (configManager *interpreterConfigManager) HasSynced() bool {
return true
}
if configManager.HasSynced() {
if configuration, err := configManager.lister.List(labels.Everything()); err == nil && len(configuration) == 0 {
// the empty list we initially stored is valid to use.
// Setting initialSynced to true, so subsequent checks
// would be able to take the fast path on the atomic boolean in a
// cluster without any customization configured.
configManager.initialSynced.Store(true)
// the informer has synced, and we don't have any items
return true
}
return false
@ -61,7 +66,7 @@ func NewInterpreterConfigManager(inform genericmanager.SingleClusterInformerMana
initialSynced: &atomic.Value{},
configuration: &atomic.Value{},
}
manager.configuration.Store(make(map[schema.GroupVersionKind]LuaScriptAccessor))
manager.configuration.Store(make(map[schema.GroupVersionKind]CustomAccessor))
manager.initialSynced.Store(false)
configHandlers := fedinformer.NewHandlerOnEvents(
func(_ interface{}) { manager.updateConfiguration() },
@ -88,7 +93,6 @@ func (configManager *interpreterConfigManager) updateConfiguration() {
key := schema.FromAPIVersionAndKind(config.Spec.Target.APIVersion, config.Spec.Target.Kind)
configs[key] = NewResourceCustomAccessorAccessor(config)
}
configManager.configuration.Store(configs)
configManager.initialSynced.Store(true)
}

View File

@ -1,8 +1,6 @@
package configurableinterpreter
import (
"fmt"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
@ -11,6 +9,7 @@ import (
configv1alpha1 "github.com/karmada-io/karmada/pkg/apis/config/v1alpha1"
workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2"
"github.com/karmada-io/karmada/pkg/resourceinterpreter/configurableinterpreter/configmanager"
"github.com/karmada-io/karmada/pkg/resourceinterpreter/configurableinterpreter/luavm"
"github.com/karmada-io/karmada/pkg/util/fedinformer/genericmanager"
)
@ -30,128 +29,112 @@ func NewConfigurableInterpreter(informer genericmanager.SingleClusterInformerMan
// HookEnabled tells if any hook exist for specific resource gvk and operation type.
func (c *ConfigurableInterpreter) HookEnabled(kind schema.GroupVersionKind, operationType configv1alpha1.InterpreterOperation) bool {
if !c.configManager.HasSynced() {
klog.Errorf("not yet ready to handle request")
return false
}
accessors, exist := c.configManager.LuaScriptAccessors()[kind]
if !exist {
return false
}
switch operationType {
case configv1alpha1.InterpreterOperationAggregateStatus:
return len(accessors.GetStatusAggregationLuaScript()) > 0
case configv1alpha1.InterpreterOperationInterpretHealth:
return len(accessors.GetHealthInterpretationLuaScript()) > 0
case configv1alpha1.InterpreterOperationInterpretDependency:
return len(accessors.GetDependencyInterpretationLuaScript()) > 0
case configv1alpha1.InterpreterOperationInterpretReplica:
return len(accessors.GetReplicaResourceLuaScript()) > 0
case configv1alpha1.InterpreterOperationInterpretStatus:
return len(accessors.GetStatusReflectionLuaScript()) > 0
case configv1alpha1.InterpreterOperationRetain:
return len(accessors.GetRetentionLuaScript()) > 0
case configv1alpha1.InterpreterOperationReviseReplica:
return len(accessors.GetReplicaRevisionLuaScript()) > 0
}
return false
_, exist := c.getInterpreter(kind, operationType)
return exist
}
// GetReplicas returns the desired replicas of the object as well as the requirements of each replica.
func (c *ConfigurableInterpreter) GetReplicas(object *unstructured.Unstructured) (int32, *workv1alpha2.ReplicaRequirements, error) {
klog.Infof("ConfigurableInterpreter Execute ReviseReplica")
customAccessor := c.configManager.LuaScriptAccessors()[object.GroupVersionKind()]
if len(customAccessor.GetReplicaResourceLuaScript()) == 0 {
return 0, nil, fmt.Errorf("customized interpreter operation GetReplicas for %q not found", object.GroupVersionKind())
func (c *ConfigurableInterpreter) GetReplicas(object *unstructured.Unstructured) (replicas int32, requires *workv1alpha2.ReplicaRequirements, enabled bool, err error) {
luaScript, enabled := c.getInterpreter(object.GroupVersionKind(), configv1alpha1.InterpreterOperationInterpretReplica)
if !enabled {
return
}
luaScript := customAccessor.GetReplicaResourceLuaScript
klog.Infof("lua script %s", luaScript)
return 0, nil, nil
vm := luavm.VM{UseOpenLibs: false}
replicas, requires, err = vm.GetReplicas(object, luaScript)
return
}
// ReviseReplica revises the replica of the given object.
func (c *ConfigurableInterpreter) ReviseReplica(object *unstructured.Unstructured, replica int64) (*unstructured.Unstructured, error) {
klog.Infof("ConfigurableInterpreter Execute ReviseReplica")
customAccessor := c.configManager.LuaScriptAccessors()[object.GroupVersionKind()]
if len(customAccessor.GetReplicaRevisionLuaScript()) == 0 {
return nil, fmt.Errorf("customized interpreter operation ReviseReplica for %q not found", object.GroupVersionKind())
func (c *ConfigurableInterpreter) ReviseReplica(object *unstructured.Unstructured, replica int64) (revised *unstructured.Unstructured, enabled bool, err error) {
luaScript, enabled := c.getInterpreter(object.GroupVersionKind(), configv1alpha1.InterpreterOperationReviseReplica)
if !enabled {
return
}
luaScript := customAccessor.GetReplicaRevisionLuaScript()
klog.Infof("lua script %s", luaScript)
return nil, nil
vm := luavm.VM{UseOpenLibs: false}
revised, err = vm.ReviseReplica(object, replica, luaScript)
return
}
// 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, err error) {
klog.Infof("ConfigurableInterpreter Execute Retain")
customAccessor := c.configManager.LuaScriptAccessors()[desired.GroupVersionKind()]
if len(customAccessor.GetRetentionLuaScript()) == 0 {
return nil, fmt.Errorf("customized interpreter operation Retain for %q not found", desired.GroupVersionKind())
func (c *ConfigurableInterpreter) Retain(desired *unstructured.Unstructured, observed *unstructured.Unstructured) (retained *unstructured.Unstructured, enabled bool, err error) {
luaScript, enabled := c.getInterpreter(desired.GroupVersionKind(), configv1alpha1.InterpreterOperationRetain)
if !enabled {
return
}
luaScript := customAccessor.GetRetentionLuaScript()
klog.Infof("lua script %s", luaScript)
return nil, err
vm := luavm.VM{UseOpenLibs: false}
retained, err = vm.Retain(desired, observed, luaScript)
return
}
// AggregateStatus returns the objects that based on the 'object' but with status aggregated.
func (c *ConfigurableInterpreter) AggregateStatus(object *unstructured.Unstructured, aggregatedStatusItems []workv1alpha2.AggregatedStatusItem) (*unstructured.Unstructured, error) {
klog.Infof("ConfigurableInterpreter Execute AggregateStatus")
customAccessor := c.configManager.LuaScriptAccessors()[object.GroupVersionKind()]
if len(customAccessor.GetStatusAggregationLuaScript()) == 0 {
return nil, fmt.Errorf("customized interpreter AggregateStatus Retain for %q not found", object.GroupVersionKind())
func (c *ConfigurableInterpreter) AggregateStatus(object *unstructured.Unstructured, aggregatedStatusItems []workv1alpha2.AggregatedStatusItem) (status *unstructured.Unstructured, enabled bool, err error) {
luaScript, enabled := c.getInterpreter(object.GroupVersionKind(), configv1alpha1.InterpreterOperationAggregateStatus)
if !enabled {
return
}
luaScript := customAccessor.GetStatusAggregationLuaScript()
klog.Infof("lua script %s", luaScript)
return nil, nil
vm := luavm.VM{UseOpenLibs: false}
status, err = vm.AggregateStatus(object, aggregatedStatusItems, luaScript)
return
}
// GetDependencies returns the dependent resources of the given object.
func (c *ConfigurableInterpreter) GetDependencies(object *unstructured.Unstructured) (dependencies []configv1alpha1.DependentObjectReference, err error) {
klog.Infof("ConfigurableInterpreter Execute GetDependencies")
customAccessor := c.configManager.LuaScriptAccessors()[object.GroupVersionKind()]
if len(customAccessor.GetDependencyInterpretationLuaScript()) == 0 {
return nil, fmt.Errorf("customized interpreter GetDependencies Retain for %q not found", object.GroupVersionKind())
func (c *ConfigurableInterpreter) GetDependencies(object *unstructured.Unstructured) (dependencies []configv1alpha1.DependentObjectReference, enabled bool, err error) {
luaScript, enabled := c.getInterpreter(object.GroupVersionKind(), configv1alpha1.InterpreterOperationInterpretDependency)
if !enabled {
return
}
luaScript := customAccessor.GetDependencyInterpretationLuaScript()
klog.Infof("lua script %s", luaScript)
return nil, err
vm := luavm.VM{UseOpenLibs: false}
dependencies, err = vm.GetDependencies(object, luaScript)
return
}
// ReflectStatus returns the status of the object.
func (c *ConfigurableInterpreter) ReflectStatus(object *unstructured.Unstructured) (status *runtime.RawExtension, err error) {
klog.Infof("ConfigurableInterpreter Execute ReflectStatus")
customAccessor := c.configManager.LuaScriptAccessors()[object.GroupVersionKind()]
if len(customAccessor.GetStatusAggregationLuaScript()) == 0 {
return nil, fmt.Errorf("customized interpreter GetDependencies Retain for %q not found", object.GroupVersionKind())
func (c *ConfigurableInterpreter) ReflectStatus(object *unstructured.Unstructured) (status *runtime.RawExtension, enabled bool, err error) {
luaScript, enabled := c.getInterpreter(object.GroupVersionKind(), configv1alpha1.InterpreterOperationInterpretStatus)
if !enabled {
return
}
luaScript := customAccessor.GetStatusAggregationLuaScript()
klog.Infof("lua script %s", luaScript)
return nil, err
vm := luavm.VM{UseOpenLibs: false}
status, err = vm.ReflectStatus(object, luaScript)
return
}
// InterpretHealth returns the health state of the object.
func (c *ConfigurableInterpreter) InterpretHealth(object *unstructured.Unstructured) (bool, error) {
klog.Infof("ConfigurableInterpreter Execute InterpretHealth")
customAccessor := c.configManager.LuaScriptAccessors()[object.GroupVersionKind()]
if len(customAccessor.GetHealthInterpretationLuaScript()) == 0 {
return false, fmt.Errorf("customized interpreter GetHealthInterpretation for %q not found", object.GroupVersionKind())
func (c *ConfigurableInterpreter) InterpretHealth(object *unstructured.Unstructured) (health bool, enabled bool, err error) {
luaScript, enabled := c.getInterpreter(object.GroupVersionKind(), configv1alpha1.InterpreterOperationInterpretHealth)
if !enabled {
return
}
luaScript := customAccessor.GetHealthInterpretationLuaScript()
klog.Infof("lua script %s", luaScript)
return false, nil
vm := luavm.VM{UseOpenLibs: false}
health, err = vm.InterpretHealth(object, luaScript)
return
}
func (c *ConfigurableInterpreter) getInterpreter(kind schema.GroupVersionKind, operationType configv1alpha1.InterpreterOperation) (string, bool) {
if !c.configManager.HasSynced() {
klog.Errorf("not yet ready to handle request")
return "", false
}
accessors, exist := c.configManager.LuaScriptAccessors()[kind]
if !exist {
return "", false
}
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
}

View File

@ -15,7 +15,6 @@ import (
configv1alpha1 "github.com/karmada-io/karmada/pkg/apis/config/v1alpha1"
workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2"
"github.com/karmada-io/karmada/pkg/util/helper"
"github.com/karmada-io/karmada/pkg/util/lifted"
)
@ -214,7 +213,7 @@ func (vm VM) Retain(desired *unstructured.Unstructured, observed *unstructured.U
}
// AggregateStatus returns the objects that based on the 'object' but with status aggregated by lua.
func (vm VM) AggregateStatus(object *unstructured.Unstructured, item []map[string]interface{}, script string) (*unstructured.Unstructured, error) {
func (vm VM) AggregateStatus(object *unstructured.Unstructured, items []workv1alpha2.AggregatedStatusItem, script string) (*unstructured.Unstructured, error) {
l := lua.NewState(lua.Options{
SkipOpenLibs: !vm.UseOpenLibs,
})
@ -245,7 +244,7 @@ func (vm VM) AggregateStatus(object *unstructured.Unstructured, item []map[strin
if err != nil {
return nil, err
}
args[1], err = decodeValue(l, item)
args[1], err = decodeValue(l, items)
if err != nil {
return nil, err
}
@ -344,7 +343,7 @@ func (vm VM) ReflectStatus(object *unstructured.Unstructured, script string) (st
if err != nil {
return
}
err = l.CallByParam(lua.P{Fn: f, NRet: 2, Protect: true}, args...)
err = l.CallByParam(lua.P{Fn: f, NRet: 1, Protect: true}, args...)
if err != nil {
return nil, err
}
@ -354,26 +353,9 @@ func (vm VM) ReflectStatus(object *unstructured.Unstructured, script string) (st
return nil, fmt.Errorf("expect the returned replica type is table but got %s", luaStatusResult.Type())
}
luaExistResult := l.Get(l.GetTop())
var exist bool
exist, err = ConvertLuaResultToBool(luaExistResult)
if err != nil {
return nil, err
}
if exist {
resultMap := make(map[string]interface{})
jsonBytes, err := luajson.Encode(luaStatusResult)
if err != nil {
return nil, err
}
err = json.Unmarshal(jsonBytes, &resultMap)
if err != nil {
return nil, err
}
return helper.BuildStatusRawExtension(resultMap)
}
return nil, err
status = &runtime.RawExtension{}
err = ConvertLuaResultInto(luaStatusResult, status)
return status, err
}
// GetDependencies returns the dependent resources of the given object by lua.
@ -414,18 +396,11 @@ func (vm VM) GetDependencies(object *unstructured.Unstructured, script string) (
}
luaResult := l.Get(l.GetTop())
if luaResult.Type() == lua.LTTable {
jsonBytes, err := luajson.Encode(luaResult)
if err != nil {
return nil, err
}
err = json.Unmarshal(jsonBytes, &dependencies)
if err != nil {
return nil, err
}
} else {
if luaResult.Type() != lua.LTTable {
return nil, fmt.Errorf("expect the returned requires type is table but got %s", luaResult.Type())
}
err = ConvertLuaResultInto(luaResult, &dependencies)
return
}

View File

@ -11,22 +11,23 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/klog/v2"
"k8s.io/utils/pointer"
configv1alpha1 "github.com/karmada-io/karmada/pkg/apis/config/v1alpha1"
workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2"
"github.com/karmada-io/karmada/pkg/util/helper"
)
func TestGetReplicas(t *testing.T) {
var replicas int32 = 1
// quantity := *resource.NewQuantity(1000, resource.BinarySI)
vm := VM{UseOpenLibs: false}
tests := []struct {
name string
deploy *appsv1.Deployment
luaScript string
expected bool
name string
deploy *appsv1.Deployment
luaScript string
expected bool
wantReplica int32
wantRequires *workv1alpha2.ReplicaRequirements
}{
{
name: "Test GetReplica",
@ -63,6 +64,8 @@ func TestGetReplicas(t *testing.T) {
result.nodeClaim = nil
return replica, {}
end`,
wantReplica: 1,
wantRequires: &workv1alpha2.ReplicaRequirements{},
},
}
@ -70,11 +73,15 @@ func TestGetReplicas(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
toUnstructured, _ := helper.ToUnstructured(tt.deploy)
replicas, requires, err := vm.GetReplicas(toUnstructured, tt.luaScript)
klog.Infof("replicas %v", replicas)
klog.Infof("requires %v", requires)
if err != nil {
t.Errorf(err.Error())
}
if !reflect.DeepEqual(replicas, tt.wantReplica) {
t.Errorf("GetReplicas() got = %v, want %v", replicas, tt.wantReplica)
}
if !reflect.DeepEqual(requires, tt.wantRequires) {
t.Errorf("GetReplicas() got = %v, want %v", requires, tt.wantRequires)
}
})
}
}
@ -166,9 +173,9 @@ func TestReviseDeploymentReplica(t *testing.T) {
func TestAggregateDeploymentStatus(t *testing.T) {
statusMap := map[string]interface{}{
"replicas": 0,
"readyReplicas": 0,
"readyReplicas": 1,
"updatedReplicas": 0,
"availableReplicas": 1,
"availableReplicas": 0,
"unavailableReplicas": 0,
}
raw, _ := helper.BuildStatusRawExtension(statusMap)
@ -186,37 +193,25 @@ func TestAggregateDeploymentStatus(t *testing.T) {
oldDeploy.Status = appsv1.DeploymentStatus{
Replicas: 0, ReadyReplicas: 1, UpdatedReplicas: 0, AvailableReplicas: 0, UnavailableReplicas: 0}
newDeploy := &appsv1.Deployment{Status: appsv1.DeploymentStatus{Replicas: 0, ReadyReplicas: 0, UpdatedReplicas: 0, AvailableReplicas: 2, UnavailableReplicas: 0}}
newDeploy := &appsv1.Deployment{Status: appsv1.DeploymentStatus{Replicas: 0, ReadyReplicas: 3, UpdatedReplicas: 0, AvailableReplicas: 0, UnavailableReplicas: 0}}
oldObj, _ := helper.ToUnstructured(oldDeploy)
newObj, _ := helper.ToUnstructured(newDeploy)
var aggregateItem []map[string]interface{}
for _, item := range aggregatedStatusItems {
if item.Status == nil {
continue
}
temp := make(map[string]interface{})
if err := json.Unmarshal(item.Status.Raw, &temp); err != nil {
t.Error(err.Error())
}
aggregateItem = append(aggregateItem, temp)
}
tests := []struct {
name string
curObj *unstructured.Unstructured
aggregatedStatusItems []map[string]interface{}
aggregatedStatusItems []workv1alpha2.AggregatedStatusItem
expectedObj *unstructured.Unstructured
luaScript string
}{
{
name: "Test AggregateDeploymentStatus",
curObj: oldObj,
aggregatedStatusItems: aggregateItem,
aggregatedStatusItems: aggregatedStatusItems,
expectedObj: newObj,
luaScript: `function AggregateStatus(desiredObj, statusItems)
luaScript: `function AggregateStatus(desiredObj, statusItems)
for i = 1, #statusItems do
desiredObj.status.readyReplicas = desiredObj.status.readyReplicas + statusItems[i].readyReplicas
desiredObj.status.readyReplicas = desiredObj.status.readyReplicas + statusItems[i].status.readyReplicas
end
return desiredObj
end`,
@ -236,8 +231,8 @@ func TestAggregateDeploymentStatus(t *testing.T) {
if err != nil {
t.Error(err.Error())
}
if reflect.DeepEqual(expectDeploy, actualDeploy) {
t.Log("Success \n")
if !reflect.DeepEqual(expectDeploy, actualDeploy) {
t.Errorf("AggregateStatus() got = %v, want %v", actualDeploy, expectDeploy)
}
}
}
@ -273,10 +268,13 @@ func TestHealthDeploymentStatus(t *testing.T) {
vm := VM{UseOpenLibs: false}
for _, tt := range tests {
flag, _ := vm.InterpretHealth(tt.curObj, tt.luaScript)
flag, err := vm.InterpretHealth(tt.curObj, tt.luaScript)
if reflect.DeepEqual(flag, tt.expectedObj) {
t.Log("Success \n")
if err != nil {
t.Error(err.Error())
}
if !reflect.DeepEqual(flag, tt.expectedObj) {
t.Errorf("AggregateStatus() got = %v, want %v", flag, tt.expectedObj)
}
}
}
@ -290,7 +288,7 @@ func TestRetainDeployment(t *testing.T) {
luaScript string
}{
{
name: "Test RetainDeployment",
name: "Test RetainDeployment1",
desiredObj: &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "apps/v1",
@ -299,7 +297,7 @@ func TestRetainDeployment(t *testing.T) {
"name": "fake-deployment",
},
"spec": map[string]interface{}{
"replicas": 1,
"replicas": 2,
},
},
},
@ -319,7 +317,7 @@ func TestRetainDeployment(t *testing.T) {
luaScript: "function Retain(desiredObj, observedObj)\n desiredObj = observedObj\n return desiredObj\n end",
},
{
name: "revise deployment replica",
name: "Test RetainDeployment2",
desiredObj: &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "apps/v1",
@ -340,7 +338,7 @@ func TestRetainDeployment(t *testing.T) {
"name": "fake-deployment",
},
"spec": map[string]interface{}{
"replicas": int64(2),
"replicas": int64(1),
},
},
},
@ -359,13 +357,8 @@ func TestRetainDeployment(t *testing.T) {
if err != nil {
t.Errorf(err.Error())
}
deploy := &appsv1.Deployment{}
err = runtime.DefaultUnstructuredConverter.FromUnstructured(res.UnstructuredContent(), deploy)
if err == nil && reflect.DeepEqual(deploy, tt.observedObj) {
t.Log("Success Test")
}
if err != nil {
t.Errorf(err.Error())
if !reflect.DeepEqual(res.UnstructuredContent(), tt.observedObj.Object) {
t.Errorf("Retain() got = %v, want %v", res.UnstructuredContent(), tt.observedObj.Object)
}
})
}
@ -397,9 +390,9 @@ func TestStatusReflection(t *testing.T) {
false,
`function ReflectStatus (observedObj)
if observedObj.status == nil then
return false, nil
return nil
end
return true, observedObj.status
return observedObj.status
end`,
},
}
@ -438,11 +431,18 @@ func TestGetDeployPodDependencies(t *testing.T) {
},
}
newObj, _ := helper.ToUnstructured(&newDeploy)
expect := make([]configv1alpha1.DependentObjectReference, 1)
expect[0] = configv1alpha1.DependentObjectReference{
APIVersion: "v1",
Kind: "ServiceAccount",
Namespace: "test",
Name: "test",
}
tests := []struct {
name string
curObj *unstructured.Unstructured
luaScript string
want []configv1alpha1.DependentObjectReference
}{
{
name: "Get GetDeployPodDependencies",
@ -450,30 +450,36 @@ func TestGetDeployPodDependencies(t *testing.T) {
luaScript: `function GetDependencies(desiredObj)
dependentSas = {}
refs = {}
if desiredObj.spec.template.spec.serviceAccountName ~= \"\" and desiredObj.spec.template.spec.serviceAccountName ~= \"default\" then
if desiredObj.spec.template.spec.serviceAccountName ~= '' and desiredObj.spec.template.spec.serviceAccountName ~= 'default' then
dependentSas[desiredObj.spec.template.spec.serviceAccountName] = true
end
local idx = 1
for key, value in pairs(dependentSas) do
dependObj = {}
dependObj.apiVersion = \"v1\"
dependObj.kind = \"ServiceAccount\"
dependObj.apiVersion = 'v1'
dependObj.kind = 'ServiceAccount'
dependObj.name = key
dependObj.namespace = desiredObj.namespace
dependObj.namespace = desiredObj.metadata.namespace
refs[idx] = {}
refs[idx] = dependObj
idx = idx + 1
end
return refs
end`,
want: expect,
},
}
vm := VM{UseOpenLibs: false}
for _, tt := range tests {
res, _ := vm.GetDependencies(tt.curObj, tt.luaScript)
t.Logf("res %v", res)
res, err := vm.GetDependencies(tt.curObj, tt.luaScript)
if err != nil {
t.Errorf("GetDependencies err %v", err)
}
if !reflect.DeepEqual(res, tt.want) {
t.Errorf("GetDependencies() got = %v, want %v", res, tt.want)
}
}
}

View File

@ -84,8 +84,9 @@ func (i *customResourceInterpreterImpl) Start(ctx context.Context) (err error) {
// HookEnabled tells if any hook exist for specific resource type and operation.
func (i *customResourceInterpreterImpl) HookEnabled(objGVK schema.GroupVersionKind, operation configv1alpha1.InterpreterOperation) bool {
return i.customizedInterpreter.HookEnabled(objGVK, operation) ||
i.defaultInterpreter.HookEnabled(objGVK, operation)
return i.defaultInterpreter.HookEnabled(objGVK, operation) ||
i.configurableInterpreter.HookEnabled(objGVK, operation) ||
i.customizedInterpreter.HookEnabled(objGVK, operation)
}
// GetReplicas returns the desired replicas of the object as well as the requirements of each replica.
@ -93,6 +94,15 @@ func (i *customResourceInterpreterImpl) GetReplicas(object *unstructured.Unstruc
klog.V(4).Infof("Begin to get replicas for request object: %v %s/%s.", object.GroupVersionKind(), object.GetNamespace(), object.GetName())
var hookEnabled bool
replica, requires, hookEnabled, err = i.configurableInterpreter.GetReplicas(object)
if err != nil {
return
}
if hookEnabled {
return
}
replica, requires, hookEnabled, err = i.customizedInterpreter.GetReplicas(context.TODO(), &webhook.RequestAttributes{
Operation: configv1alpha1.InterpreterOperationInterpretReplica,
Object: object,
@ -112,7 +122,15 @@ func (i *customResourceInterpreterImpl) GetReplicas(object *unstructured.Unstruc
func (i *customResourceInterpreterImpl) ReviseReplica(object *unstructured.Unstructured, replica int64) (*unstructured.Unstructured, error) {
klog.V(4).Infof("Begin to revise replicas for object: %v %s/%s.", object.GroupVersionKind(), object.GetNamespace(), object.GetName())
obj, hookEnabled, err := i.customizedInterpreter.Patch(context.TODO(), &webhook.RequestAttributes{
obj, hookEnabled, err := i.configurableInterpreter.ReviseReplica(object, replica)
if err != nil {
return nil, err
}
if hookEnabled {
return obj, nil
}
obj, hookEnabled, err = i.customizedInterpreter.Patch(context.TODO(), &webhook.RequestAttributes{
Operation: configv1alpha1.InterpreterOperationReviseReplica,
Object: object,
ReplicasSet: int32(replica),
@ -131,7 +149,15 @@ func (i *customResourceInterpreterImpl) ReviseReplica(object *unstructured.Unstr
func (i *customResourceInterpreterImpl) Retain(desired *unstructured.Unstructured, observed *unstructured.Unstructured) (*unstructured.Unstructured, error) {
klog.V(4).Infof("Begin to retain object: %v %s/%s.", desired.GroupVersionKind(), desired.GetNamespace(), desired.GetName())
obj, hookEnabled, err := i.customizedInterpreter.Patch(context.TODO(), &webhook.RequestAttributes{
obj, hookEnabled, err := i.configurableInterpreter.Retain(desired, observed)
if err != nil {
return nil, err
}
if hookEnabled {
return obj, nil
}
obj, hookEnabled, err = i.customizedInterpreter.Patch(context.TODO(), &webhook.RequestAttributes{
Operation: configv1alpha1.InterpreterOperationRetain,
Object: desired,
ObservedObj: observed,
@ -150,7 +176,15 @@ func (i *customResourceInterpreterImpl) Retain(desired *unstructured.Unstructure
func (i *customResourceInterpreterImpl) AggregateStatus(object *unstructured.Unstructured, aggregatedStatusItems []workv1alpha2.AggregatedStatusItem) (*unstructured.Unstructured, error) {
klog.V(4).Infof("Begin to aggregate status for object: %v %s/%s.", object.GroupVersionKind(), object.GetNamespace(), object.GetName())
obj, hookEnabled, err := i.customizedInterpreter.Patch(context.TODO(), &webhook.RequestAttributes{
obj, hookEnabled, err := i.configurableInterpreter.AggregateStatus(object, aggregatedStatusItems)
if err != nil {
return nil, err
}
if hookEnabled {
return obj, nil
}
obj, hookEnabled, err = i.customizedInterpreter.Patch(context.TODO(), &webhook.RequestAttributes{
Operation: configv1alpha1.InterpreterOperationAggregateStatus,
Object: object.DeepCopy(),
AggregatedStatus: aggregatedStatusItems,
@ -168,8 +202,15 @@ func (i *customResourceInterpreterImpl) AggregateStatus(object *unstructured.Uns
// GetDependencies returns the dependent resources of the given object.
func (i *customResourceInterpreterImpl) GetDependencies(object *unstructured.Unstructured) (dependencies []configv1alpha1.DependentObjectReference, err error) {
klog.V(4).Infof("Begin to get dependencies for object: %v %s/%s.", object.GroupVersionKind(), object.GetNamespace(), object.GetName())
dependencies, hookEnabled, err := i.configurableInterpreter.GetDependencies(object)
if err != nil {
return
}
if hookEnabled {
return
}
dependencies, hookEnabled, err := i.customizedInterpreter.GetDependencies(context.TODO(), &webhook.RequestAttributes{
dependencies, hookEnabled, err = i.customizedInterpreter.GetDependencies(context.TODO(), &webhook.RequestAttributes{
Operation: configv1alpha1.InterpreterOperationInterpretDependency,
Object: object,
})
@ -188,7 +229,14 @@ func (i *customResourceInterpreterImpl) GetDependencies(object *unstructured.Uns
func (i *customResourceInterpreterImpl) ReflectStatus(object *unstructured.Unstructured) (status *runtime.RawExtension, err error) {
klog.V(4).Infof("Begin to grab status for object: %v %s/%s.", object.GroupVersionKind(), object.GetNamespace(), object.GetName())
status, hookEnabled, err := i.customizedInterpreter.ReflectStatus(context.TODO(), &webhook.RequestAttributes{
status, hookEnabled, err := i.configurableInterpreter.ReflectStatus(object)
if err != nil {
return
}
if hookEnabled {
return
}
status, hookEnabled, err = i.customizedInterpreter.ReflectStatus(context.TODO(), &webhook.RequestAttributes{
Operation: configv1alpha1.InterpreterOperationInterpretStatus,
Object: object,
})
@ -207,7 +255,15 @@ func (i *customResourceInterpreterImpl) ReflectStatus(object *unstructured.Unstr
func (i *customResourceInterpreterImpl) InterpretHealth(object *unstructured.Unstructured) (healthy bool, err error) {
klog.V(4).Infof("Begin to check health for object: %v %s/%s.", object.GroupVersionKind(), object.GetNamespace(), object.GetName())
healthy, hookEnabled, err := i.customizedInterpreter.InterpretHealth(context.TODO(), &webhook.RequestAttributes{
healthy, hookEnabled, err := i.configurableInterpreter.InterpretHealth(object)
if err != nil {
return
}
if hookEnabled {
return
}
healthy, hookEnabled, err = i.customizedInterpreter.InterpretHealth(context.TODO(), &webhook.RequestAttributes{
Operation: configv1alpha1.InterpreterOperationInterpretHealth,
Object: object,
})