Files
kubevela/test/e2e-test/containerized_workload_test.go
wyike 74a82e0397 add header-check.sh (#1310)
add ci workflow

update scripts

add missed licence  header for all files
2021-03-26 15:24:19 +08:00

389 lines
13 KiB
Go

/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controllers_test
import (
"context"
"fmt"
"time"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/intstr"
utilpointer "k8s.io/utils/pointer"
"sigs.k8s.io/controller-runtime/pkg/client"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha2"
"github.com/oam-dev/kubevela/pkg/oam"
"github.com/oam-dev/kubevela/pkg/oam/util"
)
var _ = Describe("ContainerizedWorkload", func() {
ctx := context.TODO()
var namespace, fakeLabelKey, fakeAnnotationKey, componentName, workloadInstanceName, imageName string
var replica int32
var ns corev1.Namespace
var wd v1alpha2.WorkloadDefinition
var label map[string]string
var annotations map[string]string
var wl v1alpha2.ContainerizedWorkload
var comp v1alpha2.Component
var appConfig v1alpha2.ApplicationConfiguration
var mts v1alpha2.ManualScalerTrait
BeforeEach(func() {
// init the strings
namespace = "containerized-workload-test"
fakeLabelKey = "workload"
fakeAnnotationKey = "kubectl.kubernetes.io/last-applied-configuration"
componentName = "example-component"
workloadInstanceName = "example-appconfig-workload"
imageName = "wordpress:php7.2"
logf.Log.Info("Start to run a test, clean up previous resources")
ns = corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: namespace,
},
}
// delete the namespace with all its resources
Expect(k8sClient.Delete(ctx, &ns, client.PropagationPolicy(metav1.DeletePropagationForeground))).
Should(SatisfyAny(BeNil(), &util.NotFoundMatcher{}))
logf.Log.Info("make sure all the resources are removed")
objectKey := client.ObjectKey{
Name: namespace,
}
res := &corev1.Namespace{}
Eventually(
// gomega has a bug that can't take nil as the actual input, so has to make it a func
func() error {
return k8sClient.Get(ctx, objectKey, res)
},
time.Second*120, time.Millisecond*500).Should(&util.NotFoundMatcher{})
// recreate it
Eventually(
func() error {
return k8sClient.Create(ctx, &ns)
},
time.Second*3, time.Millisecond*300).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
// create a workload definition
label = map[string]string{fakeLabelKey: "containerized-workload"}
wd = v1alpha2.WorkloadDefinition{
ObjectMeta: metav1.ObjectMeta{
Name: "containerizedworkloads.core.oam.dev",
Namespace: "vela-system",
Labels: label,
},
Spec: v1alpha2.WorkloadDefinitionSpec{
Reference: common.DefinitionReference{
Name: "containerizedworkloads.core.oam.dev",
},
ChildResourceKinds: []common.ChildResourceKind{
{
APIVersion: corev1.SchemeGroupVersion.String(),
Kind: util.KindService,
},
{
APIVersion: appsv1.SchemeGroupVersion.String(),
Kind: util.KindDeployment,
},
},
},
}
// create a workload CR
configFileValue := "testValue"
wl = v1alpha2.ContainerizedWorkload{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Labels: label,
},
Spec: v1alpha2.ContainerizedWorkloadSpec{
Containers: []v1alpha2.Container{
{
Name: "wordpress",
Image: "wordpress:4.6.1-apache",
Ports: []v1alpha2.ContainerPort{
{
Name: "wordpress",
Port: 80,
},
},
ConfigFiles: []v1alpha2.ContainerConfigFile{
{
Path: "/test/path/config",
Value: &configFileValue,
},
},
},
},
},
}
// reflect workload gvk from scheme
gvks, _, _ := scheme.ObjectKinds(&wl)
wl.APIVersion = gvks[0].GroupVersion().String()
wl.Kind = gvks[0].Kind
// Create a component definition
comp = v1alpha2.Component{
ObjectMeta: metav1.ObjectMeta{
Name: componentName,
Namespace: namespace,
Labels: label,
},
Spec: v1alpha2.ComponentSpec{
Workload: runtime.RawExtension{
Object: &wl,
},
Parameters: []v1alpha2.ComponentParameter{
{
Name: "instance-name",
Required: utilpointer.BoolPtr(true),
FieldPaths: []string{"metadata.name"},
},
{
Name: "image",
Required: utilpointer.BoolPtr(false),
FieldPaths: []string{"spec.containers[0].image"},
},
},
},
}
// Create a manualscaler trait CR
replica = 3
mts = v1alpha2.ManualScalerTrait{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Name: "sample-manualscaler-trait",
Labels: label,
},
Spec: v1alpha2.ManualScalerTraitSpec{
ReplicaCount: replica,
},
}
// reflect trait gvk from scheme
gvks, _, _ = scheme.ObjectKinds(&mts)
mts.APIVersion = gvks[0].GroupVersion().String()
mts.Kind = gvks[0].Kind
// Create application configuration
workloadInstanceName := "example-appconfig-workload"
imageName := "wordpress:php7.2"
annotations = map[string]string{fakeAnnotationKey: "fake-annotation-key-item"}
appConfig = v1alpha2.ApplicationConfiguration{
ObjectMeta: metav1.ObjectMeta{
Name: "example-appconfig",
Namespace: namespace,
Labels: label,
Annotations: annotations,
},
Spec: v1alpha2.ApplicationConfigurationSpec{
Components: []v1alpha2.ApplicationConfigurationComponent{
{
ComponentName: componentName,
ParameterValues: []v1alpha2.ComponentParameterValue{
{
Name: "instance-name",
Value: intstr.IntOrString{StrVal: workloadInstanceName, Type: intstr.String},
},
{
Name: "image",
Value: intstr.IntOrString{StrVal: imageName, Type: intstr.String},
},
},
Traits: []v1alpha2.ComponentTrait{
{
Trait: runtime.RawExtension{
Object: &mts,
},
},
},
},
},
},
}
})
AfterEach(func() {
logf.Log.Info("Clean up resources")
// delete the namespace with all its resources
Expect(k8sClient.Delete(ctx, &ns, client.PropagationPolicy(metav1.DeletePropagationForeground))).Should(BeNil())
})
It("apply an application config", func() {
logf.Log.Info("Creating workload definition")
// For some reason, WorkloadDefinition is created as a Cluster scope object
Expect(k8sClient.Create(ctx, &wd)).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
logf.Log.Info("Creating component", "Name", comp.Name, "Namespace", comp.Namespace)
Expect(k8sClient.Create(ctx, &comp)).Should(BeNil())
time.Sleep(time.Second) //wait 1s to let component create successfully
logf.Log.Info("Creating application config", "Name", appConfig.Name, "Namespace", appConfig.Namespace)
Expect(k8sClient.Create(ctx, &appConfig)).Should(BeNil())
// Verification
By("Checking containerizedworkload is created")
cw := &v1alpha2.ContainerizedWorkload{}
Eventually(func() error {
return k8sClient.Get(ctx, client.ObjectKey{Name: workloadInstanceName, Namespace: namespace}, cw)
}, time.Second*15, time.Millisecond*500).Should(BeNil())
By("Checking ManuelScalerTrait is created")
Eventually(func() error {
return k8sClient.Get(ctx, client.ObjectKey{Name: mts.Name, Namespace: namespace}, &mts)
}, time.Second*15, time.Millisecond*500).Should(BeNil())
By("Checking labels")
cwLabels := cw.GetLabels()
Expect(cwLabels).Should(SatisfyAll(
HaveKey(fakeLabelKey), // propogated from appConfig
HaveKey(oam.LabelAppComponent),
HaveKey(oam.LabelAppComponentRevision),
HaveKey(oam.LabelAppName),
HaveKey(oam.LabelOAMResourceType)))
cwLabels = mts.GetLabels()
Expect(cwLabels).Should(SatisfyAll(
HaveKey(fakeLabelKey), // propogated from appConfig
HaveKey(oam.LabelAppComponent),
HaveKey(oam.LabelAppComponentRevision),
HaveKey(oam.LabelAppName),
HaveKey(oam.LabelOAMResourceType)))
By("Checking ConfigMap is created")
cmObjectKey := client.ObjectKey{
Namespace: namespace,
Name: fmt.Sprintf("%s-%s-3972676475", workloadInstanceName, "wordpress"),
}
configMap := &corev1.ConfigMap{}
logf.Log.Info("Checking on configMap", "Key", cmObjectKey)
Eventually(
func() error {
return k8sClient.Get(ctx, cmObjectKey, configMap)
},
time.Second*15, time.Millisecond*500).Should(BeNil())
By("Checking deployment is created")
objectKey := client.ObjectKey{
Name: workloadInstanceName,
Namespace: namespace,
}
deploy := &appsv1.Deployment{}
logf.Log.Info("Checking on deployment", "Key", objectKey)
Eventually(
func() error {
return k8sClient.Get(ctx, objectKey, deploy)
},
time.Second*15, time.Millisecond*500).Should(BeNil())
By("Verify that the parameter substitute works")
Expect(deploy.Spec.Template.Spec.Containers[0].Image).Should(Equal(imageName))
// Verification
By("Checking service is created")
service := &corev1.Service{}
logf.Log.Info("Checking on service", "Key", objectKey)
Eventually(
func() error {
return k8sClient.Get(ctx, objectKey, service)
},
time.Second*15, time.Millisecond*500).Should(BeNil())
By("Verify deployment scaled according to the manualScaler trait")
Eventually(
func() int32 {
k8sClient.Get(ctx, objectKey, deploy)
return deploy.Status.Replicas
},
time.Second*60, time.Second*5).Should(BeEquivalentTo(replica))
Expect(*deploy.Spec.Replicas).Should(BeEquivalentTo(replica))
By("Verify pod annotations should not contain kubectl.kubernetes.io/last-applied-configuration")
Eventually(
func() bool {
k8sClient.Get(ctx, objectKey, deploy)
annotations := deploy.Spec.Template.Annotations
if _, ok := annotations[fakeAnnotationKey]; ok {
return false
}
return true
},
time.Second*15, time.Millisecond*500).Should(BeTrue())
})
It("checking appConfig status changed outside of the controller loop is preserved", func() {
logf.Log.Info("Creating workload definition")
// For some reason, WorkloadDefinition is created as a Cluster scope object
Expect(k8sClient.Create(ctx, &wd)).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
logf.Log.Info("Creating component", "Name", comp.Name, "Namespace", comp.Namespace)
Expect(k8sClient.Create(ctx, &comp)).Should(BeNil())
logf.Log.Info("Creating application config", "Name", appConfig.Name, "Namespace", appConfig.Namespace)
Expect(k8sClient.Create(ctx, &appConfig)).Should(BeNil())
By("Verify deployment scaled according to the manualScaler trait")
objectKey := client.ObjectKey{
Name: workloadInstanceName,
Namespace: namespace,
}
deploy := &appsv1.Deployment{}
Eventually(
func() int32 {
k8sClient.Get(ctx, objectKey, deploy)
return deploy.Status.Replicas
},
time.Second*60, time.Second*5).Should(BeEquivalentTo(replica))
Expect(*deploy.Spec.Replicas).Should(BeEquivalentTo(replica))
// Verify that the status is set
By("Add applicationConfiguration status")
var appConfigWithStatus v1alpha2.ApplicationConfiguration
appKey := client.ObjectKey{
Name: appConfig.Name,
Namespace: namespace,
}
Expect(k8sClient.Get(ctx, appKey, &appConfigWithStatus)).ShouldNot(HaveOccurred())
logf.Log.Info("get appConfig status", "workload status", appConfigWithStatus.Status.Workloads[0])
appConfigWithStatus.Status.Workloads[0].Status = "ready"
appConfigWithStatus.Status.Workloads[0].Traits[0].Status = "running"
Expect(k8sClient.Status().Update(ctx, &appConfigWithStatus)).ShouldNot(HaveOccurred())
By("Checking appConfig status is updated")
appConfigWithStatus = v1alpha2.ApplicationConfiguration{}
Expect(k8sClient.Get(ctx, appKey, &appConfigWithStatus)).ShouldNot(HaveOccurred())
Expect(appConfigWithStatus.Status.Workloads[0].Status).Should(Equal("ready"))
Expect(appConfigWithStatus.Status.Workloads[0].Traits[0].Status).Should(BeEquivalentTo("running"))
By("Checking appConfig status is updated again")
appConfigWithStatus = v1alpha2.ApplicationConfiguration{}
Expect(k8sClient.Get(ctx, appKey, &appConfigWithStatus)).ShouldNot(HaveOccurred())
Expect(appConfigWithStatus.Status.Workloads[0].Status).Should(Equal("ready"))
Expect(appConfigWithStatus.Status.Workloads[0].Traits[0].Status).Should(BeEquivalentTo("running"))
By("change the appConfig, scale down the replicate")
mts.Spec.ReplicaCount = 1
appConfigWithStatus.Spec.Components[0].Traits[0].Trait.Raw = util.JSONMarshal(mts)
Expect(k8sClient.Update(ctx, &appConfigWithStatus)).ShouldNot(HaveOccurred())
By("Verify deployment scaled according to the manualScaler trait")
Eventually(
func() int32 {
k8sClient.Get(ctx, objectKey, deploy)
return deploy.Status.Replicas
},
time.Second*120, time.Second*5).Should(BeEquivalentTo(1))
By("Checking appConfig status is preserved through reconcile")
appConfigWithStatus = v1alpha2.ApplicationConfiguration{}
Expect(k8sClient.Get(ctx, appKey, &appConfigWithStatus)).ShouldNot(HaveOccurred())
Expect(appConfigWithStatus.Status.Workloads[0].Status).Should(Equal("ready"))
Expect(appConfigWithStatus.Status.Workloads[0].Traits[0].Status).Should(BeEquivalentTo("running"))
})
})