github.com/operator-framework/operator-lifecycle-manager@v0.30.0/test/e2e/gc_e2e_test.go (about) 1 package e2e 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/blang/semver/v4" 8 . "github.com/onsi/ginkgo/v2" 9 . "github.com/onsi/gomega" 10 . "github.com/operator-framework/operator-lifecycle-manager/test/e2e/dsl" 11 corev1 "k8s.io/api/core/v1" 12 rbacv1 "k8s.io/api/rbac/v1" 13 apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" 14 apierrors "k8s.io/apimachinery/pkg/api/errors" 15 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 16 "k8s.io/apimachinery/pkg/util/rand" 17 apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1" 18 19 "github.com/operator-framework/api/pkg/operators/v1alpha1" 20 "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned" 21 "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient" 22 "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil" 23 "github.com/operator-framework/operator-lifecycle-manager/test/e2e/ctx" 24 ) 25 26 var _ = Describe("Garbage collection for dependent resources", func() { 27 var ( 28 kubeClient operatorclient.ClientInterface 29 operatorClient versioned.Interface 30 generatedNamespace corev1.Namespace 31 ) 32 33 BeforeEach(func() { 34 kubeClient = ctx.Ctx().KubeClient() 35 operatorClient = ctx.Ctx().OperatorClient() 36 37 namespaceName := genName("gc-e2e-") 38 generatedNamespace = SetupGeneratedTestNamespace(namespaceName, namespaceName) 39 }) 40 41 AfterEach(func() { 42 TeardownNamespace(generatedNamespace.GetName()) 43 }) 44 45 Context("Given a ClusterRole owned by a CustomResourceDefinition", func() { 46 var ( 47 crd *apiextensionsv1.CustomResourceDefinition 48 cr *rbacv1.ClusterRole 49 ) 50 51 BeforeEach(func() { 52 group := fmt.Sprintf("%s.com", rand.String(16)) 53 54 crd = &apiextensionsv1.CustomResourceDefinition{ 55 ObjectMeta: metav1.ObjectMeta{ 56 Name: fmt.Sprintf("plural.%s", group), 57 }, 58 Spec: apiextensionsv1.CustomResourceDefinitionSpec{ 59 Group: group, 60 Scope: apiextensionsv1.ClusterScoped, 61 Versions: []apiextensionsv1.CustomResourceDefinitionVersion{ 62 { 63 Name: "v1", 64 Served: true, 65 Storage: true, 66 Schema: &apiextensionsv1.CustomResourceValidation{ 67 OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{Type: "object"}, 68 }, 69 }, 70 }, 71 Names: apiextensionsv1.CustomResourceDefinitionNames{ 72 Plural: "plural", 73 Singular: "singular", 74 Kind: "Kind", 75 ListKind: "KindList", 76 }, 77 }, 78 } 79 80 By(`Create a CustomResourceDefinition`) 81 var err error 82 Eventually(func() error { 83 crd, err = kubeClient.ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Create(context.Background(), crd, metav1.CreateOptions{}) 84 return err 85 }).Should(Succeed()) 86 87 cr = &rbacv1.ClusterRole{ 88 ObjectMeta: metav1.ObjectMeta{ 89 GenerateName: "clusterrole-", 90 OwnerReferences: []metav1.OwnerReference{ownerutil.NonBlockingOwner(crd)}, 91 }, 92 } 93 94 By(`Create a ClusterRole for the crd`) 95 Eventually(func() error { 96 cr, err = kubeClient.CreateClusterRole(cr) 97 return err 98 }).Should(Succeed()) 99 }) 100 101 AfterEach(func() { 102 103 By(`Clean up cluster role`) 104 IgnoreError(kubeClient.DeleteClusterRole(cr.GetName(), &metav1.DeleteOptions{})) 105 106 By(`Clean up CRD`) 107 IgnoreError(kubeClient.ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.Background(), crd.GetName(), metav1.DeleteOptions{})) 108 }) 109 110 When("CustomResourceDefinition is deleted", func() { 111 112 BeforeEach(func() { 113 By(`Delete CRD`) 114 Eventually(func() bool { 115 err := kubeClient.ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.Background(), crd.GetName(), metav1.DeleteOptions{}) 116 return apierrors.IsNotFound(err) 117 }).Should(BeTrue()) 118 }) 119 120 It("should delete the associated ClusterRole", func() { 121 Eventually(func() bool { 122 _, err := kubeClient.GetClusterRole(cr.GetName()) 123 return apierrors.IsNotFound(err) 124 }).Should(BeTrue(), "get cluster role should eventually return \"not found\"") 125 }) 126 127 }) 128 }) 129 130 Context("Given a ClusterRole owned by a APIService", func() { 131 var ( 132 apiService *apiregistrationv1.APIService 133 cr *rbacv1.ClusterRole 134 ) 135 136 BeforeEach(func() { 137 group := rand.String(16) 138 139 apiService = &apiregistrationv1.APIService{ 140 ObjectMeta: metav1.ObjectMeta{ 141 Name: fmt.Sprintf("v1.%s", group), 142 }, 143 Spec: apiregistrationv1.APIServiceSpec{ 144 Group: group, 145 Version: "v1", 146 GroupPriorityMinimum: 1, 147 VersionPriority: 1, 148 }, 149 } 150 By(`Create an API Service`) 151 var err error 152 Eventually(func() error { 153 apiService, err = kubeClient.CreateAPIService(apiService) 154 return err 155 }).Should(Succeed()) 156 157 cr = &rbacv1.ClusterRole{ 158 ObjectMeta: metav1.ObjectMeta{ 159 GenerateName: "clusterrole-", 160 OwnerReferences: []metav1.OwnerReference{ownerutil.NonBlockingOwner(apiService)}, 161 }, 162 } 163 164 Eventually(func() error { 165 By(`Create a ClusterRole`) 166 cr, err = kubeClient.CreateClusterRole(cr) 167 return err 168 }).Should(Succeed()) 169 }) 170 171 AfterEach(func() { 172 173 IgnoreError(kubeClient.DeleteClusterRole(cr.GetName(), &metav1.DeleteOptions{})) 174 175 IgnoreError(kubeClient.DeleteAPIService(apiService.GetName(), &metav1.DeleteOptions{})) 176 177 }) 178 179 When("APIService is deleted", func() { 180 181 BeforeEach(func() { 182 By(`Delete API service`) 183 Eventually(func() bool { 184 err := kubeClient.DeleteAPIService(apiService.GetName(), &metav1.DeleteOptions{}) 185 return apierrors.IsNotFound(err) 186 }).Should(BeTrue()) 187 }) 188 189 It("should delete the associated ClusterRole", func() { 190 Eventually(func() bool { 191 _, err := kubeClient.GetClusterRole(cr.GetName()) 192 return apierrors.IsNotFound(err) 193 }).Should(BeTrue(), "get cluster role should eventually return \"not found\"") 194 }) 195 196 }) 197 }) 198 199 // TestOwnerReferenceGCBehavior runs a simple check on OwnerReference behavior to ensure 200 // a resource with multiple OwnerReferences will not be garbage collected when one of its 201 // owners has been deleted. 202 // Test Case: 203 // CSV-A CSV-B CSV-B 204 // \ / --Delete CSV-A--> | 205 // ConfigMap ConfigMap 206 Context("Given a dependent resource associated with multiple owners", func() { 207 var ( 208 ownerA v1alpha1.ClusterServiceVersion 209 ownerB v1alpha1.ClusterServiceVersion 210 fetchedA *v1alpha1.ClusterServiceVersion 211 fetchedB *v1alpha1.ClusterServiceVersion 212 213 dependent *corev1.ConfigMap 214 215 propagation metav1.DeletionPropagation 216 options metav1.DeleteOptions 217 ) 218 219 BeforeEach(func() { 220 221 ownerA = newCSV("ownera", generatedNamespace.GetName(), "", semver.MustParse("0.0.0"), nil, nil, nil) 222 ownerB = newCSV("ownerb", generatedNamespace.GetName(), "", semver.MustParse("0.0.0"), nil, nil, nil) 223 224 By(`create all owners`) 225 var err error 226 Eventually(func() error { 227 fetchedA, err = operatorClient.OperatorsV1alpha1().ClusterServiceVersions(generatedNamespace.GetName()).Create(context.Background(), &ownerA, metav1.CreateOptions{}) 228 return err 229 }).Should(Succeed()) 230 231 Eventually(func() error { 232 fetchedB, err = operatorClient.OperatorsV1alpha1().ClusterServiceVersions(generatedNamespace.GetName()).Create(context.Background(), &ownerB, metav1.CreateOptions{}) 233 return err 234 }).Should(Succeed()) 235 236 dependent = &corev1.ConfigMap{ 237 ObjectMeta: metav1.ObjectMeta{ 238 Name: "dependent", 239 }, 240 Data: map[string]string{}, 241 } 242 243 By(`add owners`) 244 ownerutil.AddOwner(dependent, fetchedA, true, false) 245 ownerutil.AddOwner(dependent, fetchedB, true, false) 246 247 By(`create ConfigMap dependent`) 248 Eventually(func() error { 249 _, err = kubeClient.KubernetesInterface().CoreV1().ConfigMaps(generatedNamespace.GetName()).Create(context.Background(), dependent, metav1.CreateOptions{}) 250 return err 251 }).Should(Succeed(), "dependent could not be created") 252 253 propagation = metav1.DeletePropagationForeground 254 options = metav1.DeleteOptions{PropagationPolicy: &propagation} 255 }) 256 257 When("removing one of the owner using 'Foreground' deletion policy", func() { 258 259 BeforeEach(func() { 260 By(`delete ownerA in the foreground (to ensure any "blocking" dependents are deleted before ownerA)`) 261 Eventually(func() bool { 262 err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(generatedNamespace.GetName()).Delete(context.Background(), fetchedA.GetName(), options) 263 return apierrors.IsNotFound(err) 264 }).Should(BeTrue()) 265 266 By(`wait for deletion of ownerA`) 267 Eventually(func() bool { 268 _, err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(generatedNamespace.GetName()).Get(context.Background(), ownerA.GetName(), metav1.GetOptions{}) 269 return apierrors.IsNotFound(err) 270 }).Should(BeTrue()) 271 }) 272 273 It("should not have deleted the dependent since ownerB CSV is still present", func() { 274 Eventually(func() error { 275 _, err := kubeClient.KubernetesInterface().CoreV1().ConfigMaps(generatedNamespace.GetName()).Get(context.Background(), dependent.GetName(), metav1.GetOptions{}) 276 return err 277 }).Should(Succeed(), "dependent deleted after one of the owner was deleted") 278 ctx.Ctx().Logf("dependent still exists after one owner was deleted") 279 }) 280 }) 281 282 When("removing both the owners using 'Foreground' deletion policy", func() { 283 284 BeforeEach(func() { 285 By(`delete ownerA in the foreground (to ensure any "blocking" dependents are deleted before ownerA)`) 286 Eventually(func() bool { 287 err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(generatedNamespace.GetName()).Delete(context.Background(), fetchedA.GetName(), options) 288 return apierrors.IsNotFound(err) 289 }).Should(BeTrue()) 290 291 By(`wait for deletion of ownerA`) 292 Eventually(func() bool { 293 _, err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(generatedNamespace.GetName()).Get(context.Background(), ownerA.GetName(), metav1.GetOptions{}) 294 return apierrors.IsNotFound(err) 295 }).Should(BeTrue()) 296 297 By(`delete ownerB in the foreground (to ensure any "blocking" dependents are deleted before ownerB)`) 298 Eventually(func() bool { 299 err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(generatedNamespace.GetName()).Delete(context.Background(), fetchedB.GetName(), options) 300 return apierrors.IsNotFound(err) 301 }).Should(BeTrue()) 302 303 By(`wait for deletion of ownerB`) 304 Eventually(func() bool { 305 _, err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(generatedNamespace.GetName()).Get(context.Background(), ownerB.GetName(), metav1.GetOptions{}) 306 return apierrors.IsNotFound(err) 307 }).Should(BeTrue()) 308 }) 309 310 It("should have deleted the dependent since both the owners were deleted", func() { 311 Eventually(func() bool { 312 _, err := kubeClient.KubernetesInterface().CoreV1().ConfigMaps(generatedNamespace.GetName()).Get(context.Background(), dependent.GetName(), metav1.GetOptions{}) 313 return apierrors.IsNotFound(err) 314 }).Should(BeTrue(), "expected dependency configmap would be properly garabage collected") 315 ctx.Ctx().Logf("dependent successfully garbage collected after both owners were deleted") 316 }) 317 318 }) 319 320 }) 321 322 When("a bundle with configmap and secret objects is installed", func() { 323 324 const ( 325 packageName = "busybox" 326 channelName = "alpha" 327 subName = "test-subscription" 328 secretName = "mysecret" 329 configmapName = "special-config" 330 ) 331 332 BeforeEach(func() { 333 const ( 334 sourceName = "test-catalog" 335 imageName = "quay.io/olmtest/single-bundle-index:objects" 336 ) 337 var installPlanRef string 338 339 By(`create catalog source`) 340 source := &v1alpha1.CatalogSource{ 341 TypeMeta: metav1.TypeMeta{ 342 Kind: v1alpha1.CatalogSourceKind, 343 APIVersion: v1alpha1.CatalogSourceCRDAPIVersion, 344 }, 345 ObjectMeta: metav1.ObjectMeta{ 346 Name: sourceName, 347 Namespace: generatedNamespace.GetName(), 348 Labels: map[string]string{"olm.catalogSource": sourceName}, 349 }, 350 Spec: v1alpha1.CatalogSourceSpec{ 351 SourceType: v1alpha1.SourceTypeGrpc, 352 Image: imageName, 353 GrpcPodConfig: &v1alpha1.GrpcPodConfig{ 354 SecurityContextConfig: v1alpha1.Restricted, 355 }, 356 }, 357 } 358 359 Eventually(func() error { 360 cs, err := operatorClient.OperatorsV1alpha1().CatalogSources(source.GetNamespace()).Create(context.Background(), source, metav1.CreateOptions{}) 361 if err != nil { 362 return err 363 } 364 source = cs.DeepCopy() 365 366 return nil 367 }).Should(Succeed(), "could not create catalog source") 368 369 By(`Wait for the CatalogSource to be ready`) 370 _, err := fetchCatalogSourceOnStatus(operatorClient, source.GetName(), source.GetNamespace(), catalogSourceRegistryPodSynced()) 371 Expect(err).ToNot(HaveOccurred(), "catalog source did not become ready") 372 373 By(`Create a Subscription for package`) 374 _ = createSubscriptionForCatalog(operatorClient, source.GetNamespace(), subName, source.GetName(), packageName, channelName, "", v1alpha1.ApprovalAutomatic) 375 376 By(`Wait for the Subscription to succeed`) 377 sub, err := fetchSubscription(operatorClient, generatedNamespace.GetName(), subName, subscriptionStateAtLatestChecker()) 378 Expect(err).ToNot(HaveOccurred(), "could not get subscription at latest status") 379 380 installPlanRef = sub.Status.InstallPlanRef.Name 381 382 By(`Wait for the installplan to complete (5 minute timeout)`) 383 _, err = fetchInstallPlan(GinkgoT(), operatorClient, installPlanRef, generatedNamespace.GetName(), buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseComplete)) 384 Expect(err).ToNot(HaveOccurred(), "could not get installplan at complete phase") 385 386 ctx.Ctx().Logf("install plan %s completed", installPlanRef) 387 388 By(`confirm extra bundle objects (secret and configmap) are installed`) 389 Eventually(func() error { 390 _, err := kubeClient.GetSecret(generatedNamespace.GetName(), secretName) 391 return err 392 }).Should(Succeed(), "expected no error getting secret object associated with CSV") 393 394 Eventually(func() error { 395 _, err := kubeClient.GetConfigMap(generatedNamespace.GetName(), configmapName) 396 return err 397 }).Should(Succeed(), "expected no error getting configmap object associated with CSV") 398 }) 399 400 When("the CSV is deleted", func() { 401 402 const csvName = "busybox.v2.0.0" 403 404 BeforeEach(func() { 405 By(`Delete subscription first`) 406 Eventually(func() bool { 407 err := operatorClient.OperatorsV1alpha1().Subscriptions(generatedNamespace.GetName()).Delete(context.Background(), subName, metav1.DeleteOptions{}) 408 return apierrors.IsNotFound(err) 409 }).Should(BeTrue()) 410 411 By(`wait for deletion`) 412 Eventually(func() bool { 413 _, err := operatorClient.OperatorsV1alpha1().Subscriptions(generatedNamespace.GetName()).Get(context.Background(), subName, metav1.GetOptions{}) 414 return apierrors.IsNotFound(err) 415 }).Should(BeTrue()) 416 417 By(`Delete CSV`) 418 Eventually(func() bool { 419 err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(generatedNamespace.GetName()).Delete(context.Background(), csvName, metav1.DeleteOptions{}) 420 return apierrors.IsNotFound(err) 421 }).Should(BeTrue()) 422 423 By(`wait for deletion`) 424 Eventually(func() bool { 425 _, err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(generatedNamespace.GetName()).Get(context.Background(), csvName, metav1.GetOptions{}) 426 return apierrors.IsNotFound(err) 427 }).Should(BeTrue()) 428 }) 429 430 It("OLM should delete the associated configmap and secret", func() { 431 By(`confirm extra bundle objects (secret and configmap) are no longer installed on the cluster`) 432 Eventually(func() bool { 433 _, err := kubeClient.GetSecret(generatedNamespace.GetName(), secretName) 434 return apierrors.IsNotFound(err) 435 }).Should(BeTrue()) 436 437 Eventually(func() bool { 438 _, err := kubeClient.GetConfigMap(generatedNamespace.GetName(), configmapName) 439 return apierrors.IsNotFound(err) 440 }).Should(BeTrue()) 441 ctx.Ctx().Logf("dependent successfully garbage collected after csv owner was deleted") 442 }) 443 }) 444 }) 445 446 When("a bundle with a configmap is installed", func() { 447 448 const ( 449 subName = "test-subscription" 450 configmapName = "special-config" 451 ) 452 453 BeforeEach(func() { 454 const ( 455 packageName = "busybox" 456 channelName = "alpha" 457 sourceName = "test-catalog" 458 imageName = "quay.io/olmtest/single-bundle-index:objects-upgrade-samename" 459 ) 460 461 var installPlanRef string 462 By(`create catalog source`) 463 source := &v1alpha1.CatalogSource{ 464 TypeMeta: metav1.TypeMeta{ 465 Kind: v1alpha1.CatalogSourceKind, 466 APIVersion: v1alpha1.CatalogSourceCRDAPIVersion, 467 }, 468 ObjectMeta: metav1.ObjectMeta{ 469 Name: sourceName, 470 Namespace: generatedNamespace.GetName(), 471 Labels: map[string]string{"olm.catalogSource": sourceName}, 472 }, 473 Spec: v1alpha1.CatalogSourceSpec{ 474 SourceType: v1alpha1.SourceTypeGrpc, 475 Image: imageName, 476 GrpcPodConfig: &v1alpha1.GrpcPodConfig{ 477 SecurityContextConfig: v1alpha1.Restricted, 478 }, 479 }, 480 } 481 482 var err error 483 Eventually(func() error { 484 source, err = operatorClient.OperatorsV1alpha1().CatalogSources(source.GetNamespace()).Create(context.Background(), source, metav1.CreateOptions{}) 485 return err 486 }).Should(Succeed(), "could not create catalog source") 487 488 By(`Wait for the CatalogSource to be ready`) 489 _, err = fetchCatalogSourceOnStatus(operatorClient, source.GetName(), source.GetNamespace(), catalogSourceRegistryPodSynced()) 490 Expect(err).ToNot(HaveOccurred(), "catalog source did not become ready") 491 492 By(`Create a Subscription for package`) 493 _ = createSubscriptionForCatalog(operatorClient, source.GetNamespace(), subName, source.GetName(), packageName, channelName, "", v1alpha1.ApprovalAutomatic) 494 495 By(`Wait for the Subscription to succeed`) 496 sub, err := fetchSubscription(operatorClient, generatedNamespace.GetName(), subName, subscriptionStateAtLatestChecker()) 497 Expect(err).ToNot(HaveOccurred(), "could not get subscription at latest status") 498 499 installPlanRef = sub.Status.InstallPlanRef.Name 500 501 By(`Wait for the installplan to complete (5 minute timeout)`) 502 _, err = fetchInstallPlan(GinkgoT(), operatorClient, installPlanRef, generatedNamespace.GetName(), buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseComplete)) 503 Expect(err).ToNot(HaveOccurred(), "could not get installplan at complete phase") 504 505 Eventually(func() error { 506 _, err := kubeClient.GetConfigMap(generatedNamespace.GetName(), configmapName) 507 return err 508 }).Should(Succeed(), "expected no error getting configmap object associated with CSV") 509 }) 510 511 When("the subscription is updated to a later CSV with a configmap with the same name but new data", func() { 512 513 const ( 514 upgradeChannelName = "beta" 515 newCSVname = "busybox.v3.0.0" 516 ) 517 var installPlanRef string 518 519 BeforeEach(func() { 520 Eventually(func() error { 521 By(`update subscription first`) 522 sub, err := operatorClient.OperatorsV1alpha1().Subscriptions(generatedNamespace.GetName()).Get(context.Background(), subName, metav1.GetOptions{}) 523 if err != nil { 524 return fmt.Errorf("could not get subscription") 525 } 526 By(`update channel on sub`) 527 sub.Spec.Channel = upgradeChannelName 528 _, err = operatorClient.OperatorsV1alpha1().Subscriptions(generatedNamespace.GetName()).Update(context.Background(), sub, metav1.UpdateOptions{}) 529 return err 530 }).Should(Succeed(), "could not update subscription") 531 532 By(`Wait for the Subscription to succeed`) 533 sub, err := fetchSubscription(operatorClient, generatedNamespace.GetName(), subName, subscriptionStateAtLatestChecker()) 534 Expect(err).ToNot(HaveOccurred(), "could not get subscription at latest status") 535 536 installPlanRef = sub.Status.InstallPlanRef.Name 537 538 By(`Wait for the installplan to complete (5 minute timeout)`) 539 _, err = fetchInstallPlan(GinkgoT(), operatorClient, installPlanRef, generatedNamespace.GetName(), buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseComplete)) 540 Expect(err).ToNot(HaveOccurred(), "could not get installplan at complete phase") 541 542 By(`Ensure the new csv is installed`) 543 Eventually(func() error { 544 _, err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(generatedNamespace.GetName()).Get(context.Background(), newCSVname, metav1.GetOptions{}) 545 return err 546 }).Should(BeNil()) 547 }) 548 549 It("OLM should have upgraded associated configmap in place", func() { 550 Eventually(func() (string, error) { 551 cfg, err := kubeClient.GetConfigMap(generatedNamespace.GetName(), configmapName) 552 if err != nil { 553 return "", err 554 } 555 By(`check data in configmap to ensure it is the new data (configmap was updated in the newer bundle)`) 556 By(`new value in the configmap is "updated-very-much"`) 557 return cfg.Data["special.how"], nil 558 }).Should(Equal("updated-very-much")) 559 ctx.Ctx().Logf("dependent successfully updated after csv owner was updated") 560 }) 561 }) 562 }) 563 564 When("a bundle with a new configmap is installed", func() { 565 566 const ( 567 subName = "test-subscription" 568 configmapName = "special-config" 569 ) 570 571 BeforeEach(func() { 572 const ( 573 packageName = "busybox" 574 channelName = "alpha" 575 sourceName = "test-catalog" 576 imageName = "quay.io/olmtest/single-bundle-index:objects-upgrade-diffname" 577 ) 578 579 var installPlanRef string 580 By(`create catalog source`) 581 source := &v1alpha1.CatalogSource{ 582 TypeMeta: metav1.TypeMeta{ 583 Kind: v1alpha1.CatalogSourceKind, 584 APIVersion: v1alpha1.CatalogSourceCRDAPIVersion, 585 }, 586 ObjectMeta: metav1.ObjectMeta{ 587 Name: sourceName, 588 Namespace: generatedNamespace.GetName(), 589 Labels: map[string]string{"olm.catalogSource": sourceName}, 590 }, 591 Spec: v1alpha1.CatalogSourceSpec{ 592 SourceType: v1alpha1.SourceTypeGrpc, 593 Image: imageName, 594 GrpcPodConfig: &v1alpha1.GrpcPodConfig{ 595 SecurityContextConfig: v1alpha1.Restricted, 596 }, 597 }, 598 } 599 600 var err error 601 Eventually(func() error { 602 source, err = operatorClient.OperatorsV1alpha1().CatalogSources(source.GetNamespace()).Create(context.Background(), source, metav1.CreateOptions{}) 603 return err 604 }).Should(Succeed()) 605 606 By(`Wait for the CatalogSource to be ready`) 607 _, err = fetchCatalogSourceOnStatus(operatorClient, source.GetName(), source.GetNamespace(), catalogSourceRegistryPodSynced()) 608 Expect(err).ToNot(HaveOccurred(), "catalog source did not become ready") 609 610 By(`Create a Subscription for package`) 611 _ = createSubscriptionForCatalog(operatorClient, source.GetNamespace(), subName, source.GetName(), packageName, channelName, "", v1alpha1.ApprovalAutomatic) 612 613 By(`Wait for the Subscription to succeed`) 614 sub, err := fetchSubscription(operatorClient, generatedNamespace.GetName(), subName, subscriptionStateAtLatestChecker()) 615 Expect(err).ToNot(HaveOccurred(), "could not get subscription at latest status") 616 617 installPlanRef = sub.Status.InstallPlanRef.Name 618 619 By(`Wait for the installplan to complete (5 minute timeout)`) 620 _, err = fetchInstallPlan(GinkgoT(), operatorClient, installPlanRef, generatedNamespace.GetName(), buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseComplete)) 621 Expect(err).ToNot(HaveOccurred(), "could not get installplan at complete phase") 622 623 Eventually(func() error { 624 _, err := kubeClient.GetConfigMap(generatedNamespace.GetName(), configmapName) 625 return err 626 }).Should(Succeed(), "expected no error getting configmap object associated with CSV") 627 }) 628 629 When("the subscription is updated to a later CSV with a configmap with a new name", func() { 630 631 const ( 632 upgradeChannelName = "beta" 633 upgradedConfigMapName = "not-special-config" 634 newCSVname = "busybox.v3.0.0" 635 ) 636 var installPlanRef string 637 638 BeforeEach(func() { 639 Eventually(func() error { 640 By(`update subscription first`) 641 sub, err := operatorClient.OperatorsV1alpha1().Subscriptions(generatedNamespace.GetName()).Get(context.Background(), subName, metav1.GetOptions{}) 642 if err != nil { 643 return fmt.Errorf("could not get subscription") 644 } 645 By(`update channel on sub`) 646 sub.Spec.Channel = upgradeChannelName 647 _, err = operatorClient.OperatorsV1alpha1().Subscriptions(generatedNamespace.GetName()).Update(context.Background(), sub, metav1.UpdateOptions{}) 648 return err 649 }).Should(Succeed(), "could not update subscription") 650 651 By(`Wait for the Subscription to succeed`) 652 sub, err := fetchSubscription(operatorClient, generatedNamespace.GetName(), subName, subscriptionStateAtLatestChecker()) 653 Expect(err).ToNot(HaveOccurred(), "could not get subscription at latest status") 654 655 installPlanRef = sub.Status.InstallPlanRef.Name 656 657 By(`Wait for the installplan to complete (5 minute timeout)`) 658 _, err = fetchInstallPlan(GinkgoT(), operatorClient, installPlanRef, generatedNamespace.GetName(), buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseComplete)) 659 Expect(err).ToNot(HaveOccurred(), "could not get installplan at complete phase") 660 661 By(`Ensure the new csv is installed`) 662 Eventually(func() error { 663 _, err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(generatedNamespace.GetName()).Get(context.Background(), newCSVname, metav1.GetOptions{}) 664 return err 665 }).Should(BeNil()) 666 }) 667 668 It("[FLAKE] should have removed the old configmap and put the new configmap in place", func() { 669 By(`flake issue: https://github.com/operator-framework/operator-lifecycle-manager/issues/2626`) 670 Eventually(func() bool { 671 _, err := kubeClient.GetConfigMap(generatedNamespace.GetName(), configmapName) 672 return apierrors.IsNotFound(err) 673 }).Should(BeTrue()) 674 675 Eventually(func() error { 676 _, err := kubeClient.GetConfigMap(generatedNamespace.GetName(), upgradedConfigMapName) 677 return err 678 }).Should(BeNil()) 679 ctx.Ctx().Logf("dependent successfully updated after csv owner was updated") 680 }) 681 }) 682 }) 683 })