Files
kubevela/pkg/addon/addon_suite_test.go
github-actions[bot] a14b536fd1 [Backport release-1.4] Feat: skip validating version check (#4247)
* skip validating version check

Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com>
(cherry picked from commit 4b94a967ae)

* add comments

Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com>
(cherry picked from commit bbdc19c472)

* fix comments

Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com>
(cherry picked from commit b5c705013d)

* fix test

Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com>
(cherry picked from commit adff7ef309)

* fix commments

Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com>
(cherry picked from commit cf4afee0d8)

* add compatible logic for old controller

Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com>
(cherry picked from commit 3f5a6d33b9)

* modify minimal

Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com>
(cherry picked from commit b020725112)

Co-authored-by: 楚岳 <wangyike.wyk@alibaba-inc.com>
2022-06-24 14:13:17 +08:00

478 lines
15 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 addon
import (
"context"
"fmt"
"time"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
appsv1 "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
types2 "k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
"github.com/oam-dev/cluster-gateway/pkg/apis/cluster/v1alpha1"
clustercommon "github.com/oam-dev/cluster-gateway/pkg/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
v1alpha12 "github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha1"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/oam/util"
"github.com/oam-dev/kubevela/pkg/utils/apply"
)
var _ = Describe("Addon test", func() {
ctx := context.Background()
var app v1beta1.Application
AfterEach(func() {
Expect(k8sClient.Delete(ctx, &app)).Should(BeNil())
})
It("continueOrRestartWorkflow func test", func() {
app = v1beta1.Application{}
Expect(yaml.Unmarshal([]byte(appYaml), &app)).Should(BeNil())
app.SetNamespace(testns)
Expect(k8sClient.Create(ctx, &app)).Should(BeNil())
Eventually(func() error {
checkApp := &v1beta1.Application{}
if err := k8sClient.Get(ctx, types2.NamespacedName{Namespace: app.Namespace, Name: app.Name}, checkApp); err != nil {
return err
}
appPatch := client.MergeFrom(checkApp.DeepCopy())
checkApp.Status.Workflow = &common.WorkflowStatus{Suspend: true}
if err := k8sClient.Status().Patch(ctx, checkApp, appPatch); err != nil {
return err
}
return nil
}, 30*time.Second, 300*time.Millisecond).Should(BeNil())
Eventually(func() error {
checkApp := &v1beta1.Application{}
if err := k8sClient.Get(ctx, types2.NamespacedName{Namespace: app.Namespace, Name: app.Name}, checkApp); err != nil {
return err
}
if !checkApp.Status.Workflow.Suspend {
return fmt.Errorf("app haven't not suspend")
}
h := Installer{ctx: ctx, cli: k8sClient, addon: &InstallPackage{Meta: Meta{Name: "test-app"}}}
if err := h.continueOrRestartWorkflow(); err != nil {
return err
}
return nil
}, 30*time.Second, 300*time.Millisecond).Should(BeNil())
Eventually(func() error {
checkApp := &v1beta1.Application{}
if err := k8sClient.Get(ctx, types2.NamespacedName{Namespace: app.Namespace, Name: app.Name}, checkApp); err != nil {
return err
}
if checkApp.Status.Workflow.Suspend {
return fmt.Errorf("app haven't not continue")
}
return nil
}, 30*time.Second, 300*time.Millisecond).Should(BeNil())
})
It("continueOrRestartWorkflow func test, test restart workflow", func() {
app = v1beta1.Application{}
Expect(yaml.Unmarshal([]byte(appYaml), &app)).Should(BeNil())
app.SetNamespace(testns)
Expect(k8sClient.Create(ctx, &app)).Should(BeNil())
Eventually(func() error {
checkApp := &v1beta1.Application{}
if err := k8sClient.Get(ctx, types2.NamespacedName{Namespace: app.Namespace, Name: app.Name}, checkApp); err != nil {
return err
}
appPatch := client.MergeFrom(checkApp.DeepCopy())
checkApp.Status.Workflow = &common.WorkflowStatus{Message: "someMessage", AppRevision: "test-revision"}
checkApp.Status.Phase = common.ApplicationRunning
if err := k8sClient.Status().Patch(ctx, checkApp, appPatch); err != nil {
return err
}
return nil
}, 30*time.Second, 300*time.Millisecond).Should(BeNil())
Eventually(func() error {
checkApp := &v1beta1.Application{}
if err := k8sClient.Get(ctx, types2.NamespacedName{Namespace: app.Namespace, Name: app.Name}, checkApp); err != nil {
return err
}
if checkApp.Status.Phase != common.ApplicationRunning {
return fmt.Errorf("app haven't not running")
}
h := Installer{ctx: ctx, cli: k8sClient, addon: &InstallPackage{Meta: Meta{Name: "test-app"}}}
if err := h.continueOrRestartWorkflow(); err != nil {
return err
}
return nil
}, 30*time.Second, 300*time.Millisecond).Should(BeNil())
Eventually(func() error {
checkApp := &v1beta1.Application{}
if err := k8sClient.Get(ctx, types2.NamespacedName{Namespace: app.Namespace, Name: app.Name}, checkApp); err != nil {
return err
}
if checkApp.Status.Workflow != nil {
return fmt.Errorf("app workflow havenot been restart")
}
return nil
}, 30*time.Second, 300*time.Millisecond).Should(BeNil())
})
It(" FetchAddonRelatedApp func test", func() {
app = v1beta1.Application{}
Expect(yaml.Unmarshal([]byte(legacyAppYaml), &app)).Should(BeNil())
app.SetNamespace(testns)
Expect(k8sClient.Create(ctx, &app)).Should(BeNil())
Eventually(func() error {
app, err := FetchAddonRelatedApp(ctx, k8sClient, "legacy-addon")
if err != nil {
return err
}
if app.Name != "legacy-addon" {
return fmt.Errorf("error addon app name")
}
return nil
}, 30*time.Second, 300*time.Millisecond).Should(BeNil())
})
It(" determineAddonAppName func test", func() {
app = v1beta1.Application{}
Expect(yaml.Unmarshal([]byte(legacyAppYaml), &app)).Should(BeNil())
app.SetNamespace(testns)
Expect(k8sClient.Create(ctx, &app)).Should(BeNil())
Eventually(func() error {
appName, err := determineAddonAppName(ctx, k8sClient, "legacy-addon")
if err != nil {
return err
}
if appName != "legacy-addon" {
return fmt.Errorf("error addon app name")
}
return nil
}, 30*time.Second, 300*time.Millisecond).Should(BeNil())
notExsitAppName, err := determineAddonAppName(ctx, k8sClient, "not-exist")
Expect(err).Should(BeNil())
Expect(notExsitAppName).Should(BeEquivalentTo("addon-not-exist"))
})
})
var _ = Describe("Addon func test", func() {
var deploy appsv1.Deployment
AfterEach(func() {
Expect(k8sClient.Delete(ctx, &deploy))
})
It("fetchVelaCoreImageTag func test", func() {
deploy = appsv1.Deployment{}
tag, err := fetchVelaCoreImageTag(ctx, k8sClient)
Expect(err).ShouldNot(BeNil())
Expect(tag).Should(BeEquivalentTo(""))
Expect(yaml.Unmarshal([]byte(deployYaml), &deploy)).Should(BeNil())
deploy.SetNamespace(types.DefaultKubeVelaNS)
Expect(k8sClient.Create(ctx, &deploy)).Should(BeNil())
Eventually(func() error {
tag, err := fetchVelaCoreImageTag(ctx, k8sClient)
if err != nil {
return err
}
if tag != "v1.2.3" {
return fmt.Errorf("tag missmatch want %s actual %s", "v1.2.3", tag)
}
return err
}, 30*time.Second, 300*time.Millisecond).Should(BeNil())
})
It("checkAddonVersionMeetRequired func test", func() {
deploy = appsv1.Deployment{}
Expect(checkAddonVersionMeetRequired(ctx, &SystemRequirements{VelaVersion: ">=v1.2.1"}, k8sClient, dc)).ShouldNot(BeNil())
Expect(yaml.Unmarshal([]byte(deployYaml), &deploy)).Should(BeNil())
deploy.SetNamespace(types.DefaultKubeVelaNS)
Expect(k8sClient.Create(ctx, &deploy)).Should(BeNil())
Expect(checkAddonVersionMeetRequired(ctx, &SystemRequirements{VelaVersion: ">=v1.2.1"}, k8sClient, dc)).Should(BeNil())
Expect(checkAddonVersionMeetRequired(ctx, &SystemRequirements{VelaVersion: ">=v1.2.4"}, k8sClient, dc)).ShouldNot(BeNil())
})
})
var _ = Describe("Test addon util func", func() {
It("test render and fetch args", func() {
i := InstallPackage{Meta: Meta{Name: "test-addon"}}
args := map[string]interface{}{
"imagePullSecrets": []string{
"myreg", "myreg1",
},
}
u := RenderArgsSecret(&i, args)
secName := u.GetName()
secNs := u.GetNamespace()
Expect(k8sClient.Create(ctx, u)).Should(BeNil())
sec := v1.Secret{}
Expect(k8sClient.Get(ctx, types2.NamespacedName{Namespace: secNs, Name: secName}, &sec)).Should(BeNil())
res, err := FetchArgsFromSecret(&sec)
Expect(err).Should(BeNil())
Expect(res).Should(BeEquivalentTo(map[string]interface{}{"imagePullSecrets": []interface{}{"myreg", "myreg1"}}))
})
It("test render and fetch args backward compatibility", func() {
secArgs := v1.Secret{
TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "Secret"},
ObjectMeta: metav1.ObjectMeta{
Name: Convert2SecName("test-addon-old-args"),
Namespace: types.DefaultKubeVelaNS,
},
StringData: map[string]string{
"repo": "www.test.com",
"tag": "v1.3.1",
},
Type: v1.SecretTypeOpaque,
}
secName := secArgs.GetName()
secNs := secArgs.GetNamespace()
Expect(k8sClient.Create(ctx, &secArgs)).Should(BeNil())
sec := v1.Secret{}
Expect(k8sClient.Get(ctx, types2.NamespacedName{Namespace: secNs, Name: secName}, &sec)).Should(BeNil())
res, err := FetchArgsFromSecret(&sec)
Expect(err).Should(BeNil())
Expect(res).Should(BeEquivalentTo(map[string]interface{}{"repo": "www.test.com", "tag": "v1.3.1"}))
})
})
var _ = Describe("Test render addon with specified clusters", func() {
BeforeEach(func() {
Expect(k8sClient.Create(ctx, &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "add-c1",
Namespace: "vela-system",
Labels: map[string]string{
clustercommon.LabelKeyClusterCredentialType: string(v1alpha1.CredentialTypeX509Certificate),
clustercommon.LabelKeyClusterEndpointType: string(v1alpha1.ClusterEndpointTypeConst),
"key": "value",
},
},
})).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
Expect(k8sClient.Create(ctx, &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "add-c2",
Namespace: "vela-system",
Labels: map[string]string{
clustercommon.LabelKeyClusterCredentialType: string(v1alpha1.CredentialTypeX509Certificate),
clustercommon.LabelKeyClusterEndpointType: string(v1alpha1.ClusterEndpointTypeConst),
"key": "value",
},
},
})).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
})
It("test render not exits cluster", func() {
i := &baseAddon
i.Name = "test-cluster-addon"
args := map[string]interface{}{
"clusters": []string{"add-c1", "ne"},
}
_, err := RenderApp(ctx, i, k8sClient, args)
Expect(err.Error()).Should(BeEquivalentTo("cluster ne not exist"))
})
It("test render normal addon with specified clusters", func() {
i := &baseAddon
i.DeployTo = &DeployTo{RuntimeCluster: true}
i.Name = "test-cluster-addon-normal"
args := map[string]interface{}{
"clusters": []string{"add-c1", "add-c2"},
}
ap, err := RenderApp(ctx, i, k8sClient, args)
Expect(err).Should(BeNil())
Expect(ap.Spec.Policies).Should(BeEquivalentTo([]v1beta1.AppPolicy{{Name: "specified-addon-clusters",
Type: v1alpha12.TopologyPolicyType,
Properties: &runtime.RawExtension{Raw: []byte(`{"clusters":["add-c1","add-c2","local"]}`)}}}))
})
})
var _ = Describe("func addon update ", func() {
It("test update addon app label", func() {
app_test_update := v1beta1.Application{}
Expect(yaml.Unmarshal([]byte(addonUpdateAppYaml), &app_test_update)).Should(BeNil())
Expect(k8sClient.Create(ctx, &app_test_update)).Should(BeNil())
Eventually(func() error {
var err error
appCheck := v1beta1.Application{}
err = k8sClient.Get(ctx, types2.NamespacedName{Namespace: "vela-system", Name: "addon-test-update"}, &appCheck)
if err != nil {
return err
}
if appCheck.Labels["addons.oam.dev/version"] != "v1.2.0" {
return fmt.Errorf("label missmatch")
}
return nil
}, time.Millisecond*500, 30*time.Second).Should(BeNil())
pkg := &InstallPackage{Meta: Meta{Name: "test-update", Version: "1.3.0"}}
h := NewAddonInstaller(context.Background(), k8sClient, nil, nil, nil, &Registry{Name: "test"}, nil, nil)
h.addon = pkg
Expect(h.dispatchAddonResource(pkg)).Should(BeNil())
Eventually(func() error {
var err error
appCheck := v1beta1.Application{}
err = k8sClient.Get(context.Background(), types2.NamespacedName{Namespace: "vela-system", Name: "addon-test-update"}, &appCheck)
if err != nil {
return err
}
if appCheck.Labels["addons.oam.dev/version"] != "1.3.0" {
return fmt.Errorf("label missmatch")
}
return nil
}, time.Second*3, 300*time.Second).Should(BeNil())
})
})
var _ = Describe("test enable addon in local dir", func() {
BeforeEach(func() {
app := v1beta1.Application{ObjectMeta: metav1.ObjectMeta{Namespace: "vela-system", Name: "addon-example"}}
Expect(k8sClient.Delete(ctx, &app)).Should(SatisfyAny(BeNil(), util.NotFoundMatcher{}))
})
It("test enable addon by local dir", func() {
ctx := context.Background()
err := EnableAddonByLocalDir(ctx, "example", "./testdata/example", k8sClient, dc, apply.NewAPIApplicator(k8sClient), cfg, map[string]interface{}{"example": "test"})
Expect(err).Should(BeNil())
app := v1beta1.Application{}
Expect(k8sClient.Get(ctx, types2.NamespacedName{Namespace: "vela-system", Name: "addon-example"}, &app)).Should(BeNil())
})
})
const (
appYaml = `apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: addon-test-app
spec:
components:
- name: express-server
type: webservice
properties:
image: crccheck/hello-world
port: 8000
`
legacyAppYaml = `apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: legacy-addon
spec:
components:
- name: express-server
type: webservice
properties:
image: crccheck/hello-world
port: 8000
`
deployYaml = `apiVersion: apps/v1
kind: Deployment
metadata:
name: kubevela-vela-core
namespace: vela-system
labels:
controller.oam.dev/name: vela-core
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app.kubernetes.io/instance: kubevela
app.kubernetes.io/name: vela-core
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
annotations:
prometheus.io/path: /metrics
prometheus.io/port: "8080"
prometheus.io/scrape: "true"
labels:
app.kubernetes.io/instance: kubevela
app.kubernetes.io/name: vela-core
spec:
containers:
- args:
image: oamdev/vela-core:v1.2.3
imagePullPolicy: Always
name: kubevela
ports:
- containerPort: 9443
name: webhook-server
protocol: TCP
- containerPort: 9440
name: healthz
protocol: TCP
resources:
limits:
cpu: 500m
memory: 1Gi
requests:
cpu: 50m
memory: 20Mi
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30`
addonUpdateAppYaml = `
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: addon-test-update
namespace: vela-system
labels:
addons.oam.dev/version: v1.2.0
spec:
components:
- name: express-server
type: webservice
properties:
image: crccheck/hello-world
port: 8000
`
)