Files
kubevela/test/e2e-test/initializer_test.go
Jianbo Sun cad21c5138 Fix: refactor workflow and fix some e2e tests (#2272)
* Fix: add e2e plugin test back

* Fix: e2e rollout test and try change port to 37081

* Fix: add rollout plan test back

* Refactor: change the workflow state machine and add workflow succeed state

* Refactor: refine definition controller and fix e2e of app revision

* Refactor: unlock all the normal cases

* Fix: add helm schematic logic back into workflow
2021-09-13 14:17:12 +08:00

502 lines
14 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"
"github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
velatypes "github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/oam/util"
)
var _ = Describe("Initializer Normal tests", func() {
ctx := context.Background()
var namespace string
var ns corev1.Namespace
BeforeEach(func() {
namespace = randomNamespaceName("initializer-e2e-test")
ns = corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}}
Eventually(func() error {
return k8sClient.Create(ctx, &ns)
}, time.Second*3, time.Microsecond*300).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
worker := workerWithNoTemplate.DeepCopy()
worker.Spec.Workload = common.WorkloadTypeDescriptor{
Definition: common.WorkloadGVK{
APIVersion: "apps/v1",
Kind: "Deployment",
},
}
worker.Spec.Schematic.CUE.Template = workerV2Template
worker.SetNamespace(namespace)
Expect(k8sClient.Create(ctx, worker)).Should(Succeed())
})
AfterEach(func() {
By("Clean up resources after a test")
k8sClient.DeleteAllOf(ctx, &v1beta1.Initializer{}, client.InNamespace(namespace))
k8sClient.DeleteAllOf(ctx, &v1beta1.Application{}, client.InNamespace(namespace))
k8sClient.DeleteAllOf(ctx, &v1beta1.ComponentDefinition{}, client.InNamespace(namespace))
k8sClient.DeleteAllOf(ctx, &v1beta1.WorkloadDefinition{}, client.InNamespace(namespace))
k8sClient.DeleteAllOf(ctx, &v1beta1.TraitDefinition{}, client.InNamespace(namespace))
k8sClient.DeleteAllOf(ctx, &v1beta1.DefinitionRevision{}, client.InNamespace(namespace))
By(fmt.Sprintf("Delete the entire namespaceName %s", ns.Name))
Expect(k8sClient.Delete(ctx, &ns, client.PropagationPolicy(metav1.DeletePropagationForeground))).Should(Succeed())
})
It("Test apply initializer without dependsOn", func() {
compName := "env1-comp"
init := &v1beta1.Initializer{
TypeMeta: metav1.TypeMeta{
Kind: "Initializer",
APIVersion: "core.oam.dev/v1beta1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "env1",
Namespace: namespace,
},
Spec: v1beta1.InitializerSpec{
AppTemplate: v1beta1.Application{
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{
{
Name: compName,
Type: "worker",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "busybox",
"cmd": []string{"sleep", "10000"},
}),
},
},
},
},
},
}
By("Create Initializer")
Eventually(func() error {
return k8sClient.Create(ctx, init)
}, 10*time.Second, 500*time.Millisecond).Should(Succeed())
By("Verify the application is created successfully")
app := new(v1beta1.Application)
Eventually(func() error {
return k8sClient.Get(ctx, client.ObjectKey{Name: init.Name, Namespace: namespace}, app)
}, 30*time.Second, 500*time.Millisecond).Should(Succeed())
By("Verify the initializer successfully initialized the environment")
Eventually(func() error {
err := k8sClient.Get(ctx, client.ObjectKey{Name: init.Name, Namespace: namespace}, init)
if err != nil {
return err
}
if init.Status.Phase != v1beta1.InitializerSuccess {
return fmt.Errorf("environment was not successfully initialized")
}
return nil
}, 30*time.Second, 5*time.Second).Should(Succeed())
})
It("Test apply initializer which will create namespace", func() {
randomNs := randomNamespaceName("initializer-createns")
init := &v1beta1.Initializer{
TypeMeta: metav1.TypeMeta{
Kind: "Initializer",
APIVersion: "core.oam.dev/v1beta1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "env4",
Namespace: namespace,
},
Spec: v1beta1.InitializerSpec{
AppTemplate: v1beta1.Application{
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{
{
Name: randomNs,
Type: "raw",
Properties: util.Object2RawExtension(map[string]interface{}{
"apiVersion": "v1",
"kind": "Namespace",
"metadata": map[string]interface{}{
"name": randomNs,
},
}),
},
},
},
},
},
}
By("Create Initializer createNamespaceInit")
Eventually(func() error {
return k8sClient.Create(ctx, init)
}, 10*time.Second, 500*time.Millisecond).Should(Succeed())
By("Verify the application is created successfully")
app := new(v1beta1.Application)
Eventually(func() error {
return k8sClient.Get(ctx, client.ObjectKey{Name: init.Name, Namespace: namespace}, app)
}, 60*time.Second, 2*time.Millisecond).Should(Succeed())
By("Verify the initializer env3 successfully initialized the environment")
Eventually(func() error {
err := k8sClient.Get(ctx, client.ObjectKey{Name: init.Name, Namespace: namespace}, init)
if err != nil {
return err
}
if init.Status.Phase != v1beta1.InitializerSuccess {
return fmt.Errorf("environment was not successfully initialized")
}
return nil
}, 30*time.Second, 5*time.Second).Should(Succeed())
})
Context("Test apply initializer depends on other initializer", func() {
It("initializer depends on existing initializer", func() {
compName := "env2-comp"
init := &v1beta1.Initializer{
TypeMeta: metav1.TypeMeta{
Kind: "Initializer",
APIVersion: "core.oam.dev/v1beta1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "env2",
Namespace: namespace,
},
Spec: v1beta1.InitializerSpec{
AppTemplate: v1beta1.Application{
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{
{
Name: compName,
Type: "worker",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "busybox",
"cmd": []string{"sleep", "10000"},
}),
},
},
},
},
},
}
By("Create Initializer env2")
Eventually(func() error {
return k8sClient.Create(ctx, init)
}, 10*time.Second, 500*time.Millisecond).Should(Succeed())
compName2 := "env3-comp"
init2 := &v1beta1.Initializer{
TypeMeta: metav1.TypeMeta{
Kind: "Initializer",
APIVersion: "core.oam.dev/v1beta1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "env3",
Namespace: namespace,
},
Spec: v1beta1.InitializerSpec{
AppTemplate: v1beta1.Application{
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{
{
Name: compName2,
Type: "worker",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "busybox",
"cmd": []string{"sleep", "10000"},
}),
},
},
},
},
DependsOn: []v1beta1.DependsOn{
{
Ref: corev1.ObjectReference{
APIVersion: "core.oam.dev/v1beta1",
Kind: "Initializer",
Name: "env2",
Namespace: namespace,
},
},
},
},
}
By("Create Initializer env3 which depends on env2")
Eventually(func() error {
return k8sClient.Create(ctx, init2)
}, 10*time.Second, 500*time.Millisecond).Should(Succeed())
By("Verify the application is created successfully")
app2 := new(v1beta1.Application)
Eventually(func() error {
return k8sClient.Get(ctx, client.ObjectKey{Name: init2.Name, Namespace: namespace}, app2)
}, 60*time.Second, 2*time.Millisecond).Should(Succeed())
By("Verify the initializer env3 successfully initialized the environment")
Eventually(func() error {
err := k8sClient.Get(ctx, client.ObjectKey{Name: init2.Name, Namespace: namespace}, init2)
if err != nil {
return err
}
if init2.Status.Phase != v1beta1.InitializerSuccess {
return fmt.Errorf("environment was not successfully initialized")
}
return nil
}, 30*time.Second, 5*time.Second).Should(Succeed())
})
It("initializer depends on not non-built-in initializer not found, should be rejected by webhook", func() {
init := &v1beta1.Initializer{
TypeMeta: metav1.TypeMeta{
Kind: "Initializer",
APIVersion: "core.oam.dev/v1beta1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "env-depends",
Namespace: namespace,
},
Spec: v1beta1.InitializerSpec{
AppTemplate: v1beta1.Application{
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{{
Name: "comp1",
Type: "worker",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "busybox",
"cmd": []string{"sleep", "10000"},
}),
},
},
},
},
DependsOn: []v1beta1.DependsOn{
{
Ref: corev1.ObjectReference{
APIVersion: "core.oam.dev/v1beta1",
Kind: "Initializer",
Name: "non-built-in",
},
},
},
},
}
By("Create Initializer env-depends")
Expect(k8sClient.Create(ctx, init)).Should(HaveOccurred())
})
It("initializer depends on built-in initializer", func() {
initCm := &corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{
Kind: "ConfigMap",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "built-in",
Namespace: velatypes.DefaultKubeVelaNS,
Labels: map[string]string{
"addons.oam.dev/type": "built-in",
},
},
Data: map[string]string{
"initializer": initYaml,
},
}
By("create built-in addon")
Expect(k8sClient.Create(ctx, initCm)).Should(Succeed())
init := &v1beta1.Initializer{
TypeMeta: metav1.TypeMeta{
Kind: "Initializer",
APIVersion: "core.oam.dev/v1beta1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "env-depends-builtin",
Namespace: namespace,
},
Spec: v1beta1.InitializerSpec{
AppTemplate: v1beta1.Application{
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{
{
Name: "comp1",
Type: "worker",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "busybox",
"cmd": []string{"sleep", "10000"},
}),
},
},
},
},
DependsOn: []v1beta1.DependsOn{
{
Ref: corev1.ObjectReference{
APIVersion: "core.oam.dev/v1beta1",
Kind: "Initializer",
Name: "built-in",
Namespace: velatypes.DefaultKubeVelaNS,
},
},
},
},
}
By("Create Initializer env-depends")
Expect(k8sClient.Create(ctx, init)).Should(Succeed())
By("Check built-in Initializer is ready")
buildInInit := new(v1beta1.Initializer)
Eventually(func() error {
err := k8sClient.Get(ctx, client.ObjectKey{Name: "built-in", Namespace: "vela-system"}, buildInInit)
if err != nil {
return err
}
if buildInInit.Status.Phase == v1beta1.InitializerSuccess {
return nil
}
return fmt.Errorf("initializer %s is not ready", buildInInit.Name)
}, 30*time.Second, 500*time.Millisecond).Should(Succeed())
By("Check Initializer env-depends-builtin is ready")
Eventually(func() error {
err := k8sClient.Get(ctx, client.ObjectKey{Name: "env-depends-builtin", Namespace: namespace}, buildInInit)
if err != nil {
return err
}
if buildInInit.Status.Phase == v1beta1.InitializerSuccess {
return nil
}
return errors.New("initializer env-depends-builtin is not ready")
}, 120*time.Second, 500*time.Millisecond).Should(Succeed())
})
It("Deleting initializer depended by other initializer should be rejected by webhook", func() {
initA := &v1beta1.Initializer{
TypeMeta: metav1.TypeMeta{
Kind: "Initializer",
APIVersion: "core.oam.dev/v1beta1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "init-depended",
Namespace: namespace,
},
Spec: v1beta1.InitializerSpec{
AppTemplate: v1beta1.Application{
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{
{
Name: "comp1",
Type: "worker",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "busybox",
"cmd": []string{"sleep", "10000"},
}),
},
},
},
},
},
}
initDependingA := &v1beta1.Initializer{
TypeMeta: metav1.TypeMeta{
Kind: "Initializer",
APIVersion: "core.oam.dev/v1beta1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "init-depending",
Namespace: namespace,
},
Spec: v1beta1.InitializerSpec{
AppTemplate: v1beta1.Application{
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{
{
Name: "",
Type: "worker",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "busybox",
"cmd": []string{"sleep", "10000"},
}),
},
},
},
},
DependsOn: []v1beta1.DependsOn{
{
Ref: corev1.ObjectReference{
APIVersion: "core.oam.dev/v1beta1",
Kind: "Initializer",
Name: "init-depended",
Namespace: namespace,
},
},
},
},
}
By("Create Initializer depended")
Expect(k8sClient.Create(ctx, initA)).NotTo(HaveOccurred())
By("Create Initializer depending")
Expect(k8sClient.Create(ctx, initDependingA)).NotTo(HaveOccurred())
By("Deleting Initializer depended")
Expect(k8sClient.Delete(ctx, initA)).Should(HaveOccurred())
})
})
})
var initYaml = `
apiVersion: core.oam.dev/v1beta1
kind: Initializer
metadata:
annotations:
addons.oam.dev/description: Kruise is a Kubernetes extended suite for application automations
name: built-in
namespace: vela-system
spec:
appTemplate:
spec:
components:
- name: kruise-repo
type: worker
properties:
image: busybox
cmd: ["sleep", "10000"]
`