add e2e for resource interpreter customization

Signed-off-by: changzhen <changzhen5@huawei.com>
This commit is contained in:
changzhen 2022-11-18 09:53:37 +08:00
parent 594ad9f44b
commit df81ff9509
4 changed files with 206 additions and 0 deletions

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" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"reflect"
"time" "time"
"github.com/onsi/ginkgo/v2" "github.com/onsi/ginkgo/v2"
"github.com/onsi/gomega" "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" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/rand" "k8s.io/apimachinery/pkg/util/rand"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
@ -15,6 +19,7 @@ import (
"k8s.io/utils/pointer" "k8s.io/utils/pointer"
workloadv1alpha1 "github.com/karmada-io/karmada/examples/customresourceinterpreter/apis/workload/v1alpha1" 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" policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1"
workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2" workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2"
"github.com/karmada-io/karmada/pkg/util/names" "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{{ Containers: []corev1.Container{{
Name: "nginx", Name: "nginx",
Image: "nginx:1.19.0", Image: "nginx:1.19.0",
Resources: corev1.ResourceRequirements{
Limits: map[corev1.ResourceName]resource.Quantity{
corev1.ResourceCPU: resource.MustParse("100m"),
},
},
}}, }},
}, },
}, },