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  }