github.com/oam-dev/kubevela@v1.9.11/test/e2e-test/definition_test.go (about)

     1  /*
     2   Copyright 2021. The KubeVela Authors.
     3  
     4   Licensed under the Apache License, Version 2.0 (the "License");
     5   you may not use this file except in compliance with the License.
     6   You may obtain a copy of the License at
     7  
     8       http://www.apache.org/licenses/LICENSE-2.0
     9  
    10   Unless required by applicable law or agreed to in writing, software
    11   distributed under the License is distributed on an "AS IS" BASIS,
    12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   See the License for the specific language governing permissions and
    14   limitations under the License.
    15  */
    16  
    17  package controllers_test
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"path/filepath"
    23  	"runtime"
    24  	"strings"
    25  	"time"
    26  
    27  	testdef "github.com/kubevela/pkg/util/test/definition"
    28  	. "github.com/onsi/ginkgo/v2"
    29  	. "github.com/onsi/gomega"
    30  	corev1 "k8s.io/api/core/v1"
    31  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    32  	"sigs.k8s.io/controller-runtime/pkg/client"
    33  
    34  	"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
    35  	"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
    36  	"github.com/oam-dev/kubevela/apis/types"
    37  	"github.com/oam-dev/kubevela/pkg/oam"
    38  	"github.com/oam-dev/kubevela/pkg/oam/util"
    39  	utilcommon "github.com/oam-dev/kubevela/pkg/utils/common"
    40  )
    41  
    42  var _ = Describe("ComponentDefinition Normal tests", func() {
    43  	ctx := context.Background()
    44  
    45  	var namespace string
    46  	var ns corev1.Namespace
    47  
    48  	BeforeEach(func() {
    49  		namespace = randomNamespaceName("def-e2e-test")
    50  		ns = corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}}
    51  
    52  		Eventually(func() error {
    53  			return k8sClient.Create(ctx, &ns)
    54  		}, time.Second*3, time.Microsecond*300).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
    55  	})
    56  
    57  	AfterEach(func() {
    58  		By("Clean up resources after a test")
    59  		k8sClient.DeleteAllOf(ctx, &v1beta1.ComponentDefinition{}, client.InNamespace(namespace))
    60  		k8sClient.DeleteAllOf(ctx, &v1beta1.WorkloadDefinition{}, client.InNamespace(namespace))
    61  		k8sClient.DeleteAllOf(ctx, &v1beta1.TraitDefinition{}, client.InNamespace(namespace))
    62  		k8sClient.DeleteAllOf(ctx, &v1beta1.WorkflowStepDefinition{}, client.InNamespace(namespace))
    63  		k8sClient.DeleteAllOf(ctx, &v1beta1.DefinitionRevision{}, client.InNamespace(namespace))
    64  
    65  		By(fmt.Sprintf("Delete the entire namespaceName %s", ns.Name))
    66  		Expect(k8sClient.Delete(ctx, &ns, client.PropagationPolicy(metav1.DeletePropagationForeground))).Should(Succeed())
    67  	})
    68  
    69  	Context("Test dynamic admission control for componentDefinition", func() {
    70  
    71  		It("Test componentDefinition which only set type field", func() {
    72  			workDef := &v1beta1.WorkloadDefinition{
    73  				TypeMeta: metav1.TypeMeta{
    74  					Kind:       "WorkloadDefinition",
    75  					APIVersion: "core.oam.dev/v1beta1",
    76  				},
    77  				ObjectMeta: metav1.ObjectMeta{
    78  					Name: "deployments.apps",
    79  				},
    80  				Spec: v1beta1.WorkloadDefinitionSpec{
    81  					Reference: common.DefinitionReference{
    82  						Name:    "deployments.apps",
    83  						Version: "v1",
    84  					},
    85  				},
    86  			}
    87  			workDef.SetNamespace(namespace)
    88  			Expect(k8sClient.Create(ctx, workDef)).Should(BeNil())
    89  			getWd := new(v1beta1.WorkloadDefinition)
    90  			Eventually(func() error {
    91  				return k8sClient.Get(ctx, client.ObjectKey{Name: workDef.Name, Namespace: namespace}, getWd)
    92  			}, 15*time.Second, time.Second).Should(BeNil())
    93  
    94  			cd := webServiceWithNoTemplate.DeepCopy()
    95  			cd.Spec.Workload.Definition = common.WorkloadGVK{}
    96  			cd.Spec.Workload.Type = "deployments.apps"
    97  			cd.SetNamespace(namespace)
    98  			cd.SetName("test-componentdef")
    99  			cd.Spec.Schematic.CUE.Template = webServiceV1Template
   100  
   101  			Eventually(func() error {
   102  				return k8sClient.Create(ctx, cd)
   103  			}, 5*time.Second, time.Second).Should(BeNil())
   104  
   105  			defRev := new(v1beta1.DefinitionRevision)
   106  			Eventually(func() error {
   107  				return k8sClient.Get(ctx, client.ObjectKey{Name: "test-componentdef-v1", Namespace: namespace}, defRev)
   108  			}).Should(BeNil())
   109  		})
   110  
   111  		It("Test componentDefinition only set definition field", func() {
   112  			testCd := webServiceWithNoTemplate.DeepCopy()
   113  			testCd.Spec.Schematic.CUE.Template = webServiceV1Template
   114  			testCd.SetName("test-componentdef-v1")
   115  			testCd.SetNamespace(namespace)
   116  			Expect(k8sClient.Create(ctx, testCd)).Should(Succeed())
   117  
   118  			By("check MutatingWebhook fill the type filed")
   119  			newCd := new(v1beta1.ComponentDefinition)
   120  			Eventually(func() error {
   121  				return k8sClient.Get(ctx, client.ObjectKey{Name: testCd.Name, Namespace: namespace}, newCd)
   122  			}, 15*time.Second, time.Second).Should(BeNil())
   123  
   124  			Expect(newCd.Spec.Workload.Type).Should(Equal("deployments.apps"))
   125  
   126  			By("check workloadDefinition created by MutatingWebhook")
   127  			newWd := new(v1beta1.WorkloadDefinition)
   128  			wdName := newCd.Spec.Workload.Type
   129  			Eventually(func() error {
   130  				return k8sClient.Get(ctx, client.ObjectKey{Name: wdName, Namespace: namespace}, newWd)
   131  			}, 15*time.Second, time.Second).Should(BeNil())
   132  
   133  			Expect(newWd.Spec.Reference.Name).Should(Equal(wdName))
   134  			Expect(newWd.Spec.Reference.Version).To(Equal("v1"))
   135  		})
   136  
   137  		It("Test componentDefinition which definition and type fields are all empty", func() {
   138  			testCd1 := webServiceWithNoTemplate.DeepCopy()
   139  			testCd1.SetName("test-componentdef-v2")
   140  			testCd1.Spec.Workload.Definition = common.WorkloadGVK{}
   141  			testCd1.Spec.Schematic.CUE.Template = webServiceV1Template
   142  			testCd1.SetNamespace(namespace)
   143  			Expect(k8sClient.Create(ctx, testCd1)).Should(BeNil())
   144  
   145  			newCd := new(v1beta1.ComponentDefinition)
   146  			Eventually(func() error {
   147  				return k8sClient.Get(ctx, client.ObjectKey{Name: testCd1.Name, Namespace: namespace}, newCd)
   148  			}, 15*time.Second, time.Second).Should(BeNil())
   149  			Expect(newCd.Spec.Workload.Type).Should(Equal(types.AutoDetectWorkloadDefinition))
   150  		})
   151  
   152  		It("Test componentDefinition which definition and type point to same workload type", func() {
   153  			testCd2 := webServiceWithNoTemplate.DeepCopy()
   154  			testCd2.SetName("test-componentdef-v3")
   155  			testCd2.Spec.Workload.Type = "deployments.apps"
   156  			testCd2.Spec.Schematic.CUE.Template = webServiceV1Template
   157  			testCd2.SetNamespace(namespace)
   158  			Expect(k8sClient.Create(ctx, testCd2)).Should(Succeed())
   159  		})
   160  
   161  		It("Test componentDefinition which definition and type point to different workload type", func() {
   162  			testCd3 := webServiceWithNoTemplate.DeepCopy()
   163  			testCd3.SetName("test-componentdef-v4")
   164  			testCd3.Spec.Workload.Type = "jobs.batch"
   165  			testCd3.Spec.Schematic.CUE.Template = webServiceV1Template
   166  			testCd3.SetNamespace(namespace)
   167  			Expect(k8sClient.Create(ctx, testCd3)).Should(HaveOccurred())
   168  		})
   169  
   170  		It("Test componentDefinition which specify the name of definitionRevision", func() {
   171  			By("create componentDefinition")
   172  			cd := webServiceWithNoTemplate.DeepCopy()
   173  			cd.SetNamespace(namespace)
   174  			cd.SetName("test-def-specify-revision")
   175  			cd.SetAnnotations(map[string]string{
   176  				oam.AnnotationDefinitionRevisionName: "1.1.1",
   177  			})
   178  			cd.Spec.Schematic.CUE.Template = webServiceV1Template
   179  			Expect(k8sClient.Create(ctx, cd)).Should(Succeed())
   180  
   181  			By("check definitionRevision created by controller")
   182  			defRev := new(v1beta1.DefinitionRevision)
   183  			Eventually(func() error {
   184  				return k8sClient.Get(ctx, client.ObjectKey{Name: fmt.Sprintf("%s-v%s", cd.Name, "1.1.1"), Namespace: namespace}, defRev)
   185  			}, 15*time.Second, time.Second).Should(BeNil())
   186  
   187  			By("update componentDefinition")
   188  			oldCd := new(v1beta1.ComponentDefinition)
   189  			Eventually(func() error {
   190  				return k8sClient.Get(ctx, client.ObjectKey{Name: cd.Name, Namespace: namespace}, oldCd)
   191  			}, 15*time.Second, time.Second).Should(BeNil())
   192  
   193  			newCd := oldCd.DeepCopy()
   194  			cd.Spec.Schematic.CUE.Template = webServiceV2Template
   195  			Expect(k8sClient.Create(ctx, newCd)).Should(HaveOccurred())
   196  		})
   197  	})
   198  
   199  	Context("Test dynamic admission control for traitDefinition", func() {
   200  		It("Test traitDefinition which specify the name of definitionRevision", func() {
   201  			By("create traitDefinition")
   202  			td := exposeWithNoTemplate.DeepCopy()
   203  			td.SetNamespace(namespace)
   204  			td.SetName("test-td-specify-revision")
   205  			td.SetAnnotations(map[string]string{
   206  				oam.AnnotationDefinitionRevisionName: "1.1.1",
   207  			})
   208  			td.Spec.Schematic.CUE.Template = exposeV1Template
   209  			Expect(k8sClient.Create(ctx, td)).Should(Succeed())
   210  
   211  			By("check definitionRevision created by controller")
   212  			defRev := new(v1beta1.DefinitionRevision)
   213  			Eventually(func() error {
   214  				return k8sClient.Get(ctx, client.ObjectKey{Name: fmt.Sprintf("%s-v%s", td.Name, "1.1.1"), Namespace: namespace}, defRev)
   215  			}, 15*time.Second, time.Second).Should(BeNil())
   216  
   217  			By("update traitDefinition spec, should be ejected")
   218  			oldTd := new(v1beta1.TraitDefinition)
   219  			Eventually(func() error {
   220  				return k8sClient.Get(ctx, client.ObjectKey{Name: td.Name, Namespace: namespace}, oldTd)
   221  			}, 15*time.Second, time.Second).Should(BeNil())
   222  
   223  			newTd := oldTd.DeepCopy()
   224  			newTd.Spec.Schematic.CUE.Template = exposeV2Template
   225  			Expect(k8sClient.Create(ctx, newTd)).Should(HaveOccurred())
   226  		})
   227  	})
   228  
   229  	It("Test notification step definition", func() {
   230  		By("Install notification workflow step definition")
   231  		_, file, _, _ := runtime.Caller(0)
   232  		Expect(testdef.InstallDefinitionFromYAML(ctx, k8sClient, filepath.Join(file, "../../../charts/vela-core/templates/defwithtemplate/notification.yaml"), func(s string) string {
   233  			return strings.ReplaceAll(s, `{{ include "systemDefinitionNamespace" . }}`, "vela-system")
   234  		})).Should(SatisfyAny(Succeed(), &util.AlreadyExistMatcher{}))
   235  
   236  		By("Create a secret for the notification step")
   237  		Expect(k8sClient.Create(ctx, &corev1.Secret{
   238  			ObjectMeta: metav1.ObjectMeta{
   239  				Name:      "my-secret",
   240  				Namespace: namespace,
   241  			},
   242  			StringData: map[string]string{"url": "https://kubevela.io"},
   243  		})).Should(SatisfyAny(Succeed(), &util.AlreadyExistMatcher{}))
   244  
   245  		By("Create application with notification step consuming a secret")
   246  		var newApp v1beta1.Application
   247  		Expect(utilcommon.ReadYamlToObject("testdata/app/app_notification_secret.yaml", &newApp)).Should(BeNil())
   248  		newApp.Namespace = namespace
   249  		Expect(k8sClient.Create(ctx, &newApp)).Should(BeNil())
   250  
   251  		By("Verify application is running")
   252  		verifyApplicationPhase(context.TODO(), newApp.Namespace, newApp.Name, common.ApplicationRunning)
   253  
   254  		By("Create application with notification step")
   255  		newApp = v1beta1.Application{}
   256  		Expect(utilcommon.ReadYamlToObject("testdata/app/app_notification.yaml", &newApp)).Should(BeNil())
   257  		newApp.Namespace = namespace
   258  		Expect(k8sClient.Create(ctx, &newApp)).Should(BeNil())
   259  
   260  		By("Verify application is running")
   261  		verifyApplicationPhase(context.TODO(), newApp.Namespace, newApp.Name, common.ApplicationRunning)
   262  	})
   263  })