github.com/oam-dev/kubevela@v1.9.11/test/e2e-multicluster-test/multicluster_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 "encoding/json" 22 "fmt" 23 "os" 24 "strings" 25 "time" 26 27 "github.com/kubevela/pkg/controller/reconciler" 28 workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1" 29 . "github.com/onsi/ginkgo/v2" 30 . "github.com/onsi/gomega" 31 appsv1 "k8s.io/api/apps/v1" 32 v1 "k8s.io/api/authentication/v1" 33 corev1 "k8s.io/api/core/v1" 34 rbacv1 "k8s.io/api/rbac/v1" 35 kerrors "k8s.io/apimachinery/pkg/api/errors" 36 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 37 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 38 "k8s.io/apimachinery/pkg/runtime" 39 "k8s.io/apimachinery/pkg/types" 40 "k8s.io/client-go/tools/clientcmd" 41 "sigs.k8s.io/controller-runtime/pkg/client" 42 "sigs.k8s.io/yaml" 43 44 "github.com/kubevela/pkg/util/rand" 45 46 "github.com/oam-dev/kubevela/apis/core.oam.dev/common" 47 "github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha1" 48 "github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1" 49 kubevelatypes "github.com/oam-dev/kubevela/apis/types" 50 "github.com/oam-dev/kubevela/pkg/multicluster" 51 "github.com/oam-dev/kubevela/pkg/oam" 52 ) 53 54 func initializeContext() (hubCtx context.Context, workerCtx context.Context) { 55 hubCtx = context.Background() 56 workerCtx = multicluster.ContextWithClusterName(hubCtx, WorkerClusterName) 57 return 58 } 59 60 func initializeContextAndNamespace() (hubCtx context.Context, workerCtx context.Context, namespace string) { 61 hubCtx, workerCtx = initializeContext() 62 // initialize test namespace 63 namespace = "test-mc-" + rand.RandomString(4) 64 ns := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}} 65 Expect(k8sClient.Create(hubCtx, ns.DeepCopy())).Should(Succeed()) 66 Expect(k8sClient.Create(workerCtx, ns.DeepCopy())).Should(Succeed()) 67 return 68 } 69 70 func cleanUpNamespace(hubCtx context.Context, workerCtx context.Context, namespace string) { 71 hubNs := &corev1.Namespace{} 72 Expect(k8sClient.Get(hubCtx, types.NamespacedName{Name: namespace}, hubNs)).Should(Succeed()) 73 Expect(k8sClient.Delete(hubCtx, hubNs)).Should(Succeed()) 74 workerNs := &corev1.Namespace{} 75 Expect(k8sClient.Get(workerCtx, types.NamespacedName{Name: namespace}, workerNs)).Should(Succeed()) 76 Expect(k8sClient.Delete(workerCtx, workerNs)).Should(Succeed()) 77 } 78 79 var _ = Describe("Test multicluster scenario", func() { 80 81 Context("Test vela cluster command", func() { 82 83 It("Test join cluster by X509 kubeconfig, rename it and detach it.", func() { 84 const oldClusterName = "test-worker-cluster" 85 const newClusterName = "test-cluster-worker" 86 _, err := execCommand("cluster", "list") 87 Expect(err).Should(Succeed()) 88 _, err = execCommand("cluster", "join", "/tmp/worker.kubeconfig", "--name", oldClusterName) 89 Expect(err).Should(Succeed()) 90 _, err = execCommand("cluster", "join", "/tmp/worker.kubeconfig", "--name", oldClusterName, "-y") 91 Expect(err).Should(Succeed()) 92 out, err := execCommand("cluster", "list") 93 Expect(err).Should(Succeed()) 94 Expect(out).Should(ContainSubstring(oldClusterName)) 95 _, err = execCommand("cluster", "rename", oldClusterName, newClusterName) 96 Expect(err).Should(Succeed()) 97 out, err = execCommand("cluster", "list") 98 Expect(err).Should(Succeed()) 99 Expect(out).Should(ContainSubstring(newClusterName)) 100 _, err = execCommand("cluster", "detach", newClusterName) 101 Expect(err).Should(Succeed()) 102 out, err = execCommand("cluster", "list") 103 Expect(err).Should(Succeed()) 104 Expect(out).ShouldNot(ContainSubstring(newClusterName)) 105 }) 106 107 It("Test manage labels for cluster", func() { 108 _, err := execCommand("cluster", "labels", "add", WorkerClusterName, "purpose=test,creator=e2e") 109 Expect(err).Should(Succeed()) 110 out, err := execCommand("cluster", "list") 111 Expect(err).Should(Succeed()) 112 Expect(out).Should(ContainSubstring("purpose")) 113 _, err = execCommand("cluster", "labels", "del", WorkerClusterName, "purpose") 114 Expect(err).Should(Succeed()) 115 out, err = execCommand("cluster", "list") 116 Expect(err).Should(Succeed()) 117 Expect(out).ShouldNot(ContainSubstring("purpose")) 118 }) 119 120 It("Test alias for cluster", func() { 121 _, err := execCommand("cluster", "alias", WorkerClusterName, "alias-worker") 122 Expect(err).Should(Succeed()) 123 out, err := execCommand("cluster", "list") 124 Expect(err).Should(Succeed()) 125 Expect(out).Should(ContainSubstring("alias-worker")) 126 }) 127 128 It("Test generate service account kubeconfig", func() { 129 _, workerCtx := initializeContext() 130 By("create service account kubeconfig in worker cluster") 131 key := time.Now().UnixNano() 132 serviceAccountName := fmt.Sprintf("test-service-account-%d", key) 133 serviceAccountNamespace := "kube-system" 134 serviceAccount := &corev1.ServiceAccount{ 135 ObjectMeta: metav1.ObjectMeta{Namespace: serviceAccountNamespace, Name: serviceAccountName}, 136 } 137 Expect(k8sClient.Create(workerCtx, serviceAccount)).Should(Succeed()) 138 defer func() { 139 Expect(k8sClient.Get(workerCtx, types.NamespacedName{Namespace: "kube-system", Name: serviceAccountName}, serviceAccount)).Should(Succeed()) 140 Expect(k8sClient.Delete(workerCtx, serviceAccount)).Should(Succeed()) 141 }() 142 clusterRoleBindingName := fmt.Sprintf("test-cluster-role-binding-%d", key) 143 clusterRoleBinding := &rbacv1.ClusterRoleBinding{ 144 ObjectMeta: metav1.ObjectMeta{Name: clusterRoleBindingName}, 145 Subjects: []rbacv1.Subject{{Kind: "ServiceAccount", Name: serviceAccountName, Namespace: serviceAccountNamespace}}, 146 RoleRef: rbacv1.RoleRef{Name: "cluster-admin", APIGroup: "rbac.authorization.k8s.io", Kind: "ClusterRole"}, 147 } 148 Expect(k8sClient.Create(workerCtx, clusterRoleBinding)).Should(Succeed()) 149 defer func() { 150 Expect(k8sClient.Get(workerCtx, types.NamespacedName{Namespace: serviceAccountNamespace, Name: clusterRoleBindingName}, clusterRoleBinding)).Should(Succeed()) 151 Expect(k8sClient.Delete(workerCtx, clusterRoleBinding)).Should(Succeed()) 152 }() 153 serviceAccount = &corev1.ServiceAccount{} 154 By("Generating a token for SA") 155 tr := &v1.TokenRequest{} 156 token, err := k8sCli.CoreV1().ServiceAccounts(serviceAccountNamespace).CreateToken(workerCtx, serviceAccountName, tr, metav1.CreateOptions{}) 157 Expect(err).Should(BeNil()) 158 config, err := clientcmd.LoadFromFile(WorkerClusterKubeConfigPath) 159 Expect(err).Should(Succeed()) 160 currentContext, ok := config.Contexts[config.CurrentContext] 161 Expect(ok).Should(BeTrue()) 162 authInfo, ok := config.AuthInfos[currentContext.AuthInfo] 163 Expect(ok).Should(BeTrue()) 164 authInfo.Token = token.Status.Token 165 authInfo.ClientKeyData = nil 166 authInfo.ClientCertificateData = nil 167 kubeconfigFilePath := fmt.Sprintf("/tmp/worker.sa-%d.kubeconfig", key) 168 Expect(clientcmd.WriteToFile(*config, kubeconfigFilePath)).Should(Succeed()) 169 defer func() { 170 Expect(os.Remove(kubeconfigFilePath)).Should(Succeed()) 171 }() 172 // try to join cluster with service account token based kubeconfig 173 clusterName := fmt.Sprintf("cluster-sa-%d", key) 174 _, err = execCommand("cluster", "join", kubeconfigFilePath, "--name", clusterName) 175 Expect(err).Should(Succeed()) 176 _, err = execCommand("cluster", "detach", clusterName) 177 Expect(err).Should(Succeed()) 178 }) 179 180 It("Test vela cluster export-config", func() { 181 out, err := execCommand("cluster", "export-config") 182 Expect(err).Should(Succeed()) 183 Expect(out).Should(ContainSubstring("name: " + WorkerClusterName)) 184 }) 185 186 }) 187 188 Context("Test multi-cluster Application", func() { 189 190 var namespace string 191 var testNamespace string 192 var prodNamespace string 193 var hubCtx context.Context 194 var workerCtx context.Context 195 196 BeforeEach(func() { 197 hubCtx, workerCtx, namespace = initializeContextAndNamespace() 198 _, _, testNamespace = initializeContextAndNamespace() 199 _, _, prodNamespace = initializeContextAndNamespace() 200 }) 201 202 AfterEach(func() { 203 cleanUpNamespace(hubCtx, workerCtx, namespace) 204 cleanUpNamespace(hubCtx, workerCtx, testNamespace) 205 cleanUpNamespace(hubCtx, workerCtx, prodNamespace) 206 }) 207 208 It("Test deploy multi-cluster application with target", func() { 209 By("apply application") 210 app := &v1beta1.Application{ 211 ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: "test-app-target"}, 212 Spec: v1beta1.ApplicationSpec{ 213 Components: []common.ApplicationComponent{{ 214 Name: "test-busybox", 215 Type: "webservice", 216 Properties: &runtime.RawExtension{Raw: []byte(`{"image":"busybox","cmd":["sleep","86400"]}`)}, 217 }}, 218 Policies: []v1beta1.AppPolicy{{ 219 Name: "topology-local", 220 Type: "topology", 221 Properties: &runtime.RawExtension{Raw: []byte(fmt.Sprintf(`{"clusters":["local"],"namespace":"%s"}`, testNamespace))}, 222 }, { 223 Name: "topology-remote", 224 Type: "topology", 225 Properties: &runtime.RawExtension{Raw: []byte(fmt.Sprintf(`{"clusters":["%s"],"namespace":"%s"}`, WorkerClusterName, prodNamespace))}, 226 }}, 227 }, 228 } 229 Expect(k8sClient.Create(hubCtx, app)).Should(Succeed()) 230 Eventually(func(g Gomega) { 231 g.Expect(k8sClient.Get(hubCtx, types.NamespacedName{Name: "test-busybox", Namespace: testNamespace}, &appsv1.Deployment{})).Should(Succeed()) 232 g.Expect(k8sClient.Get(workerCtx, types.NamespacedName{Name: "test-busybox", Namespace: prodNamespace}, &appsv1.Deployment{})).Should(Succeed()) 233 }, time.Minute).Should(Succeed()) 234 }) 235 236 It("Test re-deploy application with old revisions", func() { 237 By("apply application") 238 app := &v1beta1.Application{ 239 ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: "test-app-target"}, 240 Spec: v1beta1.ApplicationSpec{ 241 Components: []common.ApplicationComponent{{ 242 Name: "test-busybox", 243 Type: "webservice", 244 Properties: &runtime.RawExtension{Raw: []byte(`{"image":"busybox","cmd":["sleep","86400"]}`)}, 245 }}, 246 Policies: []v1beta1.AppPolicy{{ 247 Name: "topology-local", 248 Type: "topology", 249 Properties: &runtime.RawExtension{Raw: []byte(fmt.Sprintf(`{"clusters":["local"],"namespace":"%s"}`, testNamespace))}, 250 }, 251 }}} 252 oam.SetPublishVersion(app, "alpha") 253 Expect(k8sClient.Create(hubCtx, app)).Should(Succeed()) 254 Eventually(func(g Gomega) { 255 g.Expect(k8sClient.Get(hubCtx, types.NamespacedName{Name: "test-busybox", Namespace: testNamespace}, &appsv1.Deployment{})).Should(Succeed()) 256 }, time.Minute).Should(Succeed()) 257 258 By("update application to new version") 259 appKey := client.ObjectKeyFromObject(app) 260 Eventually(func(g Gomega) { 261 g.Expect(k8sClient.Get(hubCtx, appKey, app)).Should(Succeed()) 262 app.Spec.Components[0].Name = "test-busybox-v2" 263 oam.SetPublishVersion(app, "beta") 264 g.Expect(k8sClient.Update(hubCtx, app)).Should(Succeed()) 265 }, 15*time.Second).Should(Succeed()) 266 Eventually(func(g Gomega) { 267 g.Expect(k8sClient.Get(hubCtx, types.NamespacedName{Name: "test-busybox-v2", Namespace: testNamespace}, &appsv1.Deployment{})).Should(Succeed()) 268 err := k8sClient.Get(hubCtx, types.NamespacedName{Name: "test-busybox", Namespace: testNamespace}, &appsv1.Deployment{}) 269 g.Expect(kerrors.IsNotFound(err)).Should(BeTrue()) 270 }, time.Minute).Should(Succeed()) 271 272 By("Re-publish application to v1") 273 _, err := execCommand("up", appKey.Name, "-n", appKey.Namespace, "--revision", appKey.Name+"-v1", "--publish-version", "v1.0") 274 Expect(err).Should(Succeed()) 275 276 Eventually(func(g Gomega) { 277 g.Expect(k8sClient.Get(hubCtx, types.NamespacedName{Name: "test-busybox", Namespace: testNamespace}, &appsv1.Deployment{})).Should(Succeed()) 278 err := k8sClient.Get(hubCtx, types.NamespacedName{Name: "test-busybox-v2", Namespace: testNamespace}, &appsv1.Deployment{}) 279 g.Expect(kerrors.IsNotFound(err)).Should(BeTrue()) 280 }, 2*time.Minute).Should(Succeed()) 281 }) 282 283 It("Test applications sharing resources", func() { 284 createApp := func(name string) *v1beta1.Application { 285 return &v1beta1.Application{ 286 ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: name}, 287 Spec: v1beta1.ApplicationSpec{ 288 Components: []common.ApplicationComponent{{ 289 Name: "shared-resource-" + name, 290 Type: "k8s-objects", 291 Properties: &runtime.RawExtension{Raw: []byte(`{"objects":[{"apiVersion":"v1","kind":"ConfigMap","metadata":{"name":"shared"},"data":{"key":"value"}}]}`)}, 292 }, { 293 Name: "no-shared-resource-" + name, 294 Type: "k8s-objects", 295 Properties: &runtime.RawExtension{Raw: []byte(`{"objects":[{"apiVersion":"v1","kind":"ConfigMap","metadata":{"name":"non-shared-` + name + `"},"data":{"key":"value"}}]}`)}, 296 }}, 297 Policies: []v1beta1.AppPolicy{{ 298 Type: "shared-resource", 299 Name: "shared-resource", 300 Properties: &runtime.RawExtension{Raw: []byte(`{"rules":[{"selector":{"componentNames":["shared-resource-` + name + `"]}}]}`)}, 301 }}, 302 }, 303 } 304 } 305 app1 := createApp("app1") 306 Expect(k8sClient.Create(hubCtx, app1)).Should(Succeed()) 307 Eventually(func(g Gomega) { 308 g.Expect(k8sClient.Get(hubCtx, client.ObjectKeyFromObject(app1), app1)).Should(Succeed()) 309 g.Expect(app1.Status.Phase).Should(Equal(common.ApplicationRunning)) 310 }, 10*time.Second).Should(Succeed()) 311 app2 := createApp("app2") 312 Expect(k8sClient.Create(hubCtx, app2)).Should(Succeed()) 313 Eventually(func(g Gomega) { 314 g.Expect(k8sClient.Get(hubCtx, client.ObjectKeyFromObject(app2), app2)).Should(Succeed()) 315 g.Expect(app2.Status.Phase).Should(Equal(common.ApplicationRunning)) 316 }, 10*time.Second).Should(Succeed()) 317 app3 := createApp("app3") 318 Expect(k8sClient.Create(hubCtx, app3)).Should(Succeed()) 319 Eventually(func(g Gomega) { 320 g.Expect(k8sClient.Get(hubCtx, client.ObjectKeyFromObject(app3), app3)).Should(Succeed()) 321 g.Expect(app3.Status.Phase).Should(Equal(common.ApplicationRunning)) 322 }, 10*time.Second).Should(Succeed()) 323 Eventually(func(g Gomega) { 324 cm := &corev1.ConfigMap{} 325 g.Expect(k8sClient.Get(hubCtx, types.NamespacedName{Namespace: namespace, Name: "shared"}, cm)).Should(Succeed()) 326 g.Expect(cm.GetAnnotations()[oam.AnnotationAppSharedBy]).Should(SatisfyAll(ContainSubstring("app1"), ContainSubstring("app2"), ContainSubstring("app3"))) 327 g.Expect(cm.GetLabels()[oam.LabelAppName]).Should(SatisfyAny(Equal("app1"), Equal("app2"), Equal("app3"))) 328 g.Expect(k8sClient.Get(hubCtx, types.NamespacedName{Namespace: namespace, Name: "non-shared-app1"}, &corev1.ConfigMap{})).Should(Succeed()) 329 g.Expect(k8sClient.Get(hubCtx, types.NamespacedName{Namespace: namespace, Name: "non-shared-app2"}, &corev1.ConfigMap{})).Should(Succeed()) 330 g.Expect(k8sClient.Get(hubCtx, types.NamespacedName{Namespace: namespace, Name: "non-shared-app3"}, &corev1.ConfigMap{})).Should(Succeed()) 331 }, 45*time.Second).Should(Succeed()) 332 Expect(k8sClient.Delete(hubCtx, app2)).Should(Succeed()) 333 Eventually(func(g Gomega) { 334 cm := &corev1.ConfigMap{} 335 g.Expect(k8sClient.Get(hubCtx, types.NamespacedName{Namespace: namespace, Name: "shared"}, cm)).Should(Succeed()) 336 g.Expect(cm.GetAnnotations()[oam.AnnotationAppSharedBy]).Should(SatisfyAll(ContainSubstring("app1"), ContainSubstring("app3"))) 337 g.Expect(cm.GetAnnotations()[oam.AnnotationAppSharedBy]).ShouldNot(SatisfyAny(ContainSubstring("app2"))) 338 g.Expect(cm.GetLabels()[oam.LabelAppName]).Should(SatisfyAny(Equal("app1"), Equal("app3"))) 339 g.Expect(k8sClient.Get(hubCtx, types.NamespacedName{Namespace: namespace, Name: "non-shared-app1"}, &corev1.ConfigMap{})).Should(Succeed()) 340 g.Expect(k8sClient.Get(hubCtx, types.NamespacedName{Namespace: namespace, Name: "non-shared-app2"}, &corev1.ConfigMap{})).Should(Satisfy(kerrors.IsNotFound)) 341 g.Expect(k8sClient.Get(hubCtx, types.NamespacedName{Namespace: namespace, Name: "non-shared-app3"}, &corev1.ConfigMap{})).Should(Succeed()) 342 }, 10*time.Second).Should(Succeed()) 343 Expect(k8sClient.Delete(hubCtx, app1)).Should(Succeed()) 344 Eventually(func(g Gomega) { 345 cm := &corev1.ConfigMap{} 346 g.Expect(k8sClient.Get(hubCtx, types.NamespacedName{Namespace: namespace, Name: "shared"}, cm)).Should(Succeed()) 347 g.Expect(cm.GetAnnotations()[oam.AnnotationAppSharedBy]).Should(SatisfyAll(ContainSubstring("app3"))) 348 g.Expect(cm.GetAnnotations()[oam.AnnotationAppSharedBy]).ShouldNot(SatisfyAny(ContainSubstring("app1"), ContainSubstring("app2"))) 349 g.Expect(cm.GetLabels()[oam.LabelAppName]).Should(Equal("app3")) 350 g.Expect(k8sClient.Get(hubCtx, types.NamespacedName{Namespace: namespace, Name: "non-shared-app1"}, &corev1.ConfigMap{})).Should(Satisfy(kerrors.IsNotFound)) 351 g.Expect(k8sClient.Get(hubCtx, types.NamespacedName{Namespace: namespace, Name: "non-shared-app3"}, &corev1.ConfigMap{})).Should(Succeed()) 352 }, 10*time.Second).Should(Succeed()) 353 Expect(k8sClient.Delete(hubCtx, app3)).Should(Succeed()) 354 Eventually(func(g Gomega) { 355 g.Expect(k8sClient.Get(hubCtx, types.NamespacedName{Namespace: namespace, Name: "shared"}, &corev1.ConfigMap{})).Should(Satisfy(kerrors.IsNotFound)) 356 g.Expect(k8sClient.Get(hubCtx, types.NamespacedName{Namespace: namespace, Name: "non-shared-app3"}, &corev1.ConfigMap{})).Should(Satisfy(kerrors.IsNotFound)) 357 }, 10*time.Second).Should(Succeed()) 358 }) 359 360 It("Test applications with bad resource", func() { 361 bs, err := os.ReadFile("./testdata/app/app-bad-resource.yaml") 362 Expect(err).Should(Succeed()) 363 appYaml := strings.ReplaceAll(string(bs), "TEST_NAMESPACE", testNamespace) 364 app := &v1beta1.Application{} 365 Expect(yaml.Unmarshal([]byte(appYaml), app)).Should(Succeed()) 366 ctx := context.Background() 367 Expect(k8sClient.Create(ctx, app)).Should(Succeed()) 368 Eventually(func(g Gomega) { 369 g.Expect(k8sClient.Get(hubCtx, client.ObjectKeyFromObject(app), app)).Should(Succeed()) 370 g.Expect(app.Status.Phase).Should(Equal(common.ApplicationRunningWorkflow)) 371 g.Expect(len(app.Status.Workflow.Steps) > 0).Should(BeTrue()) 372 g.Expect(app.Status.Workflow.Steps[0].Message).Should(ContainSubstring("is invalid")) 373 rts := &v1beta1.ResourceTrackerList{} 374 g.Expect(k8sClient.List(hubCtx, rts, client.MatchingLabels{oam.LabelAppName: app.Name, oam.LabelAppNamespace: app.Namespace})).Should(Succeed()) 375 g.Expect(len(rts.Items)).Should(Equal(0)) 376 }, 20*time.Second).Should(Succeed()) 377 Expect(k8sClient.Delete(ctx, app)).Should(Succeed()) 378 Eventually(func(g Gomega) { 379 g.Expect(k8sClient.Get(hubCtx, client.ObjectKeyFromObject(app), app)).Should(Satisfy(kerrors.IsNotFound)) 380 }, 10*time.Second).Should(Succeed()) 381 }) 382 383 It("Test applications with env and storage trait", func() { 384 bs, err := os.ReadFile("./testdata/app/app-with-env-and-storage.yaml") 385 Expect(err).Should(Succeed()) 386 appYaml := strings.ReplaceAll(string(bs), "TEST_NAMESPACE", testNamespace) 387 app := &v1beta1.Application{} 388 Expect(yaml.Unmarshal([]byte(appYaml), app)).Should(Succeed()) 389 Expect(k8sClient.Create(hubCtx, app)).Should(Succeed()) 390 Eventually(func(g Gomega) { 391 g.Expect(k8sClient.Get(hubCtx, client.ObjectKeyFromObject(app), app)).Should(Succeed()) 392 g.Expect(app.Status.Phase).Should(Equal(common.ApplicationRunning)) 393 }, 20*time.Second).Should(Succeed()) 394 }) 395 396 It("Test applications with gc policy change (onAppUpdate -> never)", func() { 397 bs, err := os.ReadFile("./testdata/app/app-gc-policy-change.yaml") 398 Expect(err).Should(Succeed()) 399 appYaml := strings.ReplaceAll(string(bs), "TEST_NAMESPACE", testNamespace) 400 app := &v1beta1.Application{} 401 Expect(yaml.Unmarshal([]byte(appYaml), app)).Should(Succeed()) 402 Expect(k8sClient.Create(hubCtx, app)).Should(Succeed()) 403 Eventually(func(g Gomega) { 404 g.Expect(k8sClient.Get(hubCtx, client.ObjectKeyFromObject(app), app)).Should(Succeed()) 405 g.Expect(app.Status.Phase).Should(Equal(common.ApplicationRunning)) 406 }, 20*time.Second).Should(Succeed()) 407 408 By("update gc policy to never") 409 Eventually(func(g Gomega) { 410 g.Expect(k8sClient.Get(hubCtx, client.ObjectKeyFromObject(app), app)) 411 gcPolicy := &v1alpha1.GarbageCollectPolicySpec{} 412 g.Expect(json.Unmarshal(app.Spec.Policies[0].Properties.Raw, gcPolicy)).Should(Succeed()) 413 gcPolicy.Rules[0].Strategy = v1alpha1.GarbageCollectStrategyNever 414 bs, err = json.Marshal(gcPolicy) 415 g.Expect(err).Should(Succeed()) 416 app.Spec.Policies[0].Properties = &runtime.RawExtension{Raw: bs} 417 g.Expect(k8sClient.Update(hubCtx, app)).Should(Succeed()) 418 }, 10*time.Second).Should(Succeed()) 419 420 By("check app updated and resource still exists") 421 Eventually(func(g Gomega) { 422 g.Expect(k8sClient.Get(hubCtx, client.ObjectKeyFromObject(app), app)).Should(Succeed()) 423 g.Expect(app.Status.ObservedGeneration).Should(Equal(int64(2))) 424 g.Expect(app.Status.Phase).Should(Equal(common.ApplicationRunning)) 425 g.Expect(k8sClient.Get(hubCtx, types.NamespacedName{Namespace: testNamespace, Name: "gc-policy-test"}, &corev1.ConfigMap{})).Should(Succeed()) 426 }, 20*time.Second).Should(Succeed()) 427 428 By("update app to new object") 429 Eventually(func(g Gomega) { 430 g.Expect(k8sClient.Get(hubCtx, client.ObjectKeyFromObject(app), app)) 431 app.Spec.Components[0].Properties = &runtime.RawExtension{Raw: []byte(`{"objects":[{"apiVersion":"v1","kind":"ConfigMap","metadata":{"name":"another"},"data":{"key":"new-val"}}]}`)} 432 g.Expect(k8sClient.Update(hubCtx, app)).Should(Succeed()) 433 }).Should(Succeed()) 434 435 By("check app updated and resource still exists") 436 Eventually(func(g Gomega) { 437 g.Expect(k8sClient.Get(hubCtx, client.ObjectKeyFromObject(app), app)).Should(Succeed()) 438 g.Expect(app.Status.ObservedGeneration).Should(Equal(int64(3))) 439 g.Expect(app.Status.Phase).Should(Equal(common.ApplicationRunning)) 440 g.Expect(k8sClient.Get(hubCtx, types.NamespacedName{Namespace: testNamespace, Name: "gc-policy-test"}, &corev1.ConfigMap{})).Should(Succeed()) 441 g.Expect(k8sClient.Get(hubCtx, types.NamespacedName{Namespace: testNamespace, Name: "another"}, &corev1.ConfigMap{})).Should(Succeed()) 442 }, 20*time.Second).Should(Succeed()) 443 444 By("delete app and check resource") 445 Eventually(func(g Gomega) { 446 g.Expect(client.IgnoreNotFound(k8sClient.Delete(hubCtx, app))).Should(Succeed()) 447 g.Expect(k8sClient.Get(hubCtx, types.NamespacedName{Namespace: testNamespace, Name: "gc-policy-test"}, &corev1.ConfigMap{})).Should(Succeed()) 448 g.Expect(k8sClient.Get(hubCtx, types.NamespacedName{Namespace: testNamespace, Name: "another"}, &corev1.ConfigMap{})).Should(Satisfy(kerrors.IsNotFound)) 449 }) 450 }) 451 452 It("Test Application with env in webservice and labels & storage trait", func() { 453 bs, err := os.ReadFile("./testdata/app/app-with-env-labels-storage.yaml") 454 Expect(err).Should(Succeed()) 455 app := &v1beta1.Application{} 456 Expect(yaml.Unmarshal(bs, app)).Should(Succeed()) 457 app.SetNamespace(namespace) 458 Expect(k8sClient.Create(hubCtx, app)).Should(Succeed()) 459 deploy := &appsv1.Deployment{} 460 Eventually(func(g Gomega) { 461 g.Expect(k8sClient.Get(hubCtx, types.NamespacedName{Namespace: namespace, Name: "test"}, deploy)).Should(Succeed()) 462 }, 15*time.Second).Should(Succeed()) 463 Expect(deploy.GetLabels()["key"]).Should(Equal("val")) 464 Expect(len(deploy.Spec.Template.Spec.Containers[0].Env)).Should(Equal(1)) 465 Expect(deploy.Spec.Template.Spec.Containers[0].Env[0].Name).Should(Equal("testKey")) 466 Expect(deploy.Spec.Template.Spec.Containers[0].Env[0].Value).Should(Equal("testValue")) 467 Expect(len(deploy.Spec.Template.Spec.Volumes)).Should(Equal(1)) 468 }) 469 470 It("Test application with collect-service-endpoint and export-data", func() { 471 By("create application") 472 bs, err := os.ReadFile("./testdata/app/app-collect-service-endpoint-and-export.yaml") 473 Expect(err).Should(Succeed()) 474 app := &v1beta1.Application{} 475 Expect(yaml.Unmarshal(bs, app)).Should(Succeed()) 476 app.SetNamespace(testNamespace) 477 Expect(k8sClient.Create(hubCtx, app)).Should(Succeed()) 478 Eventually(func(g Gomega) { 479 g.Expect(k8sClient.Get(hubCtx, client.ObjectKeyFromObject(app), app)).Should(Succeed()) 480 g.Expect(app.Status.Phase).Should(Equal(common.ApplicationRunning)) 481 }, 20*time.Second).Should(Succeed()) 482 483 By("test dispatched resource") 484 svc := &corev1.Service{} 485 Expect(k8sClient.Get(hubCtx, client.ObjectKey{Namespace: testNamespace, Name: "busybox"}, svc)).Should(Succeed()) 486 host := "busybox." + testNamespace 487 cm := &corev1.ConfigMap{} 488 Expect(k8sClient.Get(hubCtx, client.ObjectKey{Namespace: testNamespace, Name: app.Name}, cm)).Should(Succeed()) 489 Expect(cm.Data["host"]).Should(Equal(host)) 490 Expect(k8sClient.Get(workerCtx, client.ObjectKey{Namespace: testNamespace, Name: app.Name}, cm)).Should(Succeed()) 491 Expect(cm.Data["host"]).Should(Equal(host)) 492 }) 493 494 It("Test application with workflow change will rerun", func() { 495 By("create application") 496 bs, err := os.ReadFile("./testdata/app/app-lite-with-workflow.yaml") 497 Expect(err).Should(Succeed()) 498 app := &v1beta1.Application{} 499 Expect(yaml.Unmarshal(bs, app)).Should(Succeed()) 500 app.SetNamespace(testNamespace) 501 Expect(k8sClient.Create(hubCtx, app)).Should(Succeed()) 502 Eventually(func(g Gomega) { 503 g.Expect(k8sClient.Get(hubCtx, client.ObjectKeyFromObject(app), app)).Should(Succeed()) 504 g.Expect(app.Status.Phase).Should(Equal(common.ApplicationRunning)) 505 }, 20*time.Second).Should(Succeed()) 506 Expect(k8sClient.Get(hubCtx, client.ObjectKey{Namespace: testNamespace, Name: "data-worker"}, &appsv1.Deployment{})).Should(Succeed()) 507 Eventually(func(g Gomega) { 508 g.Expect(k8sClient.Get(hubCtx, client.ObjectKeyFromObject(app), app)).Should(Succeed()) 509 app.Spec.Workflow.Steps[0].Properties = &runtime.RawExtension{Raw: []byte(`{"policies":["worker"]}`)} 510 g.Expect(k8sClient.Update(hubCtx, app)).Should(Succeed()) 511 }, 10*time.Second).Should(Succeed()) 512 Eventually(func(g Gomega) { 513 g.Expect(k8sClient.Get(hubCtx, client.ObjectKey{Namespace: testNamespace, Name: "data-worker"}, &appsv1.Deployment{})).Should(Satisfy(kerrors.IsNotFound)) 514 g.Expect(k8sClient.Get(workerCtx, client.ObjectKey{Namespace: testNamespace, Name: "data-worker"}, &appsv1.Deployment{})).Should(Succeed()) 515 }, 20*time.Second).Should(Succeed()) 516 }) 517 518 It("Test application with apply-component and cluster", func() { 519 By("create application") 520 bs, err := os.ReadFile("./testdata/app/app-component-with-cluster.yaml") 521 Expect(err).Should(Succeed()) 522 app := &v1beta1.Application{} 523 Expect(yaml.Unmarshal(bs, app)).Should(Succeed()) 524 app.SetNamespace(testNamespace) 525 Expect(k8sClient.Create(hubCtx, app)).Should(Succeed()) 526 Eventually(func(g Gomega) { 527 g.Expect(k8sClient.Get(hubCtx, client.ObjectKeyFromObject(app), app)).Should(Succeed()) 528 g.Expect(app.Status.Phase).Should(Equal(common.ApplicationRunning)) 529 }, 20*time.Second).Should(Succeed()) 530 Expect(k8sClient.Get(workerCtx, client.ObjectKey{Namespace: testNamespace, Name: "component-cluster"}, &appsv1.Deployment{})).Should(Succeed()) 531 }) 532 533 It("Test application with component using cluster context", func() { 534 By("Create definition") 535 bs, err := os.ReadFile("./testdata/def/cluster-config.yaml") 536 Expect(err).Should(Succeed()) 537 def := &v1beta1.ComponentDefinition{} 538 Expect(yaml.Unmarshal(bs, def)).Should(Succeed()) 539 def.SetNamespace(kubevelatypes.DefaultKubeVelaNS) 540 Expect(k8sClient.Create(hubCtx, def)).Should(Succeed()) 541 defKey := client.ObjectKeyFromObject(def) 542 Eventually(func(g Gomega) { 543 g.Expect(k8sClient.Get(hubCtx, defKey, def)).Should(Succeed()) 544 }, 5*time.Second).Should(Succeed()) 545 bs, err = os.ReadFile("./testdata/app/app-component-with-cluster-context.yaml") 546 Expect(err).Should(Succeed()) 547 app := &v1beta1.Application{} 548 Expect(yaml.Unmarshal(bs, app)).Should(Succeed()) 549 app.SetNamespace(testNamespace) 550 Eventually(func(g Gomega) { // informer may have latency for the added definition 551 g.Expect(k8sClient.Create(hubCtx, app)).Should(Succeed()) 552 }).WithTimeout(10 * time.Second).WithPolling(2 * time.Second).Should(Succeed()) 553 key := client.ObjectKeyFromObject(app) 554 Eventually(func(g Gomega) { 555 g.Expect(k8sClient.Get(hubCtx, key, app)).Should(Succeed()) 556 g.Expect(app.Status.Phase).Should(Equal(common.ApplicationRunning)) 557 }, 20*time.Second).Should(Succeed()) 558 cm := &corev1.ConfigMap{} 559 Expect(k8sClient.Get(hubCtx, types.NamespacedName{Namespace: testNamespace, Name: "test"}, cm)).Should(Succeed()) 560 Expect(cm.Data["cluster"]).Should(Equal("local")) 561 Expect(k8sClient.Get(workerCtx, types.NamespacedName{Namespace: testNamespace, Name: "test"}, cm)).Should(Succeed()) 562 Expect(cm.Data["cluster"]).Should(Equal("cluster-worker")) 563 Expect(k8sClient.Delete(hubCtx, def)).Should(Succeed()) 564 }) 565 566 It("Test application with read-only policy", func() { 567 By("create deployment") 568 bs, err := os.ReadFile("./testdata/app/standalone/deployment-busybox.yaml") 569 Expect(err).Should(Succeed()) 570 deploy := &appsv1.Deployment{} 571 Expect(yaml.Unmarshal(bs, deploy)).Should(Succeed()) 572 deploy.SetNamespace(namespace) 573 Expect(k8sClient.Create(hubCtx, deploy)).Should(Succeed()) 574 By("create application") 575 bs, err = os.ReadFile("./testdata/app/app-readonly.yaml") 576 Expect(err).Should(Succeed()) 577 app := &v1beta1.Application{} 578 Expect(yaml.Unmarshal(bs, app)).Should(Succeed()) 579 app.SetNamespace(namespace) 580 Expect(k8sClient.Create(hubCtx, app)).Should(Succeed()) 581 Eventually(func(g Gomega) { 582 g.Expect(k8sClient.Get(hubCtx, client.ObjectKeyFromObject(app), app)).Should(Succeed()) 583 g.Expect(app.Status.Workflow).ShouldNot(BeNil()) 584 g.Expect(len(app.Status.Workflow.Steps)).ShouldNot(Equal(0)) 585 g.Expect(app.Status.Workflow.Steps[0].Phase).Should(Equal(workflowv1alpha1.WorkflowStepPhaseFailed)) 586 }, 20*time.Second).Should(Succeed()) 587 By("update application") 588 Eventually(func(g Gomega) { 589 g.Expect(k8sClient.Get(hubCtx, client.ObjectKeyFromObject(app), app)).Should(Succeed()) 590 app.Spec.Components[0].Name = "busybox-ref" 591 g.Expect(k8sClient.Update(hubCtx, app)).Should(Succeed()) 592 }, 20*time.Second).Should(Succeed()) 593 Eventually(func(g Gomega) { 594 g.Expect(k8sClient.Get(hubCtx, client.ObjectKeyFromObject(app), app)).Should(Succeed()) 595 g.Expect(app.Status.Phase).Should(Equal(common.ApplicationRunning)) 596 }, 20*time.Second).Should(Succeed()) 597 By("delete application") 598 appKey := client.ObjectKeyFromObject(app) 599 deployKey := client.ObjectKeyFromObject(deploy) 600 Expect(k8sClient.Delete(hubCtx, app)).Should(Succeed()) 601 Eventually(func(g Gomega) { 602 g.Expect(kerrors.IsNotFound(k8sClient.Get(hubCtx, appKey, app))).Should(BeTrue()) 603 }, 20*time.Second).Should(Succeed()) 604 Expect(k8sClient.Get(hubCtx, deployKey, deploy)).Should(Succeed()) 605 }) 606 607 It("Test application with take-over policy", func() { 608 By("create deployment") 609 bs, err := os.ReadFile("./testdata/app/standalone/deployment-busybox.yaml") 610 Expect(err).Should(Succeed()) 611 deploy := &appsv1.Deployment{} 612 Expect(yaml.Unmarshal(bs, deploy)).Should(Succeed()) 613 deploy.SetNamespace(namespace) 614 Expect(k8sClient.Create(hubCtx, deploy)).Should(Succeed()) 615 By("create application") 616 bs, err = os.ReadFile("./testdata/app/app-takeover.yaml") 617 Expect(err).Should(Succeed()) 618 app := &v1beta1.Application{} 619 Expect(yaml.Unmarshal(bs, app)).Should(Succeed()) 620 app.SetNamespace(namespace) 621 Expect(k8sClient.Create(hubCtx, app)).Should(Succeed()) 622 Eventually(func(g Gomega) { 623 g.Expect(k8sClient.Get(hubCtx, client.ObjectKeyFromObject(app), app)).Should(Succeed()) 624 g.Expect(app.Status.Phase).Should(Equal(common.ApplicationRunning)) 625 }, 20*time.Second).Should(Succeed()) 626 By("delete application") 627 appKey := client.ObjectKeyFromObject(app) 628 deployKey := client.ObjectKeyFromObject(deploy) 629 Expect(k8sClient.Delete(hubCtx, app)).Should(Succeed()) 630 Eventually(func(g Gomega) { 631 g.Expect(kerrors.IsNotFound(k8sClient.Get(hubCtx, appKey, app))).Should(BeTrue()) 632 g.Expect(kerrors.IsNotFound(k8sClient.Get(hubCtx, deployKey, deploy))).Should(BeTrue()) 633 }, 20*time.Second).Should(Succeed()) 634 }) 635 636 It("Test application with input/output in deploy step", func() { 637 By("create application") 638 bs, err := os.ReadFile("./testdata/app/app-deploy-io.yaml") 639 Expect(err).Should(Succeed()) 640 app := &v1beta1.Application{} 641 Expect(yaml.Unmarshal(bs, app)).Should(Succeed()) 642 app.SetNamespace(namespace) 643 Expect(k8sClient.Create(hubCtx, app)).Should(Succeed()) 644 Eventually(func(g Gomega) { 645 g.Expect(k8sClient.Get(hubCtx, client.ObjectKeyFromObject(app), app)).Should(Succeed()) 646 g.Expect(app.Status.Phase).Should(Equal(common.ApplicationRunning)) 647 }, 30*time.Second).Should(Succeed()) 648 649 By("Check input/output work properly") 650 cm := &corev1.ConfigMap{} 651 cmKey := client.ObjectKey{Namespace: namespace, Name: "deployment-msg"} 652 var ( 653 ipLocal string 654 ipWorker string 655 ) 656 Eventually(func(g Gomega) { 657 g.Expect(k8sClient.Get(hubCtx, cmKey, cm)).Should(Succeed()) 658 g.Expect(cm.Data["msg"]).Should(Equal("Deployment has minimum availability.")) 659 ipLocal = cm.Data["ip"] 660 g.Expect(ipLocal).ShouldNot(BeEmpty()) 661 }, 20*time.Second).Should(Succeed()) 662 Eventually(func(g Gomega) { 663 g.Expect(k8sClient.Get(workerCtx, cmKey, cm)).Should(Succeed()) 664 g.Expect(cm.Data["msg"]).Should(Equal("Deployment has minimum availability.")) 665 ipWorker = cm.Data["ip"] 666 g.Expect(ipWorker).ShouldNot(BeEmpty()) 667 }, 20*time.Second).Should(Succeed()) 668 Expect(ipLocal).ShouldNot(Equal(ipWorker)) 669 670 By("delete application") 671 appKey := client.ObjectKeyFromObject(app) 672 Expect(k8sClient.Delete(hubCtx, app)).Should(Succeed()) 673 Eventually(func(g Gomega) { 674 g.Expect(kerrors.IsNotFound(k8sClient.Get(hubCtx, appKey, app))).Should(BeTrue()) 675 }, 20*time.Second).Should(Succeed()) 676 }) 677 678 It("Test application with failed gc and restart workflow", func() { 679 By("duplicate cluster") 680 secret := &corev1.Secret{} 681 const secretName = "disconnection-test" 682 Expect(k8sClient.Get(hubCtx, types.NamespacedName{Namespace: kubevelatypes.DefaultKubeVelaNS, Name: WorkerClusterName}, secret)).Should(Succeed()) 683 secret.SetName(secretName) 684 secret.SetResourceVersion("") 685 Expect(k8sClient.Create(hubCtx, secret)).Should(Succeed()) 686 defer func() { 687 _ = k8sClient.Delete(hubCtx, secret) 688 }() 689 690 By("create cluster normally") 691 bs, err := os.ReadFile("./testdata/app/app-disconnection-test.yaml") 692 Expect(err).Should(Succeed()) 693 app := &v1beta1.Application{} 694 Expect(yaml.Unmarshal(bs, app)).Should(Succeed()) 695 app.SetNamespace(namespace) 696 Expect(k8sClient.Create(hubCtx, app)).Should(Succeed()) 697 key := client.ObjectKeyFromObject(app) 698 Eventually(func(g Gomega) { 699 g.Expect(k8sClient.Get(hubCtx, key, app)).Should(Succeed()) 700 g.Expect(app.Status.Phase).Should(Equal(common.ApplicationRunning)) 701 }).WithTimeout(10 * time.Second).WithPolling(2 * time.Second).Should(Succeed()) 702 703 By("disconnect cluster") 704 Expect(k8sClient.Get(hubCtx, types.NamespacedName{Namespace: kubevelatypes.DefaultKubeVelaNS, Name: secretName}, secret)).Should(Succeed()) 705 secret.Data["endpoint"] = []byte("https://1.2.3.4:9999") 706 Expect(k8sClient.Update(hubCtx, secret)).Should(Succeed()) 707 708 By("update application") 709 Expect(k8sClient.Get(hubCtx, key, app)).Should(Succeed()) 710 app.Spec.Policies = nil 711 Expect(k8sClient.Update(hubCtx, app)).Should(Succeed()) 712 Eventually(func(g Gomega) { 713 g.Expect(k8sClient.Get(hubCtx, key, app)).Should(Succeed()) 714 g.Expect(app.Status.ObservedGeneration).Should(Equal(app.Generation)) 715 g.Expect(app.Status.Phase).Should(Equal(common.ApplicationRunning)) 716 rts := &v1beta1.ResourceTrackerList{} 717 g.Expect(k8sClient.List(hubCtx, rts, client.MatchingLabels{oam.LabelAppName: key.Name, oam.LabelAppNamespace: key.Namespace})).Should(Succeed()) 718 cnt := 0 719 for _, item := range rts.Items { 720 if item.Spec.Type == v1beta1.ResourceTrackerTypeVersioned { 721 cnt++ 722 } 723 } 724 g.Expect(cnt).Should(Equal(2)) 725 }).WithTimeout(30 * time.Second).WithPolling(2 * time.Second).Should(Succeed()) 726 727 By("try update application again") 728 Expect(k8sClient.Get(hubCtx, key, app)).Should(Succeed()) 729 if app.Annotations == nil { 730 app.Annotations = map[string]string{} 731 } 732 app.Annotations[oam.AnnotationPublishVersion] = "test" 733 Expect(k8sClient.Update(hubCtx, app)).Should(Succeed()) 734 Eventually(func(g Gomega) { 735 g.Expect(k8sClient.Get(hubCtx, key, app)).Should(Succeed()) 736 g.Expect(app.Status.LatestRevision).ShouldNot(BeNil()) 737 g.Expect(app.Status.LatestRevision.Revision).Should(Equal(int64(3))) 738 g.Expect(app.Status.ObservedGeneration).Should(Equal(app.Generation)) 739 g.Expect(app.Status.Phase).Should(Equal(common.ApplicationRunning)) 740 }).WithTimeout(1 * time.Minute).WithPolling(2 * time.Second).Should(Succeed()) 741 742 By("clear disconnection cluster secret") 743 Expect(k8sClient.Get(hubCtx, types.NamespacedName{Namespace: kubevelatypes.DefaultKubeVelaNS, Name: secretName}, secret)).Should(Succeed()) 744 Expect(k8sClient.Delete(hubCtx, secret)).Should(Succeed()) 745 746 By("wait gc application completed") 747 Eventually(func(g Gomega) { 748 rts := &v1beta1.ResourceTrackerList{} 749 g.Expect(k8sClient.List(hubCtx, rts, client.MatchingLabels{oam.LabelAppName: key.Name, oam.LabelAppNamespace: key.Namespace})).Should(Succeed()) 750 cnt := 0 751 for _, item := range rts.Items { 752 if item.Spec.Type == v1beta1.ResourceTrackerTypeVersioned { 753 cnt++ 754 } 755 } 756 g.Expect(cnt).Should(Equal(1)) 757 }).WithTimeout(30 * time.Second).WithPolling(2 * time.Second).Should(Succeed()) 758 }) 759 760 It("Test application with gc policy and shared-resource policy", func() { 761 app := &v1beta1.Application{} 762 bs, err := os.ReadFile("./testdata/app/app-gc-shared.yaml") 763 Expect(err).Should(Succeed()) 764 Expect(yaml.Unmarshal(bs, app)).Should(Succeed()) 765 app.SetNamespace(namespace) 766 Expect(k8sClient.Create(hubCtx, app)).Should(Succeed()) 767 appKey := client.ObjectKeyFromObject(app) 768 Eventually(func(g Gomega) { 769 g.Expect(k8sClient.Get(hubCtx, appKey, app)).Should(Succeed()) 770 g.Expect(app.Status.Phase).Should(Equal(common.ApplicationRunning)) 771 g.Expect(k8sClient.Get(hubCtx, appKey, &corev1.ConfigMap{})).Should(Succeed()) 772 }).WithTimeout(10 * time.Second).Should(Succeed()) 773 Expect(k8sClient.Get(hubCtx, appKey, app)).Should(Succeed()) 774 Expect(k8sClient.Delete(hubCtx, app)).Should(Succeed()) 775 Eventually(func(g Gomega) { 776 g.Expect(kerrors.IsNotFound(k8sClient.Get(hubCtx, appKey, app))).Should(BeTrue()) 777 g.Expect(k8sClient.Get(hubCtx, appKey, &corev1.ConfigMap{})).Should(Succeed()) 778 }).WithTimeout(10 * time.Second).Should(Succeed()) 779 }) 780 781 It("Test application skip webservice component health check", func() { 782 td := &v1beta1.TraitDefinition{ 783 ObjectMeta: metav1.ObjectMeta{Name: "ignore-health-check", Namespace: namespace}, 784 Spec: v1beta1.TraitDefinitionSpec{ 785 Schematic: &common.Schematic{CUE: &common.CUE{ 786 Template: ` 787 patch: metadata: annotations: "app.oam.dev/disable-health-check": parameter.key 788 parameter: key: string 789 `, 790 }}, 791 Status: &common.Status{HealthPolicy: `isHealth: context.parameter.key == "true"`}, 792 }, 793 } 794 Expect(k8sClient.Create(hubCtx, td)).Should(Succeed()) 795 796 app := &v1beta1.Application{ 797 ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: namespace}, 798 Spec: v1beta1.ApplicationSpec{Components: []common.ApplicationComponent{{ 799 Type: "webservice", 800 Name: "test", 801 Properties: &runtime.RawExtension{Raw: []byte(`{"image":"bad"}`)}, 802 Traits: []common.ApplicationTrait{{ 803 Type: "ignore-health-check", 804 Properties: &runtime.RawExtension{Raw: []byte(`{"key":"false"}`)}, 805 }}, 806 }}}, 807 } 808 Eventually(func(g Gomega) { // in case the trait definition has not been watched by vela-core 809 g.Expect(k8sClient.Create(hubCtx, app)).Should(Succeed()) 810 }).WithTimeout(10 * time.Second).WithPolling(2 * time.Second).Should(Succeed()) 811 appKey := client.ObjectKeyFromObject(app) 812 Eventually(func(g Gomega) { 813 g.Expect(k8sClient.Get(hubCtx, appKey, app)).Should(Succeed()) 814 g.Expect(len(app.Status.Services) > 0).Should(BeTrue()) 815 g.Expect(len(app.Status.Services[0].Traits) > 0).Should(BeTrue()) 816 g.Expect(app.Status.Services[0].Traits[0].Healthy).Should(BeFalse()) 817 }).WithTimeout(10 * time.Second).Should(Succeed()) 818 Eventually(func(g Gomega) { 819 g.Expect(k8sClient.Get(hubCtx, appKey, app)).Should(Succeed()) 820 app.Spec.Components[0].Traits[0].Properties.Raw = []byte(`{"key":"true"}`) 821 g.Expect(k8sClient.Update(hubCtx, app)).Should(Succeed()) 822 }).WithTimeout(10 * time.Second).Should(Succeed()) 823 Eventually(func(g Gomega) { 824 g.Expect(k8sClient.Get(hubCtx, appKey, app)).Should(Succeed()) 825 g.Expect(len(app.Status.Services) > 0).Should(BeTrue()) 826 g.Expect(len(app.Status.Services[0].Traits) > 0).Should(BeTrue()) 827 g.Expect(app.Status.Services[0].Traits[0].Healthy).Should(BeTrue()) 828 }).WithTimeout(20 * time.Second).Should(Succeed()) 829 }) 830 831 It("Test pause application", func() { 832 app := &v1beta1.Application{} 833 bs, err := os.ReadFile("./testdata/app/app-pause.yaml") 834 Expect(err).Should(Succeed()) 835 Expect(yaml.Unmarshal(bs, app)).Should(Succeed()) 836 app.SetNamespace(namespace) 837 Expect(k8sClient.Create(hubCtx, app)).Should(Succeed()) 838 time.Sleep(10 * time.Second) 839 appKey := client.ObjectKeyFromObject(app) 840 Expect(k8sClient.Get(hubCtx, appKey, app)).Should(Succeed()) 841 Expect(app.Status.Workflow).Should(BeNil()) 842 Eventually(func(g Gomega) { 843 g.Expect(k8sClient.Get(hubCtx, appKey, app)).Should(Succeed()) 844 reconciler.SetPause(app, false) 845 g.Expect(k8sClient.Update(hubCtx, app)).Should(Succeed()) 846 }).WithTimeout(5 * time.Second).WithPolling(time.Second).Should(Succeed()) 847 Eventually(func(g Gomega) { 848 g.Expect(k8sClient.Get(hubCtx, appKey, app)).Should(Succeed()) 849 g.Expect(app.Status.Phase).Should(Equal(common.ApplicationRunning)) 850 }).WithTimeout(15 * time.Second).WithPolling(3 * time.Second).Should(Succeed()) 851 Expect(k8sClient.Delete(hubCtx, app)).Should(Succeed()) 852 }) 853 854 It("Test application carrying deploy step with inline policy", func() { 855 ctx := context.Background() 856 wsDef := &v1beta1.WorkflowStepDefinition{} 857 bs, err := os.ReadFile("./testdata/def/inline-deploy.yaml") 858 Expect(err).Should(Succeed()) 859 Expect(yaml.Unmarshal(bs, wsDef)).Should(Succeed()) 860 wsDef.SetNamespace(namespace) 861 Expect(k8sClient.Create(ctx, wsDef)).Should(Succeed()) 862 app := &v1beta1.Application{} 863 bs, err = os.ReadFile("./testdata/app/app-carrying-deploy-step-with-inline-policy.yaml") 864 Expect(err).Should(Succeed()) 865 Expect(yaml.Unmarshal(bs, app)).Should(Succeed()) 866 app.SetNamespace(namespace) 867 Eventually(func(g Gomega) { 868 g.Expect(k8sClient.Create(ctx, app)).Should(Succeed()) 869 }).WithPolling(2 * time.Second).WithTimeout(5 * time.Second).Should(Succeed()) 870 appKey := client.ObjectKeyFromObject(app) 871 Eventually(func(g Gomega) { 872 _app := &v1beta1.Application{} 873 g.Expect(k8sClient.Get(ctx, appKey, _app)).Should(Succeed()) 874 g.Expect(_app.Status.Phase).Should(Equal(common.ApplicationRunning)) 875 }).WithPolling(2 * time.Second).WithTimeout(20 * time.Second).Should(Succeed()) 876 _deploy := &appsv1.Deployment{} 877 Expect(k8sClient.Get(ctx, appKey, _deploy)).Should(Succeed()) 878 Expect(int(*_deploy.Spec.Replicas)).Should(Equal(0)) 879 }) 880 881 It("Test application with multiple gc & shared-resource policies", func() { 882 ctx := context.Background() 883 app := &v1beta1.Application{} 884 bs, err := os.ReadFile("./testdata/app/app-multi-resource-policies.yaml") 885 Expect(err).Should(Succeed()) 886 Expect(yaml.Unmarshal(bs, app)).Should(Succeed()) 887 app.SetNamespace(namespace) 888 app2 := app.DeepCopy() 889 app2.SetName("test-2") 890 Eventually(func(g Gomega) { 891 g.Expect(k8sClient.Create(ctx, app)).Should(Succeed()) 892 }).WithPolling(2 * time.Second).WithTimeout(5 * time.Second).Should(Succeed()) 893 Eventually(func(g Gomega) { 894 g.Expect(k8sClient.Create(ctx, app2)).Should(Succeed()) 895 }).WithPolling(2 * time.Second).WithTimeout(5 * time.Second).Should(Succeed()) 896 appKey := client.ObjectKeyFromObject(app) 897 appKey2 := client.ObjectKeyFromObject(app2) 898 Eventually(func(g Gomega) { 899 _app := &v1beta1.Application{} 900 g.Expect(k8sClient.Get(ctx, appKey, _app)).Should(Succeed()) 901 g.Expect(_app.Status.Phase).Should(Equal(common.ApplicationRunning)) 902 }).WithPolling(2 * time.Second).WithTimeout(20 * time.Second).Should(Succeed()) 903 Eventually(func(g Gomega) { 904 _app := &v1beta1.Application{} 905 g.Expect(k8sClient.Get(ctx, appKey2, _app)).Should(Succeed()) 906 g.Expect(_app.Status.Phase).Should(Equal(common.ApplicationRunning)) 907 }).WithPolling(2 * time.Second).WithTimeout(20 * time.Second).Should(Succeed()) 908 Eventually(func(g Gomega) { 909 _app := &v1beta1.Application{} 910 g.Expect(client.IgnoreNotFound(k8sClient.Get(ctx, appKey, _app))).Should(Succeed()) 911 g.Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, _app))).Should(Succeed()) 912 }).WithPolling(2 * time.Second).WithTimeout(10 * time.Second).Should(Succeed()) 913 Eventually(func(g Gomega) { 914 _app := &v1beta1.Application{} 915 g.Expect(client.IgnoreNotFound(k8sClient.Get(ctx, appKey2, _app))).Should(Succeed()) 916 g.Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, _app))).Should(Succeed()) 917 }).WithPolling(2 * time.Second).WithTimeout(10 * time.Second).Should(Succeed()) 918 Eventually(func(g Gomega) { 919 _app := &v1beta1.Application{} 920 g.Expect(kerrors.IsNotFound(k8sClient.Get(ctx, appKey, _app))).Should(BeTrue()) 921 g.Expect(kerrors.IsNotFound(k8sClient.Get(ctx, appKey2, _app))).Should(BeTrue()) 922 g.Expect(k8sClient.Get(ctx, appKey, &corev1.ConfigMap{})).Should(Succeed()) 923 g.Expect(k8sClient.Get(ctx, appKey, &corev1.Secret{})).Should(Succeed()) 924 }).WithPolling(2 * time.Second).WithTimeout(10 * time.Second).Should(Succeed()) 925 }) 926 927 It("Test application with anonymous policy", func() { 928 ctx := context.Background() 929 app := &v1beta1.Application{} 930 bs, err := os.ReadFile("./testdata/app/app-anonymous-policies.yaml") 931 Expect(err).Should(Succeed()) 932 Expect(yaml.Unmarshal(bs, app)).Should(Succeed()) 933 app.SetNamespace(namespace) 934 Eventually(func(g Gomega) { 935 g.Expect(k8sClient.Create(ctx, app)).Should(Succeed()) 936 }).WithPolling(2 * time.Second).WithTimeout(5 * time.Second).Should(Succeed()) 937 appKey := client.ObjectKeyFromObject(app) 938 Eventually(func(g Gomega) { 939 _app := &v1beta1.Application{} 940 g.Expect(k8sClient.Get(ctx, appKey, _app)).Should(Succeed()) 941 g.Expect(_app.Status.Phase).Should(Equal(common.ApplicationRunning)) 942 }).WithPolling(2 * time.Second).WithTimeout(20 * time.Second).Should(Succeed()) 943 _deploy := &appsv1.Deployment{} 944 Expect(k8sClient.Get(workerCtx, appKey, _deploy)).Should(Succeed()) 945 Expect(int(*_deploy.Spec.Replicas)).Should(Equal(0)) 946 }) 947 948 It("Test application with customized application revision limit", func() { 949 ctx := context.Background() 950 app := &v1beta1.Application{} 951 bs, err := os.ReadFile("./testdata/app/app-lite.yaml") 952 Expect(err).Should(Succeed()) 953 Expect(yaml.Unmarshal(bs, app)).Should(Succeed()) 954 app.SetNamespace(namespace) 955 Eventually(func(g Gomega) { 956 g.Expect(k8sClient.Create(ctx, app)).Should(Succeed()) 957 }).WithPolling(2 * time.Second).WithTimeout(5 * time.Second).Should(Succeed()) 958 appKey := client.ObjectKeyFromObject(app) 959 Eventually(func(g Gomega) { 960 _app := &v1beta1.Application{} 961 g.Expect(k8sClient.Get(ctx, appKey, _app)).Should(Succeed()) 962 g.Expect(_app.Status.Phase).Should(Equal(common.ApplicationRunning)) 963 }).WithPolling(2 * time.Second).WithTimeout(20 * time.Second).Should(Succeed()) 964 965 By("update app and should have two revisions") 966 Eventually(func(g Gomega) { 967 _app := &v1beta1.Application{} 968 g.Expect(k8sClient.Get(ctx, appKey, _app)).Should(Succeed()) 969 _app.Spec.Components[0].Name = "dw" 970 g.Expect(k8sClient.Update(ctx, _app)).Should(Succeed()) 971 }).WithPolling(2 * time.Second).WithTimeout(20 * time.Second).Should(Succeed()) 972 Eventually(func(g Gomega) { 973 _app := &v1beta1.Application{} 974 g.Expect(k8sClient.Get(ctx, appKey, _app)).Should(Succeed()) 975 g.Expect(_app.Status.Phase).Should(Equal(common.ApplicationRunning)) 976 _revs := &v1beta1.ApplicationRevisionList{} 977 g.Expect(k8sClient.List(ctx, _revs, client.InNamespace(namespace))).Should(Succeed()) 978 g.Expect(len(_revs.Items)).Should(Equal(2)) 979 }).WithPolling(2 * time.Second).WithTimeout(20 * time.Second).Should(Succeed()) 980 981 By("update app with gc policy and should have one revision") 982 Eventually(func(g Gomega) { 983 _app := &v1beta1.Application{} 984 g.Expect(k8sClient.Get(ctx, appKey, _app)).Should(Succeed()) 985 _app.Spec.Components[0].Name = "dw2" 986 _app.Spec.Policies = []v1beta1.AppPolicy{{ 987 Type: "garbage-collect", 988 Name: "gc", 989 Properties: &runtime.RawExtension{Raw: []byte(`{"applicationRevisionLimit":0}`)}, 990 }} 991 g.Expect(k8sClient.Update(ctx, _app)).Should(Succeed()) 992 }).WithPolling(2 * time.Second).WithTimeout(20 * time.Second).Should(Succeed()) 993 Eventually(func(g Gomega) { 994 _app := &v1beta1.Application{} 995 g.Expect(k8sClient.Get(ctx, appKey, _app)).Should(Succeed()) 996 g.Expect(_app.Status.Phase).Should(Equal(common.ApplicationRunning)) 997 _revs := &v1beta1.ApplicationRevisionList{} 998 g.Expect(k8sClient.List(ctx, _revs, client.InNamespace(namespace))).Should(Succeed()) 999 g.Expect(len(_revs.Items)).Should(Equal(1)) 1000 }).WithPolling(2 * time.Second).WithTimeout(20 * time.Second).Should(Succeed()) 1001 }) 1002 1003 It("Test application with resource-update policy", func() { 1004 ctx := context.Background() 1005 app := &v1beta1.Application{} 1006 bs, err := os.ReadFile("./testdata/app/app-recreate-test.yaml") 1007 Expect(err).Should(Succeed()) 1008 Expect(yaml.Unmarshal(bs, app)).Should(Succeed()) 1009 app.SetNamespace(namespace) 1010 Eventually(func(g Gomega) { 1011 g.Expect(k8sClient.Create(ctx, app)).Should(Succeed()) 1012 }).WithPolling(2 * time.Second).WithTimeout(5 * time.Second).Should(Succeed()) 1013 appKey := client.ObjectKeyFromObject(app) 1014 Eventually(func(g Gomega) { 1015 _app := &v1beta1.Application{} 1016 g.Expect(k8sClient.Get(ctx, appKey, _app)).Should(Succeed()) 1017 g.Expect(_app.Status.Phase).Should(Equal(common.ApplicationRunning)) 1018 }).WithPolling(2 * time.Second).WithTimeout(20 * time.Second).Should(Succeed()) 1019 1020 By("update configmap") 1021 Eventually(func(g Gomega) { 1022 cm := &corev1.ConfigMap{} 1023 g.Expect(k8sClient.Get(ctx, appKey, cm)).Should(Succeed()) 1024 cm.Data["extra"] = "extra-val" 1025 g.Expect(k8sClient.Update(ctx, cm)).Should(Succeed()) 1026 }).WithPolling(2 * time.Second).WithTimeout(20 * time.Second).Should(Succeed()) 1027 1028 By("update application") 1029 Expect(yaml.Unmarshal([]byte(strings.ReplaceAll(strings.ReplaceAll(string(bs), "key: dgo=", "key: dnZ2Cg=="), "key: val", "key: val2")), app)).Should(Succeed()) 1030 Eventually(func(g Gomega) { 1031 _app := &v1beta1.Application{} 1032 g.Expect(k8sClient.Get(ctx, appKey, _app)).Should(Succeed()) 1033 app.ResourceVersion = _app.ResourceVersion 1034 g.Expect(k8sClient.Update(ctx, app)).Should(Succeed()) 1035 }).WithPolling(2 * time.Second).WithTimeout(20 * time.Second).Should(Succeed()) 1036 Eventually(func(g Gomega) { 1037 _app := &v1beta1.Application{} 1038 g.Expect(k8sClient.Get(ctx, appKey, _app)).Should(Succeed()) 1039 g.Expect(_app.Status.Phase).Should(Equal(common.ApplicationRunning)) 1040 }).WithPolling(2 * time.Second).WithTimeout(20 * time.Second).Should(Succeed()) 1041 1042 By("validate updated result") 1043 Eventually(func(g Gomega) { 1044 cm := &corev1.ConfigMap{} 1045 g.Expect(k8sClient.Get(ctx, appKey, cm)).Should(Succeed()) 1046 g.Expect(len(cm.Data)).Should(Equal(1)) 1047 secret := &corev1.Secret{} 1048 g.Expect(k8sClient.Get(ctx, appKey, secret)).Should(Succeed()) 1049 g.Expect(string(secret.Data["key"])).Should(Equal("vvv\n")) 1050 }).WithPolling(2 * time.Second).WithTimeout(20 * time.Second).Should(Succeed()) 1051 }) 1052 1053 It("Test application apply resources into managed cluster without installing CRD on the control plane", func() { 1054 ctx := context.Background() 1055 crd := &unstructured.Unstructured{} 1056 bs, err := os.ReadFile("./testdata/kube/sample-crd.yaml") 1057 Expect(err).Should(Succeed()) 1058 Expect(yaml.Unmarshal(bs, crd)).Should(Succeed()) 1059 Expect(client.IgnoreAlreadyExists(k8sClient.Create(workerCtx, crd))).Should(Succeed()) 1060 1061 app := &v1beta1.Application{} 1062 bs, err = os.ReadFile("./testdata/app/app-remote-resource.yaml") 1063 Expect(err).Should(Succeed()) 1064 Expect(yaml.Unmarshal(bs, app)).Should(Succeed()) 1065 app.SetNamespace(namespace) 1066 Eventually(func(g Gomega) { 1067 g.Expect(k8sClient.Create(ctx, app)).Should(Succeed()) 1068 }).WithPolling(2 * time.Second).WithTimeout(5 * time.Second).Should(Succeed()) 1069 appKey := client.ObjectKeyFromObject(app) 1070 Eventually(func(g Gomega) { 1071 _app := &v1beta1.Application{} 1072 g.Expect(k8sClient.Get(ctx, appKey, _app)).Should(Succeed()) 1073 g.Expect(_app.Status.Phase).Should(Equal(common.ApplicationRunning)) 1074 }).WithPolling(2 * time.Second).WithTimeout(20 * time.Second).Should(Succeed()) 1075 obj := &unstructured.Unstructured{} 1076 obj.SetAPIVersion("sample.custom.io/v1alpha1") 1077 obj.SetKind("Foo") 1078 Expect(k8sClient.Get(workerCtx, appKey, obj)).Should(Succeed()) 1079 Expect(obj.Object["spec"].(map[string]interface{})["key"]).Should(Equal("value")) 1080 }) 1081 1082 It("Test application with fixed cluster to dispatch", func() { 1083 ctx := context.Background() 1084 app := &v1beta1.Application{} 1085 bs, err := os.ReadFile("./testdata/app/app-with-fixed-location.yaml") 1086 Expect(err).Should(Succeed()) 1087 Expect(yaml.Unmarshal(bs, app)).Should(Succeed()) 1088 app.SetNamespace(namespace) 1089 Eventually(func(g Gomega) { 1090 g.Expect(k8sClient.Create(ctx, app)).Should(Succeed()) 1091 }).WithPolling(2 * time.Second).WithTimeout(5 * time.Second).Should(Succeed()) 1092 appKey := client.ObjectKeyFromObject(app) 1093 Eventually(func(g Gomega) { 1094 _app := &v1beta1.Application{} 1095 g.Expect(k8sClient.Get(ctx, appKey, _app)).Should(Succeed()) 1096 g.Expect(_app.Status.Phase).Should(Equal(common.ApplicationRunning)) 1097 }).WithPolling(2 * time.Second).WithTimeout(20 * time.Second).Should(Succeed()) 1098 Expect(k8sClient.Get(hubCtx, types.NamespacedName{Namespace: namespace, Name: "x"}, &corev1.ConfigMap{})).Should(Succeed()) 1099 Expect(k8sClient.Get(workerCtx, types.NamespacedName{Namespace: namespace, Name: "y"}, &corev1.ConfigMap{})).Should(Succeed()) 1100 1101 By("Deleting") 1102 _app := &v1beta1.Application{} 1103 Expect(k8sClient.Get(ctx, appKey, _app)).Should(Succeed()) 1104 Expect(k8sClient.Delete(ctx, _app)).Should(Succeed()) 1105 Eventually(func(g Gomega) { 1106 g.Expect(kerrors.IsNotFound(k8sClient.Get(ctx, appKey, _app))).Should(BeTrue()) 1107 }).WithPolling(2 * time.Second).WithTimeout(20 * time.Second).Should(Succeed()) 1108 Expect(kerrors.IsNotFound(k8sClient.Get(hubCtx, types.NamespacedName{Namespace: namespace, Name: "x"}, &corev1.ConfigMap{}))).Should(BeTrue()) 1109 Expect(kerrors.IsNotFound(k8sClient.Get(workerCtx, types.NamespacedName{Namespace: namespace, Name: "y"}, &corev1.ConfigMap{}))).Should(BeTrue()) 1110 }) 1111 1112 It("Test application with garbage-collect propagation setting", func() { 1113 ctx := context.Background() 1114 app := &v1beta1.Application{} 1115 bs, err := os.ReadFile("./testdata/app/app-with-custom-gc-propagation.yaml") 1116 Expect(err).Should(Succeed()) 1117 Expect(yaml.Unmarshal(bs, app)).Should(Succeed()) 1118 app.SetNamespace(namespace) 1119 Eventually(func(g Gomega) { 1120 g.Expect(k8sClient.Create(ctx, app)).Should(Succeed()) 1121 }).WithPolling(2 * time.Second).WithTimeout(5 * time.Second).Should(Succeed()) 1122 appKey := client.ObjectKeyFromObject(app) 1123 Eventually(func(g Gomega) { 1124 _app := &v1beta1.Application{} 1125 g.Expect(k8sClient.Get(ctx, appKey, _app)).Should(Succeed()) 1126 g.Expect(_app.Status.Phase).Should(Equal(common.ApplicationRunning)) 1127 }).WithPolling(2 * time.Second).WithTimeout(20 * time.Second).Should(Succeed()) 1128 By("Deleting") 1129 _app := &v1beta1.Application{} 1130 Expect(k8sClient.Get(ctx, appKey, _app)).Should(Succeed()) 1131 Expect(k8sClient.Delete(ctx, _app)).Should(Succeed()) 1132 Eventually(func(g Gomega) { 1133 _app := &v1beta1.Application{} 1134 g.Expect(kerrors.IsNotFound(k8sClient.Get(ctx, appKey, _app))).Should(BeTrue()) 1135 }).WithPolling(2 * time.Second).WithTimeout(20 * time.Second).Should(Succeed()) 1136 Eventually(func(g Gomega) { 1137 pods := &corev1.PodList{} 1138 g.Expect(k8sClient.List(ctx, pods, client.InNamespace(namespace))).Should(Succeed()) 1139 g.Expect(len(pods.Items)).Should(Equal(1)) 1140 g.Expect(pods.Items[0].Name).Should(ContainSubstring("orphan")) 1141 }).WithPolling(2 * time.Second).WithTimeout(20 * time.Second).Should(Succeed()) 1142 }) 1143 1144 It("Test application revision gc block application gc", func() { 1145 ctx := context.Background() 1146 app := &v1beta1.Application{} 1147 bs, err := os.ReadFile("./testdata/app/app-lite.yaml") 1148 Expect(err).Should(Succeed()) 1149 Expect(yaml.Unmarshal(bs, app)).Should(Succeed()) 1150 app.SetNamespace(namespace) 1151 Eventually(func(g Gomega) { 1152 g.Expect(k8sClient.Create(ctx, app)).Should(Succeed()) 1153 }).WithPolling(2 * time.Second).WithTimeout(5 * time.Second).Should(Succeed()) 1154 appKey := client.ObjectKeyFromObject(app) 1155 Eventually(func(g Gomega) { 1156 _app := &v1beta1.Application{} 1157 g.Expect(k8sClient.Get(ctx, appKey, _app)).Should(Succeed()) 1158 g.Expect(_app.Status.Phase).Should(Equal(common.ApplicationRunning)) 1159 }).WithPolling(2 * time.Second).WithTimeout(20 * time.Second).Should(Succeed()) 1160 1161 By("Add finalizer to application revision") 1162 Eventually(func(g Gomega) { 1163 _rev := &v1beta1.ApplicationRevision{} 1164 g.Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: appKey.Name + "-v1"}, _rev)).Should(Succeed()) 1165 _rev.SetFinalizers([]string{"mine"}) 1166 g.Expect(k8sClient.Update(ctx, _rev)).Should(Succeed()) 1167 }).WithPolling(2 * time.Second).WithTimeout(10 * time.Second).Should(Succeed()) 1168 1169 By("Deleting") 1170 _app := &v1beta1.Application{} 1171 Expect(k8sClient.Get(ctx, appKey, _app)).Should(Succeed()) 1172 Expect(k8sClient.Delete(ctx, _app)).Should(Succeed()) 1173 1174 By("Check application existing after rt recycled") 1175 Eventually(func(g Gomega) { 1176 rts := &v1beta1.ResourceTrackerList{} 1177 g.Expect(k8sClient.List(ctx, rts, client.MatchingLabels{oam.LabelAppName: _app.Name, oam.LabelAppNamespace: _app.Namespace})).Should(Succeed()) 1178 g.Expect(len(rts.Items)).Should(Equal(0)) 1179 }).WithPolling(2 * time.Second).WithTimeout(10 * time.Second).Should(Succeed()) 1180 Consistently(func(g Gomega) { 1181 g.Expect(k8sClient.Get(ctx, appKey, _app)).Should(Succeed()) 1182 }).WithPolling(2 * time.Second).WithTimeout(10 * time.Second).Should(Succeed()) 1183 1184 By("Remove finalizer from application revision") 1185 Eventually(func(g Gomega) { 1186 _rev := &v1beta1.ApplicationRevision{} 1187 g.Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: appKey.Name + "-v1"}, _rev)).Should(Succeed()) 1188 _rev.SetFinalizers([]string{}) 1189 g.Expect(k8sClient.Update(ctx, _rev)).Should(Succeed()) 1190 }).WithPolling(2 * time.Second).WithTimeout(10 * time.Second).Should(Succeed()) 1191 1192 By("Check application deletion") 1193 Eventually(func(g Gomega) { 1194 g.Expect(kerrors.IsNotFound(k8sClient.Get(ctx, appKey, _app))).Should(BeTrue()) 1195 g.Expect(kerrors.IsNotFound(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: appKey.Name + "-v1"}, &v1beta1.ApplicationRevision{}))).Should(BeTrue()) 1196 }).WithPolling(2 * time.Second).WithTimeout(10 * time.Second).Should(Succeed()) 1197 }) 1198 }) 1199 })