Merge pull request #2829 from XiShanYongYe-Chang/add-e2e-for-resourceInterpreterCustomization

[E2E] add test case for resource interpreter customization
This commit is contained in:
karmada-bot 2022-11-19 19:25:29 +08:00 committed by GitHub
commit 8aa58ec6cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 232 additions and 20 deletions

View File

@ -35,6 +35,7 @@ func (c *ConfigurableInterpreter) HookEnabled(kind schema.GroupVersionKind, oper
// 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) {
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)
if !enabled {
return
@ -46,6 +47,7 @@ func (c *ConfigurableInterpreter) GetReplicas(object *unstructured.Unstructured)
// ReviseReplica revises the replica of the given object.
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())
luaScript, enabled := c.getInterpreter(object.GroupVersionKind(), configv1alpha1.InterpreterOperationReviseReplica)
if !enabled {
return
@ -57,6 +59,7 @@ func (c *ConfigurableInterpreter) ReviseReplica(object *unstructured.Unstructure
// 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) {
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)
if !enabled {
return
@ -68,6 +71,7 @@ func (c *ConfigurableInterpreter) Retain(desired *unstructured.Unstructured, obs
// 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) {
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)
if !enabled {
return
@ -79,6 +83,7 @@ func (c *ConfigurableInterpreter) AggregateStatus(object *unstructured.Unstructu
// GetDependencies returns the dependent resources of the given object.
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())
luaScript, enabled := c.getInterpreter(object.GroupVersionKind(), configv1alpha1.InterpreterOperationInterpretDependency)
if !enabled {
return
@ -90,6 +95,7 @@ func (c *ConfigurableInterpreter) GetDependencies(object *unstructured.Unstructu
// ReflectStatus returns the status of the object.
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())
luaScript, enabled := c.getInterpreter(object.GroupVersionKind(), configv1alpha1.InterpreterOperationInterpretStatus)
if !enabled {
return
@ -101,6 +107,7 @@ func (c *ConfigurableInterpreter) ReflectStatus(object *unstructured.Unstructure
// InterpretHealth returns the health state of the object.
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())
luaScript, enabled := c.getInterpreter(object.GroupVersionKind(), configv1alpha1.InterpreterOperationInterpretHealth)
if !enabled {
return

View File

@ -46,7 +46,7 @@ func (vm VM) GetReplicas(obj *unstructured.Unstructured, script string) (replica
f := l.GetGlobal("GetReplicas")
if f.Type() == lua.LTNil {
return 0, nil, fmt.Errorf("can't get function ReviseReplica pleace check the function name")
return 0, nil, fmt.Errorf("can't get function GetReplicas, please check the lua script")
}
args := make([]lua.LValue, 1)
@ -107,7 +107,7 @@ func (vm VM) ReviseReplica(object *unstructured.Unstructured, replica int64, scr
}
reviseReplicaLuaFunc := l.GetGlobal("ReviseReplica")
if reviseReplicaLuaFunc.Type() == lua.LTNil {
return nil, fmt.Errorf("can't get function ReviseReplica pleace check the function name")
return nil, fmt.Errorf("can't get function ReviseReplica, please check the lua script")
}
args := make([]lua.LValue, 2)
@ -183,7 +183,7 @@ func (vm VM) Retain(desired *unstructured.Unstructured, observed *unstructured.U
}
retainLuaFunc := l.GetGlobal("Retain")
if retainLuaFunc.Type() == lua.LTNil {
return nil, fmt.Errorf("can't get function Retatin pleace check the function ")
return nil, fmt.Errorf("can't get function Retatin, please check the lua script")
}
args := make([]lua.LValue, 2)
@ -237,7 +237,7 @@ func (vm VM) AggregateStatus(object *unstructured.Unstructured, items []workv1al
f := l.GetGlobal("AggregateStatus")
if f.Type() == lua.LTNil {
return nil, fmt.Errorf("can't get function AggregateStatus pleace check the function ")
return nil, fmt.Errorf("can't get function AggregateStatus, please check the lua script")
}
args := make([]lua.LValue, 2)
args[0], err = decodeValue(l, object.Object)
@ -289,7 +289,7 @@ func (vm VM) InterpretHealth(object *unstructured.Unstructured, script string) (
}
f := l.GetGlobal("InterpretHealth")
if f.Type() == lua.LTNil {
return false, fmt.Errorf("can't get function InterpretHealth pleace check the function ")
return false, fmt.Errorf("can't get function InterpretHealth, please check the lua script")
}
args := make([]lua.LValue, 1)
@ -335,7 +335,7 @@ func (vm VM) ReflectStatus(object *unstructured.Unstructured, script string) (st
}
f := l.GetGlobal("ReflectStatus")
if f.Type() == lua.LTNil {
return nil, fmt.Errorf("can't get function ReflectStatus pleace check the function ")
return nil, fmt.Errorf("can't get function ReflectStatus, please check the lua script")
}
args := make([]lua.LValue, 1)
@ -382,7 +382,7 @@ func (vm VM) GetDependencies(object *unstructured.Unstructured, script string) (
}
f := l.GetGlobal("GetDependencies")
if f.Type() == lua.LTNil {
return nil, fmt.Errorf("can't get function Retatin pleace check the function ")
return nil, fmt.Errorf("can't get function GetDependencies, please check the lua script")
}
args := make([]lua.LValue, 1)

View File

@ -71,6 +71,8 @@ func (e *CustomizedInterpreter) HookEnabled(objGVK schema.GroupVersionKind, oper
// GetReplicas returns the desired replicas of the object as well as the requirements of each replica.
// return matched value to indicate whether there is a matching hook.
func (e *CustomizedInterpreter) GetReplicas(ctx context.Context, attributes *webhook.RequestAttributes) (replica int32, requires *workv1alpha2.ReplicaRequirements, matched bool, err error) {
klog.V(4).Infof("Get replicas for object: %v %s/%s with webhook interpreter.",
attributes.Object.GroupVersionKind(), attributes.Object.GetNamespace(), attributes.Object.GetName())
var response *webhook.ResponseAttributes
response, matched, err = e.interpret(ctx, attributes)
if err != nil {

View File

@ -75,6 +75,7 @@ func (e *DefaultInterpreter) HookEnabled(kind schema.GroupVersionKind, operation
// GetReplicas returns the desired replicas of the object as well as the requirements of each replica.
func (e *DefaultInterpreter) GetReplicas(object *unstructured.Unstructured) (int32, *workv1alpha2.ReplicaRequirements, error) {
klog.V(4).Infof("Get replicas for object: %v %s/%s with build-in interpreter.", object.GroupVersionKind(), object.GetNamespace(), object.GetName())
handler, exist := e.replicaHandlers[object.GroupVersionKind()]
if !exist {
return 0, &workv1alpha2.ReplicaRequirements{}, fmt.Errorf("default %s interpreter for %q not found", configv1alpha1.InterpreterOperationInterpretReplica, object.GroupVersionKind())
@ -84,6 +85,7 @@ func (e *DefaultInterpreter) GetReplicas(object *unstructured.Unstructured) (int
// ReviseReplica revises the replica of the given object.
func (e *DefaultInterpreter) ReviseReplica(object *unstructured.Unstructured, replica int64) (*unstructured.Unstructured, error) {
klog.V(4).Infof("Revise replicas for object: %v %s/%s with build-in interpreter.", object.GroupVersionKind(), object.GetNamespace(), object.GetName())
handler, exist := e.reviseReplicaHandlers[object.GroupVersionKind()]
if !exist {
return nil, fmt.Errorf("default %s interpreter for %q not found", configv1alpha1.InterpreterOperationReviseReplica, object.GroupVersionKind())
@ -93,6 +95,7 @@ func (e *DefaultInterpreter) ReviseReplica(object *unstructured.Unstructured, re
// Retain returns the objects that based on the "desired" object but with values retained from the "observed" object.
func (e *DefaultInterpreter) Retain(desired *unstructured.Unstructured, observed *unstructured.Unstructured) (retained *unstructured.Unstructured, err error) {
klog.V(4).Infof("Retain object: %v %s/%s with build-in interpreter.", desired.GroupVersionKind(), desired.GetNamespace(), desired.GetName())
handler, exist := e.retentionHandlers[desired.GroupVersionKind()]
if !exist {
return nil, fmt.Errorf("default %s interpreter for %q not found", configv1alpha1.InterpreterOperationRetain, desired.GroupVersionKind())
@ -102,6 +105,7 @@ func (e *DefaultInterpreter) Retain(desired *unstructured.Unstructured, observed
// AggregateStatus returns the objects that based on the 'object' but with status aggregated.
func (e *DefaultInterpreter) AggregateStatus(object *unstructured.Unstructured, aggregatedStatusItems []workv1alpha2.AggregatedStatusItem) (*unstructured.Unstructured, error) {
klog.V(4).Infof("Aggregate status of object: %v %s/%s with build-in interpreter.", object.GroupVersionKind(), object.GetNamespace(), object.GetName())
handler, exist := e.aggregateStatusHandlers[object.GroupVersionKind()]
if !exist {
return nil, fmt.Errorf("default %s interpreter for %q not found", configv1alpha1.InterpreterOperationAggregateStatus, object.GroupVersionKind())
@ -111,6 +115,7 @@ func (e *DefaultInterpreter) AggregateStatus(object *unstructured.Unstructured,
// GetDependencies returns the dependent resources of the given object.
func (e *DefaultInterpreter) GetDependencies(object *unstructured.Unstructured) (dependencies []configv1alpha1.DependentObjectReference, err error) {
klog.V(4).Infof("Get dependencies of object: %v %s/%s with build-in interpreter.", object.GroupVersionKind(), object.GetNamespace(), object.GetName())
handler, exist := e.dependenciesHandlers[object.GroupVersionKind()]
if !exist {
return dependencies, fmt.Errorf("default interpreter for operation %s not found", configv1alpha1.InterpreterOperationInterpretDependency)
@ -120,6 +125,7 @@ func (e *DefaultInterpreter) GetDependencies(object *unstructured.Unstructured)
// ReflectStatus returns the status of the object.
func (e *DefaultInterpreter) ReflectStatus(object *unstructured.Unstructured) (status *runtime.RawExtension, err error) {
klog.V(4).Infof("Reflect status of object: %v %s/%s with build-in interpreter.", object.GroupVersionKind(), object.GetNamespace(), object.GetName())
handler, exist := e.reflectStatusHandlers[object.GroupVersionKind()]
if exist {
return handler(object)
@ -131,6 +137,7 @@ func (e *DefaultInterpreter) ReflectStatus(object *unstructured.Unstructured) (s
// InterpretHealth returns the health state of the object.
func (e *DefaultInterpreter) InterpretHealth(object *unstructured.Unstructured) (bool, error) {
klog.V(4).Infof("Get health status of object: %v %s/%s with build-in interpreter.", object.GroupVersionKind(), object.GetNamespace(), object.GetName())
handler, exist := e.healthHandlers[object.GroupVersionKind()]
if exist {
return handler(object)

View File

@ -91,8 +91,6 @@ func (i *customResourceInterpreterImpl) HookEnabled(objGVK schema.GroupVersionKi
// GetReplicas returns the desired replicas of the object as well as the requirements of each replica.
func (i *customResourceInterpreterImpl) GetReplicas(object *unstructured.Unstructured) (replica int32, requires *workv1alpha2.ReplicaRequirements, err error) {
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)
@ -120,8 +118,6 @@ func (i *customResourceInterpreterImpl) GetReplicas(object *unstructured.Unstruc
// ReviseReplica revises the replica of the given object.
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.configurableInterpreter.ReviseReplica(object, replica)
if err != nil {
return nil, err
@ -130,6 +126,7 @@ func (i *customResourceInterpreterImpl) ReviseReplica(object *unstructured.Unstr
return obj, nil
}
klog.V(4).Infof("Revise replicas for object: %v %s/%s with webhook interpreter.", object.GroupVersionKind(), object.GetNamespace(), object.GetName())
obj, hookEnabled, err = i.customizedInterpreter.Patch(context.TODO(), &webhook.RequestAttributes{
Operation: configv1alpha1.InterpreterOperationReviseReplica,
Object: object,
@ -147,8 +144,6 @@ func (i *customResourceInterpreterImpl) ReviseReplica(object *unstructured.Unstr
// Retain returns the objects that based on the "desired" object but with values retained from the "observed" object.
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.configurableInterpreter.Retain(desired, observed)
if err != nil {
return nil, err
@ -157,6 +152,7 @@ func (i *customResourceInterpreterImpl) Retain(desired *unstructured.Unstructure
return obj, nil
}
klog.V(4).Infof("Retain object: %v %s/%s with webhook interpreter.", desired.GroupVersionKind(), desired.GetNamespace(), desired.GetName())
obj, hookEnabled, err = i.customizedInterpreter.Patch(context.TODO(), &webhook.RequestAttributes{
Operation: configv1alpha1.InterpreterOperationRetain,
Object: desired,
@ -174,8 +170,6 @@ func (i *customResourceInterpreterImpl) Retain(desired *unstructured.Unstructure
// AggregateStatus returns the objects that based on the 'object' but with status aggregated.
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.configurableInterpreter.AggregateStatus(object, aggregatedStatusItems)
if err != nil {
return nil, err
@ -184,6 +178,7 @@ func (i *customResourceInterpreterImpl) AggregateStatus(object *unstructured.Uns
return obj, nil
}
klog.V(4).Infof("Aggregate status of object: %v %s/%s with webhook interpreter.", object.GroupVersionKind(), object.GetNamespace(), object.GetName())
obj, hookEnabled, err = i.customizedInterpreter.Patch(context.TODO(), &webhook.RequestAttributes{
Operation: configv1alpha1.InterpreterOperationAggregateStatus,
Object: object.DeepCopy(),
@ -201,7 +196,6 @@ 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
@ -227,8 +221,6 @@ func (i *customResourceInterpreterImpl) GetDependencies(object *unstructured.Uns
// ReflectStatus returns the status of the object.
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.configurableInterpreter.ReflectStatus(object)
if err != nil {
return
@ -253,8 +245,6 @@ func (i *customResourceInterpreterImpl) ReflectStatus(object *unstructured.Unstr
// InterpretHealth returns the health state of the object.
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.configurableInterpreter.InterpretHealth(object)
if err != nil {
return

View File

@ -0,0 +1,29 @@
package framework
import (
"context"
"fmt"
"github.com/onsi/ginkgo/v2"
"github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
configv1alpha1 "github.com/karmada-io/karmada/pkg/apis/config/v1alpha1"
karmada "github.com/karmada-io/karmada/pkg/generated/clientset/versioned"
)
// CreateResourceInterpreterCustomization creates ResourceInterpreterCustomization with karmada client.
func CreateResourceInterpreterCustomization(client karmada.Interface, customization *configv1alpha1.ResourceInterpreterCustomization) {
ginkgo.By(fmt.Sprintf("Creating ResourceInterpreterCustomization(%s)", customization.Name), func() {
_, err := client.ConfigV1alpha1().ResourceInterpreterCustomizations().Create(context.TODO(), customization, metav1.CreateOptions{})
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
})
}
// DeleteResourceInterpreterCustomization deletes ResourceInterpreterCustomization with karmada client.
func DeleteResourceInterpreterCustomization(client karmada.Interface, name string) {
ginkgo.By(fmt.Sprintf("Deleting ResourceInterpreterCustomization(%s)", name), func() {
err := client.ConfigV1alpha1().ResourceInterpreterCustomizations().Delete(context.TODO(), name, metav1.DeleteOptions{})
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
})
}

View File

@ -4,10 +4,14 @@ import (
"context"
"encoding/json"
"fmt"
"reflect"
"time"
"github.com/onsi/ginkgo/v2"
"github.com/onsi/gomega"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/rand"
"k8s.io/apimachinery/pkg/util/wait"
@ -15,6 +19,7 @@ import (
"k8s.io/utils/pointer"
workloadv1alpha1 "github.com/karmada-io/karmada/examples/customresourceinterpreter/apis/workload/v1alpha1"
configv1alpha1 "github.com/karmada-io/karmada/pkg/apis/config/v1alpha1"
policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1"
workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2"
"github.com/karmada-io/karmada/pkg/util/names"
@ -272,3 +277,149 @@ var _ = ginkgo.Describe("Resource interpreter webhook testing", func() {
})
})
})
var _ = framework.SerialDescribe("Resource interpreter customization testing", func() {
var customization *configv1alpha1.ResourceInterpreterCustomization
var deployment *appsv1.Deployment
var policy *policyv1alpha1.PropagationPolicy
// We only need to test any one of the member clusters.
var targetCluster string
ginkgo.BeforeEach(func() {
targetCluster = framework.ClusterNames()[rand.Intn(len(framework.ClusterNames()))]
deployment = testhelper.NewDeployment(testNamespace, deploymentNamePrefix+rand.String(RandomStrLength))
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},
},
})
})
ginkgo.JustBeforeEach(func() {
framework.CreateResourceInterpreterCustomization(karmadaClient, customization)
// Wait for resource interpreter informer synced.
time.Sleep(time.Second)
framework.CreatePropagationPolicy(karmadaClient, policy)
framework.CreateDeployment(kubeClient, deployment)
ginkgo.DeferCleanup(func() {
framework.RemoveDeployment(kubeClient, deployment.Namespace, deployment.Name)
framework.RemovePropagationPolicy(karmadaClient, policy.Namespace, policy.Name)
framework.DeleteResourceInterpreterCustomization(karmadaClient, customization.Name)
})
})
ginkgo.Context("InterpreterOperation InterpretReplica testing", func() {
ginkgo.BeforeEach(func() {
customization = testhelper.NewResourceInterpreterCustomization(
"interpreter-customization"+rand.String(RandomStrLength),
configv1alpha1.CustomizationTarget{
APIVersion: "apps/v1",
Kind: "Deployment",
},
configv1alpha1.CustomizationRules{
ReplicaResource: &configv1alpha1.ReplicaResourceRequirement{
LuaScript: `
function GetReplicas(desiredObj)
replica = desiredObj.spec.replicas + 1
requirement = {}
requirement.nodeClaim = {}
requirement.nodeClaim.nodeSelector = desiredObj.spec.template.spec.nodeSelector
requirement.nodeClaim.tolerations = desiredObj.spec.template.spec.tolerations
requirement.resourceRequest = desiredObj.spec.template.spec.containers[1].resources.limits
return replica, requirement
end`,
},
})
})
ginkgo.It("InterpretReplica testing", func() {
ginkgo.By("check if workload's replica is interpreted", func() {
resourceBindingName := names.GenerateBindingName(deployment.Kind, deployment.Name)
// Just for the current test case to distinguish the build-in logic.
expectedReplicas := *deployment.Spec.Replicas + 1
expectedReplicaRequirements := &workv1alpha2.ReplicaRequirements{
ResourceRequest: map[corev1.ResourceName]resource.Quantity{
corev1.ResourceCPU: resource.MustParse("100m"),
}}
gomega.Eventually(func(g gomega.Gomega) (bool, error) {
resourceBinding, err := karmadaClient.WorkV1alpha2().ResourceBindings(deployment.Namespace).Get(context.TODO(), resourceBindingName, metav1.GetOptions{})
g.Expect(err).NotTo(gomega.HaveOccurred())
klog.Infof(fmt.Sprintf("ResourceBinding(%s/%s)'s replicas is %d, expected: %d.",
resourceBinding.Namespace, resourceBinding.Name, resourceBinding.Spec.Replicas, expectedReplicas))
if resourceBinding.Spec.Replicas != expectedReplicas {
return false, nil
}
klog.Infof(fmt.Sprintf("ResourceBinding(%s/%s)'s replicaRequirements is %+v, expected: %+v.",
resourceBinding.Namespace, resourceBinding.Name, resourceBinding.Spec.ReplicaRequirements, expectedReplicaRequirements))
return reflect.DeepEqual(resourceBinding.Spec.ReplicaRequirements, expectedReplicaRequirements), nil
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
})
})
})
ginkgo.Context("InterpreterOperation ReviseReplica testing", func() {
ginkgo.BeforeEach(func() {
customization = testhelper.NewResourceInterpreterCustomization(
"interpreter-customization"+rand.String(RandomStrLength),
configv1alpha1.CustomizationTarget{
APIVersion: "apps/v1",
Kind: "Deployment",
},
configv1alpha1.CustomizationRules{
ReplicaRevision: &configv1alpha1.ReplicaRevision{
LuaScript: `
function ReviseReplica(obj, desiredReplica)
obj.spec.replicas = desiredReplica + 1
return obj
end`,
},
})
})
ginkgo.BeforeEach(func() {
sumWeight := 0
staticWeightLists := make([]policyv1alpha1.StaticClusterWeight, 0)
for index, clusterName := range framework.ClusterNames() {
staticWeightList := policyv1alpha1.StaticClusterWeight{
TargetCluster: policyv1alpha1.ClusterAffinity{
ClusterNames: []string{clusterName},
},
Weight: int64(index + 1),
}
sumWeight += index + 1
staticWeightLists = append(staticWeightLists, staticWeightList)
}
deployment.Spec.Replicas = pointer.Int32Ptr(int32(sumWeight))
policy.Spec.Placement = policyv1alpha1.Placement{
ClusterAffinity: &policyv1alpha1.ClusterAffinity{
ClusterNames: framework.ClusterNames(),
},
ReplicaScheduling: &policyv1alpha1.ReplicaSchedulingStrategy{
ReplicaDivisionPreference: policyv1alpha1.ReplicaDivisionPreferenceWeighted,
ReplicaSchedulingType: policyv1alpha1.ReplicaSchedulingTypeDivided,
WeightPreference: &policyv1alpha1.ClusterPreferences{
StaticWeightList: staticWeightLists,
},
},
}
})
ginkgo.It("ReviseReplica testing", func() {
for index, clusterName := range framework.ClusterNames() {
framework.WaitDeploymentPresentOnClusterFitWith(clusterName, deployment.Namespace, deployment.Name, func(deployment *appsv1.Deployment) bool {
return *deployment.Spec.Replicas == int32(index+1)+1
})
}
})
})
})

21
test/helper/config.go Normal file
View File

@ -0,0 +1,21 @@
package helper
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
configv1alpha1 "github.com/karmada-io/karmada/pkg/apis/config/v1alpha1"
)
// NewResourceInterpreterCustomization will build a ResourceInterpreterCustomization object.
func NewResourceInterpreterCustomization(
name string,
target configv1alpha1.CustomizationTarget,
rules configv1alpha1.CustomizationRules) *configv1alpha1.ResourceInterpreterCustomization {
return &configv1alpha1.ResourceInterpreterCustomization{
ObjectMeta: metav1.ObjectMeta{Name: name},
Spec: configv1alpha1.ResourceInterpreterCustomizationSpec{
Target: target,
Customizations: rules,
},
}
}

View File

@ -56,6 +56,11 @@ func NewDeployment(namespace string, name string) *appsv1.Deployment {
Containers: []corev1.Container{{
Name: "nginx",
Image: "nginx:1.19.0",
Resources: corev1.ResourceRequirements{
Limits: map[corev1.ResourceName]resource.Quantity{
corev1.ResourceCPU: resource.MustParse("100m"),
},
},
}},
},
},