Test: add e2e-test for multi-cluster rollout (#2472)

* Test: add e2e-test guarantee multi-cluster rollout

* Fix: install rollout runtime chart

add cluster name in dockerfile

Fix: build image error

enable all test

Fix: add rollout chart

add shebang

fix image repo
This commit is contained in:
wyike
2021-10-14 18:27:50 +08:00
committed by GitHub
parent 56a8b0c002
commit 89eaf502fa
8 changed files with 300 additions and 1 deletions
@@ -76,10 +76,16 @@ jobs:
- name: Load Image to kind cluster (Hub)
run: make kind-load
- name: Load Image to kind cluster (Worker)
run: |
make kind-load-runtime-cluster
- name: Cleanup for e2e tests
run: |
make e2e-cleanup
make e2e-setup-core
make
make setup-runtime-e2e-cluster
- name: Run e2e multicluster tests
run: make e2e-multicluster-test
+4 -1
View File
@@ -45,4 +45,7 @@ charts/vela-core/crds/_.yaml
.vela/
# check docs
git-page/
git-page/
# e2e rollout runtime image build
runtime/rollout/e2e/tmp
+12
View File
@@ -39,6 +39,9 @@ endif
VELA_CORE_IMAGE ?= vela-core:latest
VELA_CORE_TEST_IMAGE ?= vela-core-test:$(GIT_COMMIT)
VELA_RUNTIME_ROLLOUT_IMAGE ?= vela-runtime-rollout:latest
VELA_RUNTIME_ROLLOUT_TEST_IMAGE ?= vela-runtime-rollout-test:$(GIT_COMMIT)
RUNTIME_CLUSTER_CONFIG ?= /tmp/worker.kubeconfig
RUNTIME_CLUSTER_NAME ?= worker
all: build
@@ -146,6 +149,9 @@ e2e-setup-core:
helm upgrade --install --create-namespace --namespace vela-system --set image.pullPolicy=IfNotPresent --set image.repository=vela-core-test --set applicationRevisionLimit=5 --set dependCheckWait=10s --set image.tag=$(GIT_COMMIT) --set multicluster.enabled=true --wait kubevela ./charts/vela-core
kubectl wait --for=condition=Available deployment/kubevela-vela-core -n vela-system --timeout=180s
setup-runtime-e2e-cluster:
helm upgrade --install --create-namespace --namespace vela-system --kubeconfig=$(RUNTIME_CLUSTER_CONFIG) --set image.pullPolicy=IfNotPresent --set image.repository=vela-runtime-rollout-test --set image.tag=$(GIT_COMMIT) --wait vela-rollout ./runtime/rollout/charts
e2e-setup:
helm install kruise https://github.com/openkruise/kruise/releases/download/v0.9.0/kruise-chart.tgz --set featureGates="PreDownloadImageForInPlaceUpdate=true"
sh ./hack/e2e/modify_charts.sh
@@ -216,6 +222,12 @@ kind-load:
docker build -t $(VELA_CORE_TEST_IMAGE) -f Dockerfile.e2e .
kind load docker-image $(VELA_CORE_TEST_IMAGE) || { echo >&2 "kind not installed or error loading image: $(VELA_CORE_TEST_IMAGE)"; exit 1; }
kind-load-runtime-cluster:
/bin/sh hack/e2e/build_runtime_rollout.sh
docker build -t $(VELA_RUNTIME_ROLLOUT_TEST_IMAGE) -f runtime/rollout/e2e/Dockerfile.e2e runtime/rollout/e2e/
rm -rf runtime/rollout/e2e/tmp
kind load docker-image $(VELA_RUNTIME_ROLLOUT_TEST_IMAGE) --name=$(RUNTIME_CLUSTER_NAME) || { echo >&2 "kind not installed or error loading image: $(VELA_RUNTIME_ROLLOUT_TEST_IMAGE)"; exit 1; }
# Run tests
core-test: fmt vet manifests
go test ./pkg/... -coverprofile cover.out
+12
View File
@@ -0,0 +1,12 @@
#!/bin/sh
TEMP_DIR="./runtime/rollout/e2e/tmp/"
mkdir -p $TEMP_DIR
cp -r go.mod $TEMP_DIR
cp -r go.sum $TEMP_DIR
cp -r entrypoint.sh $TEMP_DIR
cp -r runtime/rollout/cmd/main.go $TEMP_DIR
cp -r ./apis $TEMP_DIR
cp -r ./pkg $TEMP_DIR
cp -r ./version $TEMP_DIR
+44
View File
@@ -0,0 +1,44 @@
# Build the manager binary
FROM --platform=${BUILDPLATFORM:-linux/amd64} golang:1.16-alpine as builder
WORKDIR /workspace
# Copy the Go Modules manifests
COPY ./tmp/go.mod go.mod
COPY ./tmp/go.sum go.sum
# cache deps before building and copying source so that we don't need to re-download as much
# and so that source changes don't invalidate our downloaded layer
RUN go mod download
# Copy the go source
COPY ./tmp/main.go main.go
COPY ./tmp/apis apis/
COPY ./tmp/pkg pkg/
COPY ./tmp/version version/
# Build
ARG TARGETARCH
ARG VERSION
ARG GITVERSION
RUN GO111MODULE=on CGO_ENABLED=0 GOOS=linux GOARCH=${TARGETARCH} \
go build -a -ldflags "-s -w -X github.com/oam-dev/kubevela/version.VelaVersion=${VERSION:-undefined} -X github.com/oam-dev/kubevela/version.GitRevision=${GITVERSION:-undefined}" \
-o manager-${TARGETARCH} main.go
# Use alpine as base image due to the discussion in issue #1448
# You can replace distroless as minimal base image to package the manager binary
# Refer to https://github.com/GoogleContainerTools/distroless for more details
# Overwrite `BASE_IMAGE` by passing `--build-arg=BASE_IMAGE=gcr.io/distroless/static:nonroot`
ARG BASE_IMAGE
FROM ${BASE_IMAGE:-alpine:latest}
# This is required by daemon connnecting with cri
RUN apk add --no-cache ca-certificates bash
WORKDIR /
ARG TARGETARCH
COPY --from=builder /workspace/manager-${TARGETARCH} /usr/local/bin/manager
COPY ./tmp/entrypoint.sh /usr/local/bin/
ENTRYPOINT ["entrypoint.sh"]
CMD ["manager"]
@@ -0,0 +1,147 @@
/*
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 e2e_multicluster_test
import (
"context"
"fmt"
"io/ioutil"
"time"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
appsv1 "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/apis/standard.oam.dev/v1alpha1"
"github.com/oam-dev/kubevela/pkg/oam/util"
"sigs.k8s.io/yaml"
)
var _ = Describe("Test MultiClustet Rollout", func() {
Context("Test Runtime Cluster Rollout", func() {
var namespace string
var hubCtx context.Context
var workerCtx context.Context
var rollout v1alpha1.Rollout
var componentName string
var targetDeploy appsv1.Deployment
var sourceDeploy appsv1.Deployment
BeforeEach(func() {
hubCtx, workerCtx, namespace = initializeContextAndNamespace()
componentName = "hello-world-server"
})
AfterEach(func() {
cleanUpNamespace(hubCtx, workerCtx, namespace)
ns := v1.Namespace{}
Eventually(func() error { return k8sClient.Get(hubCtx, types.NamespacedName{Name: namespace}, &ns) }, 300*time.Second, 300*time.Millisecond).Should(util.NotFoundMatcher{})
})
verifySucceed := func(componentRevision string) {
By("check rollout status have succeed")
Eventually(func() error {
rolloutKey := types.NamespacedName{Namespace: namespace, Name: componentName}
if err := k8sClient.Get(workerCtx, rolloutKey, &rollout); err != nil {
return err
}
if rollout.Spec.TargetRevisionName != componentRevision {
return fmt.Errorf("rollout have not point to right targetRevision")
}
if rollout.Status.RollingState != v1alpha1.RolloutSucceedState {
return fmt.Errorf("error rollout status state %s", rollout.Status.RollingState)
}
compRevName := rollout.Spec.TargetRevisionName
deployKey := types.NamespacedName{Namespace: namespace, Name: compRevName}
if err := k8sClient.Get(workerCtx, deployKey, &targetDeploy); err != nil {
return err
}
if *targetDeploy.Spec.Replicas != *rollout.Spec.RolloutPlan.TargetSize {
return fmt.Errorf("targetDeploy replicas missMatch %d, %d", targetDeploy.Spec.Replicas, rollout.Spec.RolloutPlan.TargetSize)
}
if targetDeploy.Status.UpdatedReplicas != *targetDeploy.Spec.Replicas {
return fmt.Errorf("update not finish")
}
if len(targetDeploy.OwnerReferences) != 1 {
return fmt.Errorf("workload ownerReference missMatch")
}
// guarantee rollout's owners and workload's owners are same
if targetDeploy.OwnerReferences[0].Kind != rollout.OwnerReferences[0].Kind ||
targetDeploy.OwnerReferences[0].Name != rollout.OwnerReferences[0].Name {
return fmt.Errorf("workload ownerReference missMatch")
}
if rollout.Status.LastSourceRevision == "" {
return nil
}
deployKey = types.NamespacedName{Namespace: namespace, Name: rollout.Status.LastSourceRevision}
if err := k8sClient.Get(workerCtx, deployKey, &sourceDeploy); err == nil || !apierrors.IsNotFound(err) {
return fmt.Errorf("source deploy still exist")
}
return nil
}, time.Second*360, 300*time.Millisecond).Should(BeNil())
}
It("Test Rollout whole feature in runtime cluster ", func() {
app := &v1beta1.Application{}
appYaml, err := ioutil.ReadFile("./testdata/app/app-rollout-envbinding.yaml")
Expect(err).Should(Succeed())
Expect(yaml.Unmarshal([]byte(appYaml), app)).Should(Succeed())
app.SetNamespace(namespace)
err = k8sClient.Create(hubCtx, app)
Expect(err).Should(Succeed())
verifySucceed(componentName + "-v1")
By("update application to v2")
checkApp := &v1beta1.Application{}
Eventually(func() error {
if err := k8sClient.Get(hubCtx, types.NamespacedName{Namespace: namespace, Name: app.Name}, checkApp); err != nil {
return err
}
checkApp.Spec.Components[0].Properties.Raw = []byte(`{"image": "stefanprodan/podinfo:5.0.2"}`)
if err := k8sClient.Update(hubCtx, checkApp); err != nil {
return err
}
return nil
}, 500*time.Millisecond, 30*time.Second).Should(BeNil())
verifySucceed(componentName + "-v2")
By("revert to v1, should guarantee compRev v1 still exist")
appYaml, err = ioutil.ReadFile("./testdata/app/revert-app-envbinding.yaml")
Expect(err).Should(Succeed())
Expect(k8sClient.Get(hubCtx, types.NamespacedName{Namespace: namespace, Name: app.Name}, checkApp)).Should(BeNil())
revertApp := &v1beta1.Application{}
Expect(yaml.Unmarshal([]byte(appYaml), revertApp)).Should(Succeed())
revertApp.SetNamespace(namespace)
revertApp.SetResourceVersion(checkApp.ResourceVersion)
Eventually(func() error {
if err := k8sClient.Update(hubCtx, revertApp); err != nil {
return err
}
return nil
}, 500*time.Millisecond, 30*time.Second).Should(BeNil())
verifySucceed(componentName + "-v1")
})
})
})
@@ -0,0 +1,37 @@
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: example-app
namespace: default
spec:
components:
- name: hello-world-server
type: webservice
properties:
image: stefanprodan/podinfo:4.0.3
traits:
- type: rollout
properties:
targetSize: 2
rolloutBatches:
- replicas: 1
- replicas: 1
policies:
- name: example-multi-env-policy
type: env-binding
properties:
envs:
- name: staging
placement: # selecting the cluster to deploy to
clusterSelector:
name: cluster-worker
workflow:
steps:
# deploy to staging env
- name: deploy-staging
type: deploy2env
properties:
policy: example-multi-env-policy
env: staging
@@ -0,0 +1,38 @@
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: example-app
namespace: default
spec:
components:
- name: hello-world-server
type: webservice
properties:
image: stefanprodan/podinfo:5.0.2
traits:
- type: rollout
properties:
targetRevision: hello-world-server-v1
targetSize: 2
rolloutBatches:
- replicas: 1
- replicas: 1
policies:
- name: example-multi-env-policy
type: env-binding
properties:
envs:
- name: staging
placement: # selecting the cluster to deploy to
clusterSelector:
name: cluster-worker
workflow:
steps:
# deploy to staging env
- name: deploy-staging
type: deploy2env
properties:
policy: example-multi-env-policy
env: staging