Compare commits

..

8 Commits

Author SHA1 Message Date
Tianxin Dong
8f35596872 Fix: fix panic if trait tries to patch an invalid workload like terraform (#5329)
Signed-off-by: FogDong <dongtianxin.tx@alibaba-inc.com>

Signed-off-by: FogDong <dongtianxin.tx@alibaba-inc.com>
2023-01-19 14:40:49 +08:00
github-actions[bot]
18c2fa15a2 fix: fix --cluster when addon enable (#5339)
Signed-off-by: zhaowei.wang <zhaowei.wang@metabit-trading.com>
(cherry picked from commit 021ca69cfd)

Co-authored-by: zhaowei.wang <zhaowei.wang@metabit-trading.com>
2023-01-13 17:06:50 +08:00
Somefive
18d93039c9 [Backport release-1.4] Fix: gc failure cause workflow restart not working properly (#5241) (#5243)
* Fix: gc failure cause workflow restart not working properly

Signed-off-by: Somefive <yd219913@alibaba-inc.com>

* Feat: switch ci machine

Signed-off-by: Somefive <yd219913@alibaba-inc.com>

* Fix: enhance test

Signed-off-by: Somefive <yd219913@alibaba-inc.com>

Signed-off-by: Somefive <yd219913@alibaba-inc.com>

Signed-off-by: Somefive <yd219913@alibaba-inc.com>
2023-01-03 20:01:29 +08:00
github-actions[bot]
8ffd80e4a7 Fix:Dry-run from revision application,Problems caused by resource version lower than the current version (#5249)
Signed-off-by: old.prince <di7zhang@gmail.com>
(cherry picked from commit d5fcb04147)

Co-authored-by: oldprince <di7zhang@gmail.com>
2023-01-03 11:36:57 +08:00
github-actions[bot]
735075f5a6 [Backport release-1.5] Fix: forbid 302 request to avoid SSRF (#5003)
* fix helm chart list endpoint SSRF CVE

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

* revert error log

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

* change with const value

Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com>

fix ci

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

Co-authored-by: 楚岳 <wangyike.wyk@alibaba-inc.com>
2022-11-04 20:16:53 +08:00
github-actions[bot]
52d1a4364b fix gitlab addon registry (#4938)
Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com>
(cherry picked from commit f3ee964734)

Co-authored-by: 楚岳 <wangyike.wyk@alibaba-inc.com>
2022-10-27 22:19:34 +08:00
github-actions[bot]
1b7f9aae65 [Backport release-1.5] Chore: wrong endpoint for LoadBalancer type service(revert #4729) (#4906)
* Chore: wrong endpoint for LoadBalancer type service(revert #4729)

Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
(cherry picked from commit 92ed75c863)

* Fix: change the unit test

Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
(cherry picked from commit 7985353e1d)

Co-authored-by: barnettZQG <barnett.zqg@gmail.com>
2022-10-22 13:27:07 +08:00
github-actions[bot]
e94519b788 Chore: change the package name of the readme-generator-for-helm (#4896)
Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
(cherry picked from commit 8b46e6076a)

Co-authored-by: barnettZQG <barnett.zqg@gmail.com>
2022-10-20 16:37:25 +08:00
26 changed files with 251 additions and 68 deletions

View File

@@ -104,7 +104,7 @@ jobs:
name: codecov-umbrella
apiserver-e2e-tests:
runs-on: aliyun
runs-on: aliyun-legacy
needs: [ detect-noop,set-k8s-matrix ]
if: needs.detect-noop.outputs.noop != 'true'
strategy:

View File

@@ -52,7 +52,7 @@ jobs:
e2e-multi-cluster-tests:
runs-on: aliyun
runs-on: aliyun-legacy
needs: [ detect-noop,set-k8s-matrix ]
if: needs.detect-noop.outputs.noop != 'true'
strategy:

View File

@@ -51,7 +51,7 @@ jobs:
fi
e2e-rollout-tests:
runs-on: aliyun
runs-on: aliyun-legacy
needs: [ detect-noop,set-k8s-matrix ]
if: needs.detect-noop.outputs.noop != 'true'
strategy:

View File

@@ -51,7 +51,7 @@ jobs:
fi
e2e-tests:
runs-on: aliyun
runs-on: aliyun-legacy
needs: [ detect-noop,set-k8s-matrix ]
if: needs.detect-noop.outputs.noop != 'true'
strategy:

View File

@@ -97,7 +97,7 @@ jobs:
version: ${{ env.GOLANGCI_VERSION }}
check-diff:
runs-on: aliyun
runs-on: aliyun-legacy
needs: detect-noop
if: needs.detect-noop.outputs.noop != 'true'

View File

@@ -4,7 +4,7 @@ on:
- cron: '* * * * *'
jobs:
clean-image:
runs-on: aliyun
runs-on: aliyun-legacy
steps:
- name: Cleanup image
run: docker image prune -f

View File

@@ -80,7 +80,7 @@ ifeq (, $(shell which readme-generator))
@{ \
set -e ;\
echo 'installing readme-generator-for-helm' ;\
npm install -g readme-generator-for-helm ;\
npm install -g @bitnami/readme-generator-for-helm ;\
}
else
@$(OK) readme-generator-for-helm is already installed

View File

@@ -86,7 +86,6 @@ var _ = Describe("test FindWholeAddonPackagesFromRegistry", func() {
Expect(res).To(HaveLen(1))
Expect(res[0].Name).To(Equal("velaux"))
Expect(res[0].InstallPackage).ToNot(BeNil())
Expect(res[0].APISchema).ToNot(BeNil())
})
It("should return one valid result, matching one registry", func() {
res, err := FindWholeAddonPackagesFromRegistry(context.Background(), k8sClient, []string{"velaux"}, []string{"KubeVela"})
@@ -94,7 +93,6 @@ var _ = Describe("test FindWholeAddonPackagesFromRegistry", func() {
Expect(res).To(HaveLen(1))
Expect(res[0].Name).To(Equal("velaux"))
Expect(res[0].InstallPackage).ToNot(BeNil())
Expect(res[0].APISchema).ToNot(BeNil())
})
})
@@ -113,10 +111,8 @@ var _ = Describe("test FindWholeAddonPackagesFromRegistry", func() {
Expect(res).To(HaveLen(2))
Expect(res[0].Name).To(Equal("velaux"))
Expect(res[0].InstallPackage).ToNot(BeNil())
Expect(res[0].APISchema).ToNot(BeNil())
Expect(res[1].Name).To(Equal("traefik"))
Expect(res[1].InstallPackage).ToNot(BeNil())
Expect(res[1].APISchema).ToNot(BeNil())
})
})
@@ -127,7 +123,6 @@ var _ = Describe("test FindWholeAddonPackagesFromRegistry", func() {
Expect(res).To(HaveLen(1))
Expect(res[0].Name).To(Equal("velaux"))
Expect(res[0].InstallPackage).ToNot(BeNil())
Expect(res[0].APISchema).ToNot(BeNil())
})
})
})

View File

@@ -1550,6 +1550,13 @@ func (c *applicationServiceImpl) DryRunAppOrRevision(ctx context.Context, appMod
}
case "REVISION":
app, _, err = c.getAppModelFromRevision(ctx, appModel.Name, dryRunReq.Version)
originalApp := &v1beta1.Application{}
if err := c.KubeClient.Get(ctx, types.NamespacedName{
Name: app.Name,
Namespace: app.Namespace,
}, originalApp); err == nil {
app.ResourceVersion = originalApp.ResourceVersion
}
if err != nil {
return nil, err
}

View File

@@ -257,7 +257,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
}
case common.WorkflowStateSkipping:
logCtx.Info("Skip this reconcile")
return ctrl.Result{}, nil
return r.result(nil).requeue(wf.GetBackoffWaitTime()).ret()
}
var phase = common.ApplicationRunning
@@ -299,6 +299,11 @@ func (r *Reconciler) gcResourceTrackers(logCtx monitorContext.Context, handler *
}))
defer subCtx.Commit("finish gc resourceTrackers")
statusUpdater := r.updateStatus
if isPatch {
statusUpdater = r.patchStatus
}
var options []resourcekeeper.GCOption
if !gcOutdated {
options = append(options, resourcekeeper.DisableMarkStageGCOption{}, resourcekeeper.DisableGCComponentRevisionOption{}, resourcekeeper.DisableLegacyGCOption{})
@@ -306,8 +311,10 @@ func (r *Reconciler) gcResourceTrackers(logCtx monitorContext.Context, handler *
finished, waiting, err := handler.resourceKeeper.GarbageCollect(logCtx, options...)
if err != nil {
logCtx.Error(err, "Failed to gc resourcetrackers")
r.Recorder.Event(handler.app, event.Warning(velatypes.ReasonFailedGC, err))
return r.endWithNegativeCondition(logCtx, handler.app, condition.ReconcileError(err), phase)
cond := condition.Deleting()
cond.Message = fmt.Sprintf("error encountered during garbage collection: %s", err.Error())
handler.app.Status.SetConditions(cond)
return r.result(statusUpdater(logCtx, handler.app, phase)).ret()
}
if !finished {
logCtx.Info("GarbageCollecting resourcetrackers unfinished")
@@ -316,13 +323,13 @@ func (r *Reconciler) gcResourceTrackers(logCtx monitorContext.Context, handler *
cond.Message = fmt.Sprintf("Waiting for %s to delete. (At least %d resources are deleting.)", waiting[0].DisplayName(), len(waiting))
}
handler.app.Status.SetConditions(cond)
return r.result(r.patchStatus(logCtx, handler.app, phase)).requeue(baseGCBackoffWaitTime).ret()
return r.result(statusUpdater(logCtx, handler.app, phase)).requeue(baseGCBackoffWaitTime).ret()
}
logCtx.Info("GarbageCollected resourcetrackers")
if !isPatch {
return r.result(r.updateStatus(logCtx, handler.app, common.ApplicationRunningWorkflow)).ret()
phase = common.ApplicationRunningWorkflow
}
return r.result(r.patchStatus(logCtx, handler.app, phase)).ret()
return r.result(statusUpdater(logCtx, handler.app, phase)).ret()
}
type reconcileResult struct {

View File

@@ -292,6 +292,7 @@ func NewTraitAbstractEngine(name string, pd *packages.PackageDiscover) AbstractE
}
// Complete do trait definition's rendering
// nolint:gocyclo
func (td *traitDef) Complete(ctx process.Context, abstractTemplate string, params interface{}) error {
bi := build.NewContext().NewInstance("", nil)
if err := bi.AddFile("-", abstractTemplate); err != nil {
@@ -360,6 +361,9 @@ func (td *traitDef) Complete(ctx process.Context, abstractTemplate string, param
if err != nil {
return errors.WithMessagef(err, "invalid patch of trait %s", td.name)
}
if base == nil {
return fmt.Errorf("patch trait %s into an invalid workload", td.name)
}
if err := base.Unify(p, sets.CreateUnifyOptionsForPatcher(patcher)...); err != nil {
return errors.WithMessagef(err, "invalid patch trait %s into workload", td.name)
}

View File

@@ -1266,6 +1266,38 @@ outputs: abc :{
}
}
func TestTraitCompleteErrorCases(t *testing.T) {
cases := map[string]struct {
ctx process.Context
traitName string
template string
params map[string]interface{}
err string
}{
"patch trait": {
ctx: process.NewContext(process.ContextData{}),
template: `
patch: {
// +patchKey=name
spec: template: spec: containers: [parameter]
}
parameter: {
name: string
image: string
command?: [...string]
}`,
err: "patch trait patch trait into an invalid workload",
},
}
for k, v := range cases {
td := NewTraitAbstractEngine(k, &packages.PackageDiscover{})
err := td.Complete(v.ctx, v.template, v.params)
assert.Error(t, err)
assert.Contains(t, err.Error(), v.err)
}
}
func TestCheckHealth(t *testing.T) {
cases := map[string]struct {
tpContext map[string]interface{}

View File

@@ -79,9 +79,15 @@ import (
var (
// Scheme defines the default KubeVela schema
Scheme = k8sruntime.NewScheme()
// forbidRedirectFunc general check func for http redirect response
forbidRedirectFunc = func(req *http.Request, via []*http.Request) error {
return errors.New("got a redirect response which is forbidden")
}
//nolint:gosec
// insecureHTTPClient insecure http client
insecureHTTPClient = &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}}
insecureHTTPClient = &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}, CheckRedirect: forbidRedirectFunc}
// forbidRedirectClient is a http client forbid redirect http request
forbidRedirectClient = &http.Client{CheckRedirect: forbidRedirectFunc}
)
const (
@@ -169,7 +175,7 @@ func HTTPGetResponse(ctx context.Context, url string, opts *HTTPOption) (*http.R
if err != nil {
return nil, err
}
httpClient := http.DefaultClient
httpClient := forbidRedirectClient
if opts != nil && len(opts.Username) != 0 && len(opts.Password) != 0 {
req.SetBasicAuth(opts.Username, opts.Password)
}
@@ -197,7 +203,7 @@ func HTTPGetResponse(ctx context.Context, url string, opts *HTTPOption) (*http.R
}
tr.TLSClientConfig = tlsConfig
defer tr.CloseIdleConnections()
httpClient = &http.Client{Transport: &tr}
httpClient = &http.Client{Transport: &tr, CheckRedirect: forbidRedirectFunc}
}
return httpClient.Do(req)
}

View File

@@ -26,6 +26,7 @@ import (
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
"time"
@@ -223,6 +224,25 @@ func TestHttpGetCaFile(t *testing.T) {
}
}
func TestHttpGetForbidRedirect(t *testing.T) {
var ctx = context.Background()
testServer := &http.Server{Addr: ":19090"}
http.HandleFunc("/redirect", func(writer http.ResponseWriter, request *http.Request) {
http.Redirect(writer, request, "http://192.168.1.1", http.StatusFound)
})
go func() {
err := testServer.ListenAndServe()
assert.NoError(t, err)
}()
time.Sleep(time.Millisecond)
_, err := HTTPGetWithOption(ctx, "http://127.0.0.1:19090/redirect", nil)
assert.Error(t, err)
assert.True(t, strings.Contains(err.Error(), "got a redirect response which is forbidden"))
}
func TestGetCUEParameterValue(t *testing.T) {
type want struct {
err error

View File

@@ -225,7 +225,7 @@ func (h *Helper) GetIndexInfo(repoURL string, skipCache bool, opts *common.HTTPO
}
i := &repo.IndexFile{}
if err := yaml.UnmarshalStrict(body, i); err != nil {
return nil, fmt.Errorf("parse index file from %s failure %w", repoURL, err)
return nil, fmt.Errorf("parse index file from %s failure", repoURL)
}
if h.cache != nil {

View File

@@ -211,10 +211,10 @@ func generatorFromService(service corev1.Service, selectorNodeIP func() string,
appp := judgeAppProtocol(port.Port)
for _, ingress := range service.Status.LoadBalancer.Ingress {
if ingress.Hostname != "" {
serviceEndpoints = append(serviceEndpoints, formatEndpoint(ingress.Hostname, appp, port.Name, port.Protocol, port.NodePort, false))
serviceEndpoints = append(serviceEndpoints, formatEndpoint(ingress.Hostname, appp, port.Name, port.Protocol, port.Port, false))
}
if ingress.IP != "" {
serviceEndpoints = append(serviceEndpoints, formatEndpoint(ingress.IP, appp, port.Name, port.Protocol, port.NodePort, false))
serviceEndpoints = append(serviceEndpoints, formatEndpoint(ingress.IP, appp, port.Name, port.Protocol, port.Port, false))
}
}
}

View File

@@ -165,7 +165,7 @@ var _ = Describe("Test Query Provider", func() {
{
"name": "seldon-ambassador-2",
"ports": []corev1.ServicePort{
{Port: 80, TargetPort: intstr.FromInt(80), Name: "80port", NodePort: 30010},
{Port: 80, TargetPort: intstr.FromInt(80), Name: "80port"},
},
"type": corev1.ServiceTypeLoadBalancer,
"status": corev1.ServiceStatus{
@@ -248,11 +248,11 @@ var _ = Describe("Test Query Provider", func() {
Expect(err).Should(BeNil())
urls := []string{
"http://1.1.1.1:30010/seldon/default/sdep2",
"http://1.1.1.1/seldon/default/sdep2",
"http://clusterip-2.default",
"clusterip-2.default:81",
"http://2.2.2.2:30020",
"http://1.1.1.1:30010",
"http://2.2.2.2:8080",
"http://1.1.1.1",
}
endValue, err := v.Field("list")
Expect(err).Should(BeNil())

View File

@@ -937,13 +937,13 @@ options: {
"https://ingress.domain.path/test",
"https://ingress.domain.path/test2",
fmt.Sprintf("http://%s:30229", gatewayIP),
"http://10.10.10.10:30080",
"http://text.example.com:30080",
"10.10.10.10:30081",
"text.example.com:30081",
"http://10.10.10.10",
"http://text.example.com",
"10.10.10.10:81",
"text.example.com:81",
fmt.Sprintf("http://%s:30002", gatewayIP),
"http://ingress.domain.helm",
"http://1.1.1.1:30011/seldon/default/sdep",
"http://1.1.1.1/seldon/default/sdep",
"http://gateway.domain",
"http://gateway.domain/api",
"https://demo.kubevela.net",

View File

@@ -149,13 +149,6 @@ func (w *workflow) ExecuteSteps(ctx monitorContext.Context, appRev *oamcore.Appl
return common.WorkflowStateSucceeded, nil
}
if cacheValue, ok := StepStatusCache.Load(cacheKey); ok {
// handle cache resource
if len(wfStatus.Steps) < cacheValue.(int) {
return common.WorkflowStateSkipping, nil
}
}
wfCtx, err := w.makeContext(w.app.Name)
if err != nil {
ctx.Error(err, "make context")
@@ -164,6 +157,13 @@ func (w *workflow) ExecuteSteps(ctx monitorContext.Context, appRev *oamcore.Appl
}
w.wfCtx = wfCtx
if cacheValue, ok := StepStatusCache.Load(cacheKey); ok {
// handle cache resource
if len(wfStatus.Steps) < cacheValue.(int) {
return common.WorkflowStateSkipping, nil
}
}
e := newEngine(ctx, wfCtx, w, wfStatus)
err = e.Run(taskRunners, w.dagMode)

View File

@@ -31,19 +31,20 @@ import (
)
const (
addonRegistryType = "type"
addonEndpoint = "endpoint"
addonOssBucket = "bucket"
addonPath = "path"
addonGitToken = "gitToken"
addonOssType = "OSS"
addonGitType = "git"
addonGiteeType = "gitee"
addonGitlabType = "gitlab"
addonHelmType = "helm"
addonUsername = "username"
addonPassword = "password"
addonRepoName = "repoName"
addonRegistryType = "type"
addonEndpoint = "endpoint"
addonOssBucket = "bucket"
addonPath = "path"
addonGitToken = "gitToken"
addonOssType = "OSS"
addonGitType = "git"
addonGiteeType = "gitee"
addonGitlabType = "gitlab"
addonHelmType = "helm"
addonUsername = "username"
addonPassword = "password"
// only gitlab registry need set this flag
addonRepoName = "gitlabRepoName"
addonHelmInsecureSkipTLS = "insecureSkipTLS"
)
@@ -67,10 +68,12 @@ func NewAddonRegistryCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.
// NewAddAddonRegistryCommand return an addon registry create command
func NewAddAddonRegistryCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
cmd := &cobra.Command{
Use: "add",
Short: "Add an addon registry.",
Long: "Add an addon registry.",
Example: `"vela addon registry add <my-registry-name> --type OSS --endpoint=<URL> --bucket=<bukect-name> or vela addon registry add my-repo --type git --endpoint=<URL> --path=<OSS-ptah> --gitToken=<git token>"`,
Use: "add",
Short: "Add an addon registry.",
Long: "Add an addon registry.",
Example: `add a helm repo registry: vela addon registry add --type=helm my-repo --endpoint=<URL>
add a github registry: vela addon registry add my-repo --type git --endpoint=<URL> --path=<ptah> --token=<git token>"
add a gitlab registry: vela addon registry add my-repo --type gitlab --endpoint=<URL> --gitlabRepoName=<repoName> --path=<path> --token=<git token>`,
RunE: func(cmd *cobra.Command, args []string) error {
registry, err := getRegistryFromArgs(cmd, args)
if err != nil {
@@ -298,6 +301,7 @@ func parseArgsFromFlag(cmd *cobra.Command) {
cmd.Flags().StringP(addonGitToken, "", "", "specify the github repo token")
cmd.Flags().StringP(addonUsername, "", "", "specify the Helm addon registry username")
cmd.Flags().StringP(addonPassword, "", "", "specify the Helm addon registry password")
cmd.Flags().StringP(addonRepoName, "", "", "specify the gitlab addon registry repoName")
cmd.Flags().BoolP(addonHelmInsecureSkipTLS, "", false,
"specify the Helm addon registry skip tls verify")
}

View File

@@ -1071,12 +1071,12 @@ func hasAddon(addons []*pkgaddon.UIData, name string) bool {
return false
}
func transClusters(cstr string) []string {
func transClusters(cstr string) []interface{} {
if len(cstr) == 0 {
return nil
}
cstr = strings.TrimPrefix(strings.TrimSuffix(cstr, "}"), "{")
var clusterL []string
var clusterL []interface{}
clusterList := strings.Split(cstr, ",")
for _, v := range clusterList {
clusterL = append(clusterL, strings.TrimSpace(v))

View File

@@ -169,7 +169,7 @@ var _ = Describe("Addon status or info", func() {
Expect(ds.DeleteRegistry(context.Background(), "KubeVela")).To(Succeed())
})
It("should display addon name and disabled status, registry name, available versions, dependencies, and parameters(optional)", func() {
PIt("should display addon name and disabled status, registry name, available versions, dependencies, and parameters(optional)", func() {
addonName := "velaux"
res, _, err := generateAddonInfo(k8sClient, addonName)
Expect(err).Should(BeNil())

View File

@@ -192,19 +192,19 @@ func TestAddonUpgradeCmdWithErrLocalPath(t *testing.T) {
func TestTransCluster(t *testing.T) {
testcase := []struct {
str string
res []string
res []interface{}
}{
{
str: "{cluster1, cluster2}",
res: []string{"cluster1", "cluster2"},
res: []interface{}{"cluster1", "cluster2"},
},
{
str: "{cluster1,cluster2}",
res: []string{"cluster1", "cluster2"},
res: []interface{}{"cluster1", "cluster2"},
},
{
str: "{cluster1, cluster2 }",
res: []string{"cluster1", "cluster2"},
res: []interface{}{"cluster1", "cluster2"},
},
}
for _, s := range testcase {

View File

@@ -436,10 +436,10 @@ var _ = Describe("Test velaQL", func() {
"https://ingress.domain.path/test",
"https://ingress.domain.path/test2",
fmt.Sprintf("http://%s:30229", gatewayIP),
"http://10.10.10.10:30180",
"http://text.example.com:30180",
"10.10.10.10:30181",
"text.example.com:30181",
"http://10.10.10.10",
"http://text.example.com",
"10.10.10.10:81",
"text.example.com:81",
// helmRelease
fmt.Sprintf("http://%s:30002", gatewayIP),
"http://ingress.domain.helm",

View File

@@ -41,6 +41,7 @@ import (
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha1"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
kubevelatypes "github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/multicluster"
"github.com/oam-dev/kubevela/pkg/oam"
"github.com/oam-dev/kubevela/pkg/utils"
@@ -696,5 +697,95 @@ var _ = Describe("Test multicluster scenario", func() {
g.Expect(k8sClient.Get(workerCtx, client.ObjectKey{Namespace: testNamespace, Name: "data-worker"}, &appsv1.Deployment{})).Should(Succeed())
}, 20*time.Second).Should(Succeed())
})
It("Test application with failed gc and restart workflow", func() {
By("duplicate cluster")
secret := &corev1.Secret{}
const secretName = "disconnection-test"
Expect(k8sClient.Get(hubCtx, types.NamespacedName{Namespace: kubevelatypes.DefaultKubeVelaNS, Name: WorkerClusterName}, secret)).Should(Succeed())
secret.SetName(secretName)
secret.SetResourceVersion("")
Expect(k8sClient.Create(hubCtx, secret)).Should(Succeed())
defer func() {
_ = k8sClient.Delete(hubCtx, secret)
}()
By("create cluster normally")
bs, err := os.ReadFile("./testdata/app/app-disconnection-test.yaml")
Expect(err).Should(Succeed())
app := &v1beta1.Application{}
Expect(yaml.Unmarshal(bs, app)).Should(Succeed())
app.SetNamespace(namespace)
Expect(k8sClient.Create(hubCtx, app)).Should(Succeed())
key := client.ObjectKeyFromObject(app)
Eventually(func(g Gomega) {
g.Expect(k8sClient.Get(hubCtx, key, app)).Should(Succeed())
g.Expect(app.Status.Phase).Should(Equal(common.ApplicationRunning))
}).WithTimeout(30 * time.Second).WithPolling(2 * time.Second).Should(Succeed())
By("disconnect cluster")
Expect(k8sClient.Get(hubCtx, types.NamespacedName{Namespace: kubevelatypes.DefaultKubeVelaNS, Name: secretName}, secret)).Should(Succeed())
secret.Data["tls.crt"] = []byte("-")
Expect(k8sClient.Update(hubCtx, secret)).Should(Succeed())
By("update application")
Expect(k8sClient.Get(hubCtx, key, app)).Should(Succeed())
app.Spec.Policies = nil
Expect(k8sClient.Update(hubCtx, app)).Should(Succeed())
Eventually(func(g Gomega) {
g.Expect(k8sClient.Get(hubCtx, key, app)).Should(Succeed())
g.Expect(app.Status.ObservedGeneration).Should(Equal(app.Generation))
g.Expect(app.Status.Phase).Should(Equal(common.ApplicationRunning))
rts := &v1beta1.ResourceTrackerList{}
g.Expect(k8sClient.List(hubCtx, rts, client.MatchingLabels{oam.LabelAppName: key.Name, oam.LabelAppNamespace: key.Namespace})).Should(Succeed())
cnt := 0
for _, item := range rts.Items {
if item.Spec.Type == v1beta1.ResourceTrackerTypeVersioned {
cnt++
}
}
g.Expect(cnt).Should(Equal(2))
}).WithTimeout(30 * time.Second).WithPolling(2 * time.Second).Should(Succeed())
By("try update application again")
Expect(k8sClient.Get(hubCtx, key, app)).Should(Succeed())
if app.Annotations == nil {
app.Annotations = map[string]string{}
}
app.Annotations[oam.AnnotationPublishVersion] = "test"
Expect(k8sClient.Update(hubCtx, app)).Should(Succeed())
Eventually(func(g Gomega) {
g.Expect(k8sClient.Get(hubCtx, key, app)).Should(Succeed())
g.Expect(app.Status.LatestRevision).ShouldNot(BeNil())
g.Expect(app.Status.LatestRevision.Revision).Should(Equal(int64(3)))
g.Expect(app.Status.ObservedGeneration).Should(Equal(app.Generation))
g.Expect(app.Status.Phase).Should(Equal(common.ApplicationRunning))
}).WithTimeout(1 * time.Minute).WithPolling(2 * time.Second).Should(Succeed())
By("clear disconnection cluster secret")
Expect(k8sClient.Get(hubCtx, types.NamespacedName{Namespace: kubevelatypes.DefaultKubeVelaNS, Name: secretName}, secret)).Should(Succeed())
Expect(k8sClient.Delete(hubCtx, secret)).Should(Succeed())
By("update application again")
Eventually(func(g Gomega) {
g.Expect(k8sClient.Get(hubCtx, key, app)).Should(Succeed())
app.Annotations[oam.AnnotationPublishVersion] = "test2"
g.Expect(k8sClient.Update(hubCtx, app)).Should(Succeed())
}).WithTimeout(10 * time.Second).WithPolling(2 * time.Second).Should(Succeed())
By("wait gc application completed")
Eventually(func(g Gomega) {
rts := &v1beta1.ResourceTrackerList{}
g.Expect(k8sClient.List(hubCtx, rts, client.MatchingLabels{oam.LabelAppName: key.Name, oam.LabelAppNamespace: key.Namespace})).Should(Succeed())
cnt := 0
for _, item := range rts.Items {
if item.Spec.Type == v1beta1.ResourceTrackerTypeVersioned {
cnt++
}
}
g.Expect(cnt).Should(Equal(1))
}).WithTimeout(3 * time.Minute).WithPolling(10 * time.Second).Should(Succeed())
})
})
})

View File

@@ -0,0 +1,17 @@
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: app-disconnection-test
spec:
components:
- type: k8s-objects
name: app-dis-cm
properties:
objects:
- apiVersion: v1
kind: ConfigMap
policies:
- type: topology
name: disconnection-test
properties:
clusters: ["disconnection-test"]