timflannagan / rukpak

Rukpak runs in a Kubernetes cluster and defines an API for installing cloud native bundle content
Apache License 2.0
0 stars 0 forks source link

[tflannag] Right now deleting an unpacked Bundle after the BI stamped #6

Closed github-actions[bot] closed 2 years ago

github-actions[bot] commented 2 years ago

out it's contents reset's the Bundle's lookup information from BI's status

but the unpacked resources are still present on the cluster. This is because

the BI places ownerreferences on these resources, but the condition we write

to it's status can be confusing to the end user as it implies the installation

failed and the resources aren't present on-cluster.

https://github.com/timflannagan/rukpak/blob/a902b4eead37583bcc557ab0fd6f02c44d53aafd/test/e2e/plain-v0_provisioner_test.go#L320


        })
    })
})

var _ = Describe("plain-v0 provisioner bundleinstance", func() {
    When("a BundleInstance targets a valid Bundle", func() {
        var (
            bundle *rukpakv1alpha1.Bundle
            bi     *rukpakv1alpha1.BundleInstance
            ctx    context.Context
        )
        BeforeEach(func() {
            ctx = context.Background()

            By("creating the testing Bundle resource")
            bundle = &rukpakv1alpha1.Bundle{
                ObjectMeta: metav1.ObjectMeta{
                    GenerateName: "olm-crds",
                },
                Spec: rukpakv1alpha1.BundleSpec{
                    ProvisionerClassName: plainProvisionerID,
                    Image:                "quay.io/tflannag/olm-plain-bundle:olm-crds-v0.20.0",
                },
            }
            err := c.Create(ctx, bundle)
            Expect(err).To(BeNil())

            bi = &rukpakv1alpha1.BundleInstance{
                ObjectMeta: metav1.ObjectMeta{
                    GenerateName: "olm-crds",
                },
                Spec: rukpakv1alpha1.BundleInstanceSpec{
                    ProvisionerClassName: plainProvisionerID,
                    BundleName:           bundle.GetName(),
                },
            }
            err = c.Create(ctx, bi)
            Expect(err).To(BeNil())
        })
        AfterEach(func() {
            By("deleting the testing Bundle resource")
            Eventually(func() error {
                return client.IgnoreNotFound(c.Delete(ctx, bundle))
            }).Should(Succeed())

            By("deleting the testing BundleInstance resource")
            Eventually(func() error {
                return c.Delete(ctx, bi)
            }).Should(Succeed())
        })

        It("should rollout the bundle contents successfully", func() {
            By("eventually writing a successful installation state back to the bundleinstance status")
            Eventually(func() bool {
                if err := c.Get(ctx, client.ObjectKeyFromObject(bi), bi); err != nil {
                    return false
                }
                if bi.Status.InstalledBundleName != bundle.GetName() {
                    return false
                }
                existing := meta.FindStatusCondition(bi.Status.Conditions, "Installed")
                if existing == nil {
                    return false
                }
                expected := metav1.Condition{
                    Type:    "Installed",
                    Status:  metav1.ConditionStatus(corev1.ConditionTrue),
                    Reason:  "InstallationSucceeded",
                    Message: "",
                }
                return conditionsSemanticallyEqual(expected, *existing)
            }).Should(BeTrue())

            By("eventually reseting a bundle lookup failure when the targeted bundle has been deleted")
            Eventually(func() error {
                return c.Delete(ctx, bundle)
            }).Should(Succeed())

            // TODO(tflannag): Right now deleting an unpacked Bundle after the BI stamped
            // out it's contents reset's the Bundle's lookup information from BI's status
            // but the unpacked resources are still present on the cluster. This is because
            // the BI places ownerreferences on these resources, but the condition we write
            // to it's status can be confusing to the end user as it implies the installation
            // failed and the resources aren't present on-cluster.
            Eventually(func() bool {
                if err := c.Get(ctx, client.ObjectKeyFromObject(bi), bi); err != nil {
                    return false
                }
                if bi.Status.InstalledBundleName != "" {
                    return false
                }
                existing := meta.FindStatusCondition(bi.Status.Conditions, "Installed")
                if existing == nil {
                    return false
                }
                expected := metav1.Condition{
                    Type:    "Installed",
                    Status:  metav1.ConditionStatus(corev1.ConditionFalse),
                    Reason:  "BundleLookupFailed",
                    Message: fmt.Sprintf(`Bundle.core.rukpak.io "%s" not found`, bundle.GetName()),
                }
                return conditionsSemanticallyEqual(expected, *existing)
            }).Should(BeTrue())
        })
    })

    When("a BundleInstance targets an invalid Bundle", func() {
        var (
            bundle *rukpakv1alpha1.Bundle
            bi     *rukpakv1alpha1.BundleInstance
            ctx    context.Context
        )
        BeforeEach(func() {
            ctx = context.Background()

            By("creating the testing Bundle resource")
            bundle = &rukpakv1alpha1.Bundle{
                ObjectMeta: metav1.ObjectMeta{
                    GenerateName: "olm-apis",
                },
                Spec: rukpakv1alpha1.BundleSpec{
                    ProvisionerClassName: plainProvisionerID,
                    Image:                "quay.io/tflannag/olm-plain-bundle:olm-api-v0.20.0",
                },
            }
            err := c.Create(ctx, bundle)
            Expect(err).To(BeNil())

            bi = &rukpakv1alpha1.BundleInstance{
                ObjectMeta: metav1.ObjectMeta{
                    GenerateName: "olm-apis",
                },
                Spec: rukpakv1alpha1.BundleInstanceSpec{
                    ProvisionerClassName: plainProvisionerID,
                    BundleName:           bundle.GetName(),
                },
            }
            err = c.Create(ctx, bi)
            Expect(err).To(BeNil())
        })
        AfterEach(func() {
            By("deleting the testing Bundle resource")
            Eventually(func() error {
                return client.IgnoreNotFound(c.Delete(ctx, bundle))
            }).Should(Succeed())

            By("deleting the testing BundleInstance resource")
            Eventually(func() error {
                return client.IgnoreNotFound(c.Delete(ctx, bi))
            }).Should(Succeed())
        })

        It("should project a failed installation state", func() {
            Eventually(func() bool {
                if err := c.Get(ctx, client.ObjectKeyFromObject(bi), bi); err != nil {
                    return false
                }
                if bi.Status.InstalledBundleName != "" {
                    return false
                }
                existing := meta.FindStatusCondition(bi.Status.Conditions, "Installed")
                if existing == nil {
                    return false
                }
                // TODO(tflannag): Add a custom error type for API-based Bundle installations that
                // are missing the requisite CRDs to be able to deploy the unpacked Bundle successfully.
                expectedMessage := `
                error while running post render on files: [unable to recognize "": no
                matches for kind "CatalogSource" in version "operators.coreos.com/v1alpha1",
                unable to recognize "": no matches for kind "ClusterServiceVersion" in version
                "operators.coreos.com/v1alpha1", unable to recognize "": no matches for kind
                "OLMConfig" in version "operators.coreos.com/v1", unable to recognize "": no
                matches for kind "OperatorGroup" in version "operators.coreos.com/v1"]
                `
                expected := metav1.Condition{
                    Type:    "Installed",
                    Status:  metav1.ConditionStatus(corev1.ConditionFalse),
                    Reason:  "InstallFailed",
                    Message: strings.Join(strings.Fields(expectedMessage), " "),
                }
                return conditionsSemanticallyEqual(expected, *existing)
            }).Should(BeTrue())
        })
    })
})

func conditionsSemanticallyEqual(a, b metav1.Condition) bool {
    return a.Type == b.Type && a.Status == b.Status && a.Reason == b.Reason && a.Message == b.Message
}
github-actions[bot] commented 2 years ago

Closed in 67f0345a5ab0a28d06b45b64f7110e7dbe2706be