github.com/operator-framework/operator-lifecycle-manager@v0.30.0/test/e2e/bundle_e2e_test.go (about) 1 package e2e 2 3 import ( 4 "context" 5 _ "embed" 6 "encoding/json" 7 8 "github.com/ghodss/yaml" 9 corev1 "k8s.io/api/core/v1" 10 apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" 11 apierrors "k8s.io/apimachinery/pkg/api/errors" 12 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 13 14 . "github.com/onsi/ginkgo/v2" 15 . "github.com/onsi/gomega" 16 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 17 "k8s.io/apimachinery/pkg/runtime/schema" 18 "k8s.io/client-go/dynamic" 19 20 "github.com/operator-framework/api/pkg/operators/v1alpha1" 21 "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned" 22 "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient" 23 "github.com/operator-framework/operator-lifecycle-manager/test/e2e/ctx" 24 ) 25 26 //go:embed testdata/vpa/crd.yaml 27 var vpaCRDRaw []byte 28 29 var _ = Describe("Installing bundles with new object types", func() { 30 var ( 31 kubeClient operatorclient.ClientInterface 32 operatorClient versioned.Interface 33 dynamicClient dynamic.Interface 34 generatedNamespace corev1.Namespace 35 ) 36 37 BeforeEach(func() { 38 kubeClient = ctx.Ctx().KubeClient() 39 operatorClient = ctx.Ctx().OperatorClient() 40 dynamicClient = ctx.Ctx().DynamicClient() 41 42 By("creating a test namespace") 43 generatedNamespace = SetupGeneratedTestNamespace(genName("bundle-e2e-")) 44 }) 45 46 AfterEach(func() { 47 TeardownNamespace(generatedNamespace.GetName()) 48 }) 49 50 When("a bundle with a pdb, priorityclass, and VPA object is installed", func() { 51 const ( 52 packageName = "busybox" 53 channelName = "alpha" 54 subName = "test-subscription" 55 ) 56 var vpaCRD unstructured.Unstructured 57 58 BeforeEach(func() { 59 By("first installing the VPA CRD on cluster") 60 const ( 61 sourceName = "test-catalog" 62 imageName = "quay.io/olmtest/single-bundle-index:pdb-v1" 63 ) 64 65 By("create VPA CRD on cluster") 66 Expect(vpaCRDRaw).ToNot(BeEmpty(), "could not read vpa bindata") 67 data, err := yaml.YAMLToJSON(vpaCRDRaw) 68 Expect(err).ToNot(HaveOccurred(), "could not convert vpa crd to json") 69 70 err = json.Unmarshal(data, &vpaCRD) 71 Expect(err).ToNot(HaveOccurred(), "could not convert vpa crd to unstructured") 72 73 Eventually(func() error { 74 err := ctx.Ctx().Client().Create(context.Background(), &vpaCRD) 75 if err != nil { 76 if !apierrors.IsAlreadyExists(err) { 77 return err 78 } 79 } 80 return nil 81 }).Should(Succeed()) 82 83 By("ensure vpa crd is established and accepted on the cluster before continuing") 84 Eventually(func() (bool, error) { 85 crd, err := kubeClient.ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Get(context.Background(), vpaCRD.GetName(), metav1.GetOptions{}) 86 if err != nil { 87 return false, err 88 } 89 return crdReady(&crd.Status), nil 90 }).Should(BeTrue()) 91 92 source := &v1alpha1.CatalogSource{ 93 TypeMeta: metav1.TypeMeta{ 94 Kind: v1alpha1.CatalogSourceKind, 95 APIVersion: v1alpha1.CatalogSourceCRDAPIVersion, 96 }, 97 ObjectMeta: metav1.ObjectMeta{ 98 Name: sourceName, 99 Namespace: generatedNamespace.GetName(), 100 Labels: map[string]string{"olm.catalogSource": sourceName}, 101 }, 102 Spec: v1alpha1.CatalogSourceSpec{ 103 SourceType: v1alpha1.SourceTypeGrpc, 104 Image: imageName, 105 GrpcPodConfig: &v1alpha1.GrpcPodConfig{ 106 SecurityContextConfig: v1alpha1.Restricted, 107 }, 108 }, 109 } 110 111 Eventually(func() error { 112 source, err = operatorClient.OperatorsV1alpha1().CatalogSources(source.GetNamespace()).Create(context.Background(), source, metav1.CreateOptions{}) 113 return err 114 }).Should(Succeed()) 115 116 By("Wait for the CatalogSource to be ready") 117 _, err = fetchCatalogSourceOnStatus(operatorClient, source.GetName(), source.GetNamespace(), catalogSourceRegistryPodSynced()) 118 Expect(err).ToNot(HaveOccurred(), "catalog source did not become ready") 119 120 By("Create a Subscription for package") 121 _ = createSubscriptionForCatalog(operatorClient, source.GetNamespace(), subName, source.GetName(), packageName, channelName, "", v1alpha1.ApprovalAutomatic) 122 123 By("Wait for the Subscription to succeed") 124 sub, err := fetchSubscription(operatorClient, generatedNamespace.GetName(), subName, subscriptionStateAtLatestChecker()) 125 Expect(err).ToNot(HaveOccurred(), "could not get subscription at latest status") 126 127 installPlanRef := sub.Status.InstallPlanRef 128 129 By("Wait for the installplan to complete (5 minute timeout)") 130 _, err = fetchInstallPlanWithNamespace(GinkgoT(), operatorClient, installPlanRef.Name, installPlanRef.Namespace, buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseComplete)) 131 Expect(err).ToNot(HaveOccurred(), "could not get installplan at complete phase") 132 133 ctx.Ctx().Logf("install plan %s completed", installPlanRef) 134 }) 135 136 It("should create the additional bundle objects", func() { 137 const ( 138 vpaGroup = "autoscaling.k8s.io" 139 vpaVersion = "v1" 140 vpaResource = "verticalpodautoscalers" 141 pdbName = "busybox-pdb" 142 priorityClassName = "super-priority" 143 vpaName = "busybox-vpa" 144 ) 145 146 var resource = schema.GroupVersionResource{ 147 Group: vpaGroup, 148 Version: vpaVersion, 149 Resource: vpaResource, 150 } 151 152 By("confirm extra bundle objects are installed") 153 Eventually(func() error { 154 _, err := kubeClient.KubernetesInterface().SchedulingV1().PriorityClasses().Get(context.Background(), priorityClassName, metav1.GetOptions{}) 155 return err 156 }).Should(Succeed(), "expected no error getting priorityclass object associated with CSV") 157 158 Eventually(func() error { 159 _, err := dynamicClient.Resource(resource).Namespace(generatedNamespace.GetName()).Get(context.Background(), vpaName, metav1.GetOptions{}) 160 return err 161 }).Should(Succeed(), "expected no error finding vpa object associated with csv") 162 163 Eventually(func() error { 164 _, err := kubeClient.KubernetesInterface().PolicyV1().PodDisruptionBudgets(generatedNamespace.GetName()).Get(context.Background(), pdbName, metav1.GetOptions{}) 165 return err 166 }).Should(Succeed(), "expected no error getting pdb object associated with CSV") 167 }) 168 169 AfterEach(func() { 170 By("Deleting the VPA CRD") 171 Eventually(func() error { 172 err := ctx.Ctx().Client().Delete(context.Background(), &vpaCRD) 173 if apierrors.IsNotFound(err) { 174 return nil 175 } 176 return err 177 }).Should(Succeed()) 178 }) 179 }) 180 }) 181 182 func crdReady(status *apiextensionsv1.CustomResourceDefinitionStatus) bool { 183 if status == nil { 184 return false 185 } 186 established, namesAccepted := false, false 187 for _, cdt := range status.Conditions { 188 switch cdt.Type { 189 case apiextensionsv1.Established: 190 if cdt.Status == apiextensionsv1.ConditionTrue { 191 established = true 192 } 193 case apiextensionsv1.NamesAccepted: 194 if cdt.Status == apiextensionsv1.ConditionTrue { 195 namesAccepted = true 196 } 197 } 198 } 199 return established && namesAccepted 200 }