github.com/oam-dev/kubevela@v1.9.11/test/e2e-multicluster-test/multicluster_cli_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 e2e_multicluster_test
    18  
    19  import (
    20  	"context"
    21  	"io"
    22  	"net/http"
    23  	"os"
    24  	"os/exec"
    25  	"strings"
    26  	"time"
    27  
    28  	. "github.com/onsi/ginkgo/v2"
    29  	. "github.com/onsi/gomega"
    30  	"github.com/onsi/gomega/gbytes"
    31  	"github.com/onsi/gomega/gexec"
    32  	appsv1 "k8s.io/api/apps/v1"
    33  	v1 "k8s.io/api/core/v1"
    34  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    35  	apitypes "k8s.io/apimachinery/pkg/types"
    36  	"sigs.k8s.io/controller-runtime/pkg/client"
    37  	"sigs.k8s.io/yaml"
    38  
    39  	"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
    40  	"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
    41  	"github.com/oam-dev/kubevela/apis/types"
    42  	"github.com/oam-dev/kubevela/pkg/oam/util"
    43  )
    44  
    45  var _ = Describe("Test multicluster CLI commands", func() {
    46  
    47  	var namespace string
    48  	var hubCtx context.Context
    49  	var workerCtx context.Context
    50  	var app *v1beta1.Application
    51  
    52  	BeforeEach(func() {
    53  		hubCtx, workerCtx, namespace = initializeContextAndNamespace()
    54  		app = &v1beta1.Application{}
    55  		bs, err := os.ReadFile("./testdata/app/example-vela-cli-tool-test-app.yaml")
    56  		Expect(err).Should(Succeed())
    57  		appYaml := strings.ReplaceAll(string(bs), "TEST_NAMESPACE", namespace)
    58  		Expect(yaml.Unmarshal([]byte(appYaml), app)).Should(Succeed())
    59  		app.SetNamespace(namespace)
    60  		Expect(k8sClient.Create(hubCtx, app)).Should(Succeed())
    61  		Expect(err).Should(Succeed())
    62  		Eventually(func(g Gomega) {
    63  			pods := &v1.PodList{}
    64  			g.Expect(k8sClient.List(workerCtx, pods, client.InNamespace(namespace), client.MatchingLabels(map[string]string{
    65  				"app.oam.dev/name": app.Name,
    66  			}))).Should(Succeed())
    67  			g.Expect(len(pods.Items)).Should(Equal(1))
    68  			g.Expect(pods.Items[0].Status.Phase).Should(Equal(v1.PodRunning))
    69  			g.Expect(k8sClient.Get(hubCtx, client.ObjectKeyFromObject(app), app)).Should(Succeed())
    70  			g.Expect(len(app.Status.AppliedResources)).ShouldNot(Equal(0))
    71  		}, 2*time.Minute, time.Second*3).Should(Succeed())
    72  	})
    73  
    74  	AfterEach(func() {
    75  		Expect(k8sClient.Get(hubCtx, client.ObjectKeyFromObject(app), app)).Should(Succeed())
    76  		Expect(k8sClient.Delete(hubCtx, app)).Should(Succeed())
    77  		cleanUpNamespace(hubCtx, workerCtx, namespace)
    78  	})
    79  
    80  	Context("Test debugging tools in multicluster", func() {
    81  
    82  		It("Test vela exec", func() {
    83  			command := exec.Command("vela", "exec", app.Name, "-n", namespace, "-i=false", "-t=false", "--", "pwd")
    84  			outputs, err := command.CombinedOutput()
    85  			Expect(string(outputs)).Should(ContainSubstring("/"))
    86  			Expect(err).Should(Succeed())
    87  		})
    88  
    89  		It("Test vela port-forward", func() {
    90  			stopChannel := make(chan struct{}, 1)
    91  			go func() {
    92  				defer GinkgoRecover()
    93  				command := exec.Command("vela", "port-forward", app.Name, "-n", namespace)
    94  				session, err := gexec.Start(command, io.Discard, io.Discard)
    95  				Expect(err).Should(Succeed())
    96  				<-stopChannel
    97  				session.Terminate()
    98  			}()
    99  			defer func() {
   100  				stopChannel <- struct{}{}
   101  			}()
   102  			var resp *http.Response
   103  			var err error
   104  			Eventually(func(g Gomega) {
   105  				resp, err = http.Get("http://127.0.0.1:8000")
   106  				g.Expect(err).Should(Succeed())
   107  			}, time.Minute).Should(Succeed())
   108  			bs := make([]byte, 128)
   109  			_, err = resp.Body.Read(bs)
   110  			Expect(err).Should(Succeed())
   111  			Expect(string(bs)).Should(ContainSubstring("Hello World"))
   112  		})
   113  
   114  		It("Test vela status --tree", func() {
   115  			_, err := execCommand("cluster", "alias", WorkerClusterName, "alias-worker-tree")
   116  			Expect(err).Should(Succeed())
   117  			for _, format := range []string{"inline", "wide", "table", "list"} {
   118  				outputs, err := execCommand("status", app.Name, "-n", namespace, "--tree", "--detail", "--detail-format", format)
   119  				Expect(err).Should(Succeed())
   120  				Expect(outputs).Should(SatisfyAll(
   121  					ContainSubstring("alias-worker-tree"),
   122  					ContainSubstring("Deployment/exec-podinfo"),
   123  					ContainSubstring("updated"),
   124  					ContainSubstring("1/1"),
   125  				))
   126  			}
   127  		})
   128  
   129  		It("Test vela logs", func() {
   130  			var (
   131  				err         error
   132  				session     *gexec.Session
   133  				waitingTime = 2 * time.Minute
   134  			)
   135  			podViewCMFile, err := os.ReadFile("./testdata/view/component-pod-view.yaml")
   136  			Expect(err).Should(BeNil())
   137  			podViewCM := &v1.ConfigMap{}
   138  			Expect(yaml.Unmarshal(podViewCMFile, podViewCM)).Should(BeNil())
   139  			Expect(k8sClient.Create(hubCtx, podViewCM)).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
   140  
   141  			stopChannel := make(chan struct{}, 1)
   142  			defer func() {
   143  				stopChannel <- struct{}{}
   144  			}()
   145  
   146  			command := exec.Command("vela", "logs", app.Name, "-n", namespace, "--cluster", WorkerClusterName)
   147  			session, err = gexec.Start(command, nil, nil)
   148  			Expect(err).Should(Succeed())
   149  			go func() {
   150  				defer GinkgoRecover()
   151  				<-stopChannel
   152  				session.Terminate()
   153  				Eventually(session, 10*time.Second).Should(gexec.Exit())
   154  			}()
   155  			Expect(err).Should(Succeed())
   156  			Eventually(session, waitingTime).ShouldNot(BeNil())
   157  			Eventually(session, waitingTime).Should(gbytes.Say("exec-podinfo"))
   158  			Eventually(session, waitingTime).Should(gbytes.Say("httpd started"))
   159  		})
   160  	})
   161  
   162  })
   163  
   164  var _ = Describe("Test kube commands", func() {
   165  
   166  	Context("Test apply command", func() {
   167  
   168  		var namespace string
   169  		var hubCtx context.Context
   170  		var workerCtx context.Context
   171  
   172  		BeforeEach(func() {
   173  			hubCtx, workerCtx, namespace = initializeContextAndNamespace()
   174  		})
   175  
   176  		AfterEach(func() {
   177  			cleanUpNamespace(hubCtx, workerCtx, namespace)
   178  		})
   179  
   180  		It("Test vela kube apply & delete", func() {
   181  			_, err := execCommand("kube", "apply",
   182  				"--cluster", types.ClusterLocalName, "--cluster", WorkerClusterName, "-n", namespace,
   183  				"-f", "./testdata/kube",
   184  				"-f", "https://gist.githubusercontent.com/Somefive/b189219a9222eaa70b8908cf4379402b/raw/e603987b3e0989e01e50f69ebb1e8bb436461326/example-busybox-deployment.yaml",
   185  			)
   186  			Expect(err).Should(Succeed())
   187  			Expect(k8sClient.Get(hubCtx, apitypes.NamespacedName{Namespace: namespace, Name: "busybox"}, &appsv1.Deployment{})).Should(Succeed())
   188  			Expect(k8sClient.Get(workerCtx, apitypes.NamespacedName{Namespace: namespace, Name: "busybox"}, &appsv1.Deployment{})).Should(Succeed())
   189  			Expect(k8sClient.Get(hubCtx, apitypes.NamespacedName{Namespace: namespace, Name: "busybox"}, &v1.Service{})).Should(Succeed())
   190  			Expect(k8sClient.Get(workerCtx, apitypes.NamespacedName{Namespace: namespace, Name: "busybox"}, &v1.Service{})).Should(Succeed())
   191  			Expect(k8sClient.Get(hubCtx, apitypes.NamespacedName{Namespace: namespace, Name: "busybox-1"}, &v1.ConfigMap{})).Should(Succeed())
   192  			Expect(k8sClient.Get(workerCtx, apitypes.NamespacedName{Namespace: namespace, Name: "busybox-1"}, &v1.ConfigMap{})).Should(Succeed())
   193  			Expect(k8sClient.Get(hubCtx, apitypes.NamespacedName{Namespace: namespace, Name: "busybox-2"}, &v1.ConfigMap{})).Should(Succeed())
   194  			Expect(k8sClient.Get(workerCtx, apitypes.NamespacedName{Namespace: namespace, Name: "busybox-2"}, &v1.ConfigMap{})).Should(Succeed())
   195  			_, err = execCommand("kube", "delete",
   196  				"--cluster", types.ClusterLocalName, "--cluster", WorkerClusterName, "-n", namespace,
   197  				"deployment", "busybox",
   198  			)
   199  			Expect(err).Should(Succeed())
   200  			Expect(apierrors.IsNotFound(k8sClient.Get(hubCtx, apitypes.NamespacedName{Namespace: namespace, Name: "busybox"}, &appsv1.Deployment{}))).Should(BeTrue())
   201  			Expect(apierrors.IsNotFound(k8sClient.Get(workerCtx, apitypes.NamespacedName{Namespace: namespace, Name: "busybox"}, &appsv1.Deployment{}))).Should(BeTrue())
   202  			_, err = execCommand("kube", "delete",
   203  				"--cluster", types.ClusterLocalName, "--cluster", WorkerClusterName, "-n", namespace,
   204  				"configmap", "--all",
   205  			)
   206  			Expect(err).Should(Succeed())
   207  			Expect(apierrors.IsNotFound(k8sClient.Get(hubCtx, apitypes.NamespacedName{Namespace: namespace, Name: "busybox-1"}, &v1.ConfigMap{}))).Should(BeTrue())
   208  			Expect(apierrors.IsNotFound(k8sClient.Get(workerCtx, apitypes.NamespacedName{Namespace: namespace, Name: "busybox-1"}, &v1.ConfigMap{}))).Should(BeTrue())
   209  			Expect(apierrors.IsNotFound(k8sClient.Get(hubCtx, apitypes.NamespacedName{Namespace: namespace, Name: "busybox-2"}, &v1.ConfigMap{}))).Should(BeTrue())
   210  			Expect(apierrors.IsNotFound(k8sClient.Get(workerCtx, apitypes.NamespacedName{Namespace: namespace, Name: "busybox-2"}, &v1.ConfigMap{}))).Should(BeTrue())
   211  		})
   212  
   213  	})
   214  
   215  })
   216  
   217  var _ = Describe("Test delete commands", func() {
   218  
   219  	Context("Test delete command", func() {
   220  
   221  		var namespace string
   222  		var hubCtx context.Context
   223  		var workerCtx context.Context
   224  
   225  		BeforeEach(func() {
   226  			hubCtx, workerCtx, namespace = initializeContextAndNamespace()
   227  		})
   228  
   229  		AfterEach(func() {
   230  			cleanUpNamespace(hubCtx, workerCtx, namespace)
   231  		})
   232  
   233  		It("Test delete with orphan option", func() {
   234  			bs, err := os.ReadFile("./testdata/app/app-orphan-delete.yaml")
   235  			Expect(err).Should(Succeed())
   236  			app := &v1beta1.Application{}
   237  			Expect(yaml.Unmarshal(bs, app)).Should(Succeed())
   238  			app.SetNamespace(namespace)
   239  			Expect(k8sClient.Create(hubCtx, app)).Should(Succeed())
   240  			key := client.ObjectKeyFromObject(app)
   241  			cmKey := apitypes.NamespacedName{Namespace: namespace, Name: "orphan-cm"}
   242  			Eventually(func(g Gomega) {
   243  				g.Expect(k8sClient.Get(hubCtx, key, app)).Should(Succeed())
   244  				g.Expect(app.Status.Phase).Should(Equal(common.ApplicationRunning))
   245  				g.Expect(k8sClient.Get(workerCtx, cmKey, &v1.ConfigMap{})).To(Succeed())
   246  			}).WithTimeout(20 * time.Second).WithPolling(2 * time.Second).Should(Succeed())
   247  			_, err = execCommand("delete", key.Name, "-n", key.Namespace, "--orphan", "-y")
   248  			Expect(err).Should(Succeed())
   249  			Eventually(func(g Gomega) {
   250  				g.Expect(apierrors.IsNotFound(k8sClient.Get(hubCtx, key, app))).Should(BeTrue())
   251  			}).WithTimeout(10 * time.Second).WithPolling(2 * time.Second).Should(Succeed())
   252  			Expect(k8sClient.Get(workerCtx, cmKey, &v1.ConfigMap{})).To(Succeed())
   253  		})
   254  
   255  	})
   256  
   257  })