Skip to content

Commit 2159df5

Browse files
Merge pull request #1516 from exdx/fix/bug-1833195
Bug 1833195: delete bundle objects after CSV gets deleted
2 parents 110997c + ebbf8f1 commit 2159df5

File tree

3 files changed

+328
-2
lines changed

3 files changed

+328
-2
lines changed

pkg/controller/operators/catalog/operator.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1509,6 +1509,23 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error {
15091509
if err != nil {
15101510
return errorwrap.Wrapf(err, "error parsing step manifest: %s", step.Resource.Name)
15111511
}
1512+
1513+
// add ownerrefs on the secret that point to the CSV in the bundle
1514+
if step.Resolving != "" {
1515+
owner := &v1alpha1.ClusterServiceVersion{}
1516+
owner.SetNamespace(plan.GetNamespace())
1517+
owner.SetName(step.Resolving)
1518+
ownerutil.AddNonBlockingOwner(&s, owner)
1519+
}
1520+
1521+
// Update UIDs on all CSV OwnerReferences
1522+
updated, err := o.getUpdatedOwnerReferences(s.OwnerReferences, plan.Namespace)
1523+
if err != nil {
1524+
return errorwrap.Wrapf(err, "error generating ownerrefs for secret %s", s.GetName())
1525+
}
1526+
s.SetOwnerReferences(updated)
1527+
s.SetNamespace(namespace)
1528+
15121529
status, err := ensurer.EnsureBundleSecret(plan.Namespace, &s)
15131530
if err != nil {
15141531
return err
@@ -1631,6 +1648,14 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error {
16311648
return errorwrap.Wrapf(err, "error parsing step manifest: %s", step.Resource.Name)
16321649
}
16331650

1651+
// add ownerrefs on the service that point to the CSV in the bundle
1652+
if step.Resolving != "" {
1653+
owner := &v1alpha1.ClusterServiceVersion{}
1654+
owner.SetNamespace(plan.GetNamespace())
1655+
owner.SetName(step.Resolving)
1656+
ownerutil.AddNonBlockingOwner(&s, owner)
1657+
}
1658+
16341659
// Update UIDs on all CSV OwnerReferences
16351660
updated, err := o.getUpdatedOwnerReferences(s.OwnerReferences, plan.Namespace)
16361661
if err != nil {
@@ -1653,6 +1678,14 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error {
16531678
return errorwrap.Wrapf(err, "error parsing step manifest: %s", step.Resource.Name)
16541679
}
16551680

1681+
// add ownerrefs on the configmap that point to the CSV in the bundle
1682+
if step.Resolving != "" {
1683+
owner := &v1alpha1.ClusterServiceVersion{}
1684+
owner.SetNamespace(plan.GetNamespace())
1685+
owner.SetName(step.Resolving)
1686+
ownerutil.AddNonBlockingOwner(&cfg, owner)
1687+
}
1688+
16561689
// Update UIDs on all CSV OwnerReferences
16571690
updated, err := o.getUpdatedOwnerReferences(cfg.OwnerReferences, plan.Namespace)
16581691
if err != nil {

pkg/lib/ownerutil/util.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,18 @@ func InferGroupVersionKind(obj runtime.Object) error {
314314
Version: "v1",
315315
Kind: "ServiceAccount",
316316
})
317+
case *corev1.ConfigMap:
318+
objectKind.SetGroupVersionKind(schema.GroupVersionKind{
319+
Group: "",
320+
Version: "v1",
321+
Kind: "ConfigMap",
322+
})
323+
case *corev1.Secret:
324+
objectKind.SetGroupVersionKind(schema.GroupVersionKind{
325+
Group: "",
326+
Version: "v1",
327+
Kind: "Secret",
328+
})
317329
case *rbac.ClusterRole:
318330
objectKind.SetGroupVersionKind(schema.GroupVersionKind{
319331
Group: "rbac.authorization.k8s.io",

test/e2e/gc_e2e_test.go

Lines changed: 283 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ package e2e
33
import (
44
"context"
55
"fmt"
6-
"github.com/operator-framework/api/pkg/operators/v1alpha1"
76

87
"github.com/blang/semver"
98
. "github.com/onsi/ginkgo"
109
. "github.com/onsi/gomega"
10+
. "github.com/operator-framework/operator-lifecycle-manager/test/e2e/dsl"
1111
corev1 "k8s.io/api/core/v1"
1212
rbacv1 "k8s.io/api/rbac/v1"
1313
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
@@ -16,11 +16,11 @@ import (
1616
"k8s.io/apimachinery/pkg/util/rand"
1717
apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
1818

19+
"github.com/operator-framework/api/pkg/operators/v1alpha1"
1920
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned"
2021
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient"
2122
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil"
2223
"github.com/operator-framework/operator-lifecycle-manager/test/e2e/ctx"
23-
. "github.com/operator-framework/operator-lifecycle-manager/test/e2e/dsl"
2424
)
2525

2626
var _ = Describe("Garbage collection for dependent resources", func() {
@@ -284,4 +284,285 @@ var _ = Describe("Garbage collection for dependent resources", func() {
284284

285285
})
286286

287+
When("a bundle with configmap and secret objects is installed", func() {
288+
const (
289+
packageName = "busybox"
290+
channelName = "alpha"
291+
subName = "test-subscription"
292+
secretName = "mysecret"
293+
configmapName = "special-config"
294+
)
295+
296+
BeforeEach(func() {
297+
const (
298+
sourceName = "test-catalog"
299+
imageName = "quay.io/olmtest/single-bundle-index:objects"
300+
)
301+
// create catalog source
302+
source := &v1alpha1.CatalogSource{
303+
TypeMeta: metav1.TypeMeta{
304+
Kind: v1alpha1.CatalogSourceKind,
305+
APIVersion: v1alpha1.CatalogSourceCRDAPIVersion,
306+
},
307+
ObjectMeta: metav1.ObjectMeta{
308+
Name: sourceName,
309+
Namespace: testNamespace,
310+
Labels: map[string]string{"olm.catalogSource": sourceName},
311+
},
312+
Spec: v1alpha1.CatalogSourceSpec{
313+
SourceType: v1alpha1.SourceTypeGrpc,
314+
Image: imageName,
315+
},
316+
}
317+
318+
source, err := operatorClient.OperatorsV1alpha1().CatalogSources(source.GetNamespace()).Create(context.TODO(), source, metav1.CreateOptions{})
319+
Expect(err).ToNot(HaveOccurred(), "could not create catalog source")
320+
321+
// Create a Subscription for package
322+
_ = createSubscriptionForCatalog(operatorClient, source.GetNamespace(), subName, source.GetName(), packageName, channelName, "", v1alpha1.ApprovalAutomatic)
323+
324+
// Wait for the Subscription to succeed
325+
Eventually(func() error {
326+
_, err = fetchSubscription(operatorClient, testNamespace, subName, subscriptionStateAtLatestChecker)
327+
return err
328+
}).Should(BeNil())
329+
330+
// confirm extra bundle objects (secret and configmap) are installed
331+
Eventually(func() error {
332+
_, err := kubeClient.GetSecret(testNamespace, secretName)
333+
return err
334+
}).Should(Succeed(), "expected no error getting secret object associated with CSV")
335+
336+
Eventually(func() error {
337+
_, err := kubeClient.GetConfigMap(testNamespace, configmapName)
338+
return err
339+
}).Should(Succeed(), "expected no error getting configmap object associated with CSV")
340+
})
341+
342+
When("the CSV is deleted", func() {
343+
const csvName = "busybox.v2.0.0"
344+
345+
BeforeEach(func() {
346+
// Delete subscription first
347+
err := operatorClient.OperatorsV1alpha1().Subscriptions(testNamespace).Delete(context.TODO(), subName, metav1.DeleteOptions{})
348+
Expect(err).To(BeNil())
349+
350+
// wait for deletion
351+
Eventually(func() bool {
352+
_, err := operatorClient.OperatorsV1alpha1().Subscriptions(testNamespace).Get(context.TODO(), subName, metav1.GetOptions{})
353+
return k8serrors.IsNotFound(err)
354+
}).Should(BeTrue())
355+
356+
// Delete CSV
357+
err = operatorClient.OperatorsV1alpha1().ClusterServiceVersions(testNamespace).Delete(context.TODO(), csvName, metav1.DeleteOptions{})
358+
Expect(err).To(BeNil())
359+
360+
// wait for deletion
361+
Eventually(func() bool {
362+
_, err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(testNamespace).Get(context.TODO(), csvName, metav1.GetOptions{})
363+
return k8serrors.IsNotFound(err)
364+
}).Should(BeTrue())
365+
})
366+
367+
It("OLM should delete the associated configmap and secret", func() {
368+
// confirm extra bundle objects (secret and configmap) are no longer installed on the cluster
369+
Eventually(func() bool {
370+
_, err := kubeClient.GetSecret(testNamespace, secretName)
371+
return k8serrors.IsNotFound(err)
372+
}).Should(BeTrue())
373+
374+
Eventually(func() bool {
375+
_, err := kubeClient.GetConfigMap(testNamespace, configmapName)
376+
return k8serrors.IsNotFound(err)
377+
}).Should(BeTrue())
378+
ctx.Ctx().Logf("dependent successfully garbage collected after csv owner was deleted")
379+
})
380+
})
381+
})
382+
383+
When("a bundle with a configmap is installed", func() {
384+
const (
385+
subName = "test-subscription"
386+
configmapName = "special-config"
387+
)
388+
389+
BeforeEach(func() {
390+
const (
391+
packageName = "busybox"
392+
channelName = "alpha"
393+
sourceName = "test-catalog"
394+
imageName = "quay.io/olmtest/single-bundle-index:objects-upgrade-samename"
395+
)
396+
// create catalog source
397+
source := &v1alpha1.CatalogSource{
398+
TypeMeta: metav1.TypeMeta{
399+
Kind: v1alpha1.CatalogSourceKind,
400+
APIVersion: v1alpha1.CatalogSourceCRDAPIVersion,
401+
},
402+
ObjectMeta: metav1.ObjectMeta{
403+
Name: sourceName,
404+
Namespace: testNamespace,
405+
Labels: map[string]string{"olm.catalogSource": sourceName},
406+
},
407+
Spec: v1alpha1.CatalogSourceSpec{
408+
SourceType: v1alpha1.SourceTypeGrpc,
409+
Image: imageName,
410+
},
411+
}
412+
413+
source, err := operatorClient.OperatorsV1alpha1().CatalogSources(source.GetNamespace()).Create(context.TODO(), source, metav1.CreateOptions{})
414+
Expect(err).ToNot(HaveOccurred(), "could not create catalog source")
415+
416+
// Create a Subscription for package
417+
_ = createSubscriptionForCatalog(operatorClient, source.GetNamespace(), subName, source.GetName(), packageName, channelName, "", v1alpha1.ApprovalAutomatic)
418+
419+
// Wait for the Subscription to succeed
420+
Eventually(func() error {
421+
_, err = fetchSubscription(operatorClient, testNamespace, subName, subscriptionStateAtLatestChecker)
422+
return err
423+
}).Should(BeNil())
424+
425+
Eventually(func() error {
426+
_, err := kubeClient.GetConfigMap(testNamespace, configmapName)
427+
return err
428+
}).Should(Succeed(), "expected no error getting configmap object associated with CSV")
429+
})
430+
431+
When("the subscription is updated to a later CSV with a configmap with the same name but new data", func() {
432+
const (
433+
upgradeChannelName = "beta"
434+
newCSVname = "busybox.v3.0.0"
435+
)
436+
437+
BeforeEach(func() {
438+
// update subscription first
439+
sub, err := operatorClient.OperatorsV1alpha1().Subscriptions(testNamespace).Get(context.TODO(), subName, metav1.GetOptions{})
440+
Expect(err).ToNot(HaveOccurred(), "could not get subscription")
441+
442+
// update channel on sub
443+
sub.Spec.Channel = upgradeChannelName
444+
_, err = operatorClient.OperatorsV1alpha1().Subscriptions(testNamespace).Update(context.TODO(), sub, metav1.UpdateOptions{})
445+
Expect(err).ToNot(HaveOccurred(), "could not update subscription")
446+
447+
// Wait for the Subscription to succeed
448+
Eventually(func() error {
449+
_, err = fetchSubscription(operatorClient, testNamespace, subName, subscriptionStateAtLatestChecker)
450+
return err
451+
}).Should(BeNil())
452+
453+
// Ensure the new csv is installed
454+
Eventually(func() error {
455+
_, err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(testNamespace).Get(context.TODO(), newCSVname, metav1.GetOptions{})
456+
return err
457+
}).Should(BeNil())
458+
})
459+
460+
It("OLM should have upgraded associated configmap in place", func() {
461+
Eventually(func() bool {
462+
cfg, err := kubeClient.GetConfigMap(testNamespace, configmapName)
463+
if err != nil {
464+
return false
465+
}
466+
// check data in configmap to ensure it is the new data (configmap was updated in the newer bundle)
467+
// new value in the configmap is "updated-very-much"
468+
data := cfg.Data["special.how"]
469+
return data == "updated-very-much"
470+
}).Should(BeTrue())
471+
ctx.Ctx().Logf("dependent successfully updated after csv owner was updated")
472+
})
473+
})
474+
})
475+
476+
When("a bundle with a new configmap is installed", func() {
477+
const (
478+
subName = "test-subscription"
479+
configmapName = "special-config"
480+
)
481+
482+
BeforeEach(func() {
483+
const (
484+
packageName = "busybox"
485+
channelName = "alpha"
486+
sourceName = "test-catalog"
487+
imageName = "quay.io/olmtest/single-bundle-index:objects-upgrade-diffname"
488+
)
489+
// create catalog source
490+
source := &v1alpha1.CatalogSource{
491+
TypeMeta: metav1.TypeMeta{
492+
Kind: v1alpha1.CatalogSourceKind,
493+
APIVersion: v1alpha1.CatalogSourceCRDAPIVersion,
494+
},
495+
ObjectMeta: metav1.ObjectMeta{
496+
Name: sourceName,
497+
Namespace: testNamespace,
498+
Labels: map[string]string{"olm.catalogSource": sourceName},
499+
},
500+
Spec: v1alpha1.CatalogSourceSpec{
501+
SourceType: v1alpha1.SourceTypeGrpc,
502+
Image: imageName,
503+
},
504+
}
505+
506+
source, err := operatorClient.OperatorsV1alpha1().CatalogSources(source.GetNamespace()).Create(context.TODO(), source, metav1.CreateOptions{})
507+
Expect(err).ToNot(HaveOccurred(), "could not create catalog source")
508+
509+
// Create a Subscription for package
510+
_ = createSubscriptionForCatalog(operatorClient, source.GetNamespace(), subName, source.GetName(), packageName, channelName, "", v1alpha1.ApprovalAutomatic)
511+
512+
// Wait for the Subscription to succeed
513+
Eventually(func() error {
514+
_, err = fetchSubscription(operatorClient, testNamespace, subName, subscriptionStateAtLatestChecker)
515+
return err
516+
}).Should(BeNil())
517+
518+
Eventually(func() error {
519+
_, err := kubeClient.GetConfigMap(testNamespace, configmapName)
520+
return err
521+
}).Should(Succeed(), "expected no error getting configmap object associated with CSV")
522+
})
523+
524+
When("the subscription is updated to a later CSV with a configmap with a new name", func() {
525+
const (
526+
upgradeChannelName = "beta"
527+
upgradedConfigMapName = "not-special-config"
528+
newCSVname = "busybox.v3.0.0"
529+
)
530+
531+
BeforeEach(func() {
532+
// update subscription first
533+
sub, err := operatorClient.OperatorsV1alpha1().Subscriptions(testNamespace).Get(context.TODO(), subName, metav1.GetOptions{})
534+
Expect(err).ToNot(HaveOccurred(), "could not get subscription")
535+
536+
// update channel on sub
537+
sub.Spec.Channel = upgradeChannelName
538+
_, err = operatorClient.OperatorsV1alpha1().Subscriptions(testNamespace).Update(context.TODO(), sub, metav1.UpdateOptions{})
539+
Expect(err).ToNot(HaveOccurred(), "could not update subscription")
540+
541+
// Wait for the Subscription to succeed
542+
Eventually(func() error {
543+
_, err = fetchSubscription(operatorClient, testNamespace, subName, subscriptionStateAtLatestChecker)
544+
return err
545+
}).Should(BeNil())
546+
547+
// Ensure the new csv is installed
548+
Eventually(func() error {
549+
_, err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(testNamespace).Get(context.TODO(), newCSVname, metav1.GetOptions{})
550+
return err
551+
}).Should(BeNil())
552+
})
553+
554+
It("should have removed the old configmap and put the new configmap in place", func() {
555+
Eventually(func() bool {
556+
_, err := kubeClient.GetConfigMap(testNamespace, configmapName)
557+
return k8serrors.IsNotFound(err)
558+
}).Should(BeTrue())
559+
560+
Eventually(func() error {
561+
_, err := kubeClient.GetConfigMap(testNamespace, upgradedConfigMapName)
562+
return err
563+
}).Should(BeNil())
564+
ctx.Ctx().Logf("dependent successfully updated after csv owner was updated")
565+
})
566+
})
567+
})
287568
})

0 commit comments

Comments
 (0)