Skip to content

Commit

Permalink
e2e test utilities update (#2799)
Browse files Browse the repository at this point in the history
* Update unpack job pod security (#2793)

* Update unpack job security

Signed-off-by: perdasilva <perdasilva@redhat.com>

* Refactor catsrc pod creation to use security package

Signed-off-by: perdasilva <perdasilva@redhat.com>

* Refactor MagicCatalog removing superfluous interface and add factory method to create from file

Signed-off-by: perdasilva <perdasilva@redhat.com>

* Switch TestContext client to be the e2e client and add crd garbage collection

Signed-off-by: perdasilva <perdasilva@redhat.com>

* Add determined e2e client that retries on failure

Signed-off-by: perdasilva <perdasilva@redhat.com>

* Small fixes

Signed-off-by: perdasilva <perdasilva@redhat.com>

* Add olm gomega assertions and matchers

Signed-off-by: perdasilva <perdasilva@redhat.com>
  • Loading branch information
perdasilva committed Jun 14, 2022
1 parent eedad28 commit a538831
Show file tree
Hide file tree
Showing 12 changed files with 327 additions and 71 deletions.
2 changes: 1 addition & 1 deletion test/e2e/catalog_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1349,7 +1349,7 @@ var _ = Describe("Starting CatalogSource e2e tests", func() {

When("A CatalogSource is created with an operator that has a CSV with missing metadata.ApiVersion", func() {
var (
magicCatalog MagicCatalog
magicCatalog *MagicCatalog
catalogSourceName string
subscription *operatorsv1alpha1.Subscription
c client.Client
Expand Down
9 changes: 2 additions & 7 deletions test/e2e/ctx/ctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,12 @@ import (
"os"
"os/exec"
"path/filepath"
"strings"

"github.com/operator-framework/operator-lifecycle-manager/test/e2e/util"
appsv1 "k8s.io/api/apps/v1"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"

g "github.com/onsi/ginkgo/v2"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/dynamic"
Expand Down Expand Up @@ -61,10 +59,7 @@ func Ctx() *TestContext {
}

func (ctx TestContext) Logf(f string, v ...interface{}) {
if !strings.HasSuffix(f, "\n") {
f += "\n"
}
fmt.Fprintf(g.GinkgoWriter, f, v...)
util.Logf(f, v...)
}

func (ctx TestContext) Scheme() *runtime.Scheme {
Expand Down Expand Up @@ -210,8 +205,8 @@ func setDerivedFields(ctx *TestContext) error {
if err != nil {
return err
}
ctx.client = client
ctx.e2eClient = util.NewK8sResourceManager(client)
ctx.client = ctx.e2eClient

ctx.ssaClient, err = controllerclient.NewForConfig(ctx.restConfig, ctx.scheme, "test.olm.registry")
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions test/e2e/fail_forward_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ var _ = Describe("Fail Forward Upgrades", func() {
When("an InstallPlan is reporting a failed state", func() {

var (
magicCatalog MagicCatalog
magicCatalog *MagicCatalog
catalogSourceName string
subscription *operatorsv1alpha1.Subscription
)
Expand Down Expand Up @@ -194,7 +194,7 @@ var _ = Describe("Fail Forward Upgrades", func() {
When("a CSV resource is in a failed state", func() {

var (
magicCatalog MagicCatalog
magicCatalog *MagicCatalog
catalogSourceName string
subscription *operatorsv1alpha1.Subscription
)
Expand Down
121 changes: 67 additions & 54 deletions test/e2e/magic_catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,20 @@ const (
catalogReadyState string = "READY"
)

type MagicCatalog interface {
DeployCatalog(ctx context.Context) error
UpdateCatalog(ctx context.Context, provider FileBasedCatalogProvider) error
UndeployCatalog(ctx context.Context) []error
}

type magicCatalog struct {
type MagicCatalog struct {
fileBasedCatalog FileBasedCatalogProvider
kubeClient k8scontrollerclient.Client
namespace string
name string
namespace string
configMapName string
serviceName string
podName string
}

// NewMagicCatalog creates an object that can deploy an arbitrary file-based catalog given by the FileBasedCatalogProvider
// Keep in mind that there are limits to the configMaps. So, the catalogs need to be relatively simple
func NewMagicCatalog(kubeClient k8scontrollerclient.Client, namespace string, catalogName string, provider FileBasedCatalogProvider) MagicCatalog {
return &magicCatalog{
func NewMagicCatalog(kubeClient k8scontrollerclient.Client, namespace string, catalogName string, provider FileBasedCatalogProvider) *MagicCatalog {
return &MagicCatalog{
fileBasedCatalog: provider,
kubeClient: kubeClient,
namespace: namespace,
Expand All @@ -51,53 +45,41 @@ func NewMagicCatalog(kubeClient k8scontrollerclient.Client, namespace string, ca
}
}

func (c *magicCatalog) DeployCatalog(ctx context.Context) error {
catalogSource := c.makeCatalogSource()
func NewMagicCatalogFromFile(kubeClient k8scontrollerclient.Client, namespace string, catalogName string, fbcFilePath string) (*MagicCatalog, error) {
provider, err := NewFileBasedFiledBasedCatalogProvider(fbcFilePath)
if err != nil {
return nil, err
}
catalog := NewMagicCatalog(kubeClient, namespace, catalogName, provider)
return catalog, nil
}

func (c *MagicCatalog) GetName() string {
return c.name
}

func (c *MagicCatalog) GetNamespace() string {
return c.namespace
}

func (c *MagicCatalog) DeployCatalog(ctx context.Context) error {
resourcesInOrderOfDeployment := []k8scontrollerclient.Object{
c.makeConfigMap(),
c.makeCatalogSourcePod(),
c.makeCatalogService(),
catalogSource,
c.makeCatalogSource(),
}
if err := c.deployCatalog(ctx, resourcesInOrderOfDeployment); err != nil {
return err
}
if err := catalogSourceIsReady(ctx, c.kubeClient, catalogSource); err != nil {
return c.cleanUpAfter(ctx, err)
if err := c.catalogSourceIsReady(ctx); err != nil {
return c.cleanUpAfterError(ctx, err)
}

return nil
}

func catalogSourceIsReady(ctx context.Context, c k8scontrollerclient.Client, cs *operatorsv1alpha1.CatalogSource) error {
// wait for catalog source to become ready
return waitFor(func() (bool, error) {
err := c.Get(ctx, k8scontrollerclient.ObjectKey{
Name: cs.GetName(),
Namespace: cs.GetNamespace(),
}, cs)
if err != nil || cs.Status.GRPCConnectionState == nil {
return false, err
}
state := cs.Status.GRPCConnectionState.LastObservedState
if state != catalogReadyState {
return false, nil
}
return true, nil
})
}

func (c *magicCatalog) deployCatalog(ctx context.Context, resources []k8scontrollerclient.Object) error {
for _, res := range resources {
err := c.kubeClient.Create(ctx, res)
if err != nil {
return c.cleanUpAfter(ctx, err)
}
}
return nil
}

func (c *magicCatalog) UpdateCatalog(ctx context.Context, provider FileBasedCatalogProvider) error {
func (c *MagicCatalog) UpdateCatalog(ctx context.Context, provider FileBasedCatalogProvider) error {
resourcesInOrderOfDeletion := []k8scontrollerclient.Object{
c.makeCatalogSourcePod(),
c.makeConfigMap(),
Expand Down Expand Up @@ -132,14 +114,14 @@ func (c *magicCatalog) UpdateCatalog(ctx context.Context, provider FileBasedCata
if err := c.deployCatalog(ctx, resourcesInOrderOfCreation); err != nil {
return err
}
if err := catalogSourceIsReady(ctx, c.kubeClient, c.makeCatalogSource()); err != nil {
return c.cleanUpAfter(ctx, err)
if err := c.catalogSourceIsReady(ctx); err != nil {
return c.cleanUpAfterError(ctx, err)
}

return nil
}

func (c *magicCatalog) UndeployCatalog(ctx context.Context) []error {
func (c *MagicCatalog) UndeployCatalog(ctx context.Context) []error {
resourcesInOrderOfDeletion := []k8scontrollerclient.Object{
c.makeCatalogSource(),
c.makeCatalogService(),
Expand All @@ -149,7 +131,38 @@ func (c *magicCatalog) UndeployCatalog(ctx context.Context) []error {
return c.undeployCatalog(ctx, resourcesInOrderOfDeletion)
}

func (c *magicCatalog) undeployCatalog(ctx context.Context, resources []k8scontrollerclient.Object) []error {
func (c *MagicCatalog) catalogSourceIsReady(ctx context.Context) error {
// wait for catalog source to become ready
key := k8scontrollerclient.ObjectKey{
Name: c.name,
Namespace: c.namespace,
}

return waitFor(func() (bool, error) {
catalogSource := &operatorsv1alpha1.CatalogSource{}
err := c.kubeClient.Get(ctx, key, catalogSource)
if err != nil || catalogSource.Status.GRPCConnectionState == nil {
return false, err
}
state := catalogSource.Status.GRPCConnectionState.LastObservedState
if state != catalogReadyState {
return false, nil
}
return true, nil
})
}

func (c *MagicCatalog) deployCatalog(ctx context.Context, resources []k8scontrollerclient.Object) error {
for _, res := range resources {
err := c.kubeClient.Create(ctx, res)
if err != nil {
return c.cleanUpAfterError(ctx, err)
}
}
return nil
}

func (c *MagicCatalog) undeployCatalog(ctx context.Context, resources []k8scontrollerclient.Object) []error {
var errors []error
// try to delete all resourcesInOrderOfDeletion even if errors are
// encountered through deletion.
Expand All @@ -167,15 +180,15 @@ func (c *magicCatalog) undeployCatalog(ctx context.Context, resources []k8scontr
return errors
}

func (c *magicCatalog) cleanUpAfter(ctx context.Context, err error) error {
func (c *MagicCatalog) cleanUpAfterError(ctx context.Context, err error) error {
cleanupErr := c.UndeployCatalog(ctx)
if cleanupErr != nil {
return fmt.Errorf("the following cleanup errors occurred: '%s' after an error deploying the configmap: '%s' ", cleanupErr, err)
}
return err
}

func (c *magicCatalog) makeCatalogService() *corev1.Service {
func (c *MagicCatalog) makeCatalogService() *corev1.Service {
return &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: c.serviceName,
Expand All @@ -195,7 +208,7 @@ func (c *magicCatalog) makeCatalogService() *corev1.Service {
}
}

func (c *magicCatalog) makeConfigMap() *corev1.ConfigMap {
func (c *MagicCatalog) makeConfigMap() *corev1.ConfigMap {
isImmutable := true
return &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Expand Down Expand Up @@ -224,7 +237,7 @@ func (c *magicCatalog) makeConfigMap() *corev1.ConfigMap {
}
}

func (c *magicCatalog) makeCatalogSource() *operatorsv1alpha1.CatalogSource {
func (c *MagicCatalog) makeCatalogSource() *operatorsv1alpha1.CatalogSource {
return &operatorsv1alpha1.CatalogSource{
ObjectMeta: metav1.ObjectMeta{
Name: c.name,
Expand All @@ -237,7 +250,7 @@ func (c *magicCatalog) makeCatalogSource() *operatorsv1alpha1.CatalogSource {
}
}

func (c *magicCatalog) makeCatalogSourcePod() *corev1.Pod {
func (c *MagicCatalog) makeCatalogSourcePod() *corev1.Pod {

const (
image = "quay.io/operator-framework/upstream-opm-builder"
Expand Down Expand Up @@ -320,7 +333,7 @@ func (c *magicCatalog) makeCatalogSourcePod() *corev1.Pod {
}
}

func (c *magicCatalog) makeCatalogSourcePodLabels() map[string]string {
func (c *MagicCatalog) makeCatalogSourcePodLabels() map[string]string {
return map[string]string{
olmCatalogLabel: c.name,
}
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/magic_catalog_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ var _ = Describe("MagicCatalog", func() {

When("an existing magic catalog exists", func() {
var (
mc MagicCatalog
mc *MagicCatalog
catalogName string
)

Expand Down
6 changes: 3 additions & 3 deletions test/e2e/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -1010,11 +1010,11 @@ func SetupGeneratedTestNamespaceWithOperatorGroup(name string, og operatorsv1.Op
},
}
Eventually(func() error {
return ctx.Ctx().Client().Create(context.Background(), &ns)
return ctx.Ctx().E2EClient().Create(context.Background(), &ns)
}).Should(Succeed())

Eventually(func() error {
return ctx.Ctx().Client().Create(context.Background(), &og)
return ctx.Ctx().E2EClient().Create(context.Background(), &og)
}).Should(Succeed())

ctx.Ctx().Logf("created the %s testing namespace", ns.GetName())
Expand Down Expand Up @@ -1049,7 +1049,7 @@ func TeardownNamespace(ns string) {

log("tearing down the %s namespace", ns)
Eventually(func() error {
return ctx.Ctx().KubeClient().KubernetesInterface().CoreV1().Namespaces().Delete(context.Background(), ns, metav1.DeleteOptions{})
return ctx.Ctx().E2EClient().Reset()
}).Should(Succeed())
}

Expand Down
40 changes: 37 additions & 3 deletions test/e2e/util/e2e_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ package util

import (
"context"
"strings"

"github.com/onsi/ginkgo/v2"
k8serror "k8s.io/apimachinery/pkg/api/errors"
extensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
k8scontrollerclient "sigs.k8s.io/controller-runtime/pkg/client"
)

Expand Down Expand Up @@ -38,7 +39,6 @@ func (m *E2EKubeClient) Update(context context.Context, obj k8scontrollerclient.
if err := m.Client.Update(context, obj, options...); err != nil {
return err
}
m.createdResources.EnqueueIgnoreExisting(obj)
return nil
}

Expand All @@ -51,17 +51,51 @@ func (m *E2EKubeClient) Delete(context context.Context, obj k8scontrollerclient.
}

func (m *E2EKubeClient) Reset() error {
Logf("resetting e2e kube client")
for {
obj, ok := m.createdResources.DequeueTail()

if !ok {
break
}

if err := m.Delete(context.TODO(), obj); err != nil && !k8serror.IsNotFound(err) {
namespace := obj.GetNamespace()
if namespace == "" {
namespace = "<global>"
}

Logf("deleting %s/%s", namespace, obj.GetName())
if err := k8scontrollerclient.IgnoreNotFound(m.Delete(context.Background(), obj)); err != nil {
Logf("error deleting object %s/%s: %s", namespace, obj.GetName(), obj)
return err
}
}
return m.GarbageCollectCRDs()
}

// GarbageCollectCRDs deletes any CRD with a label like operatorframework.io/installed-alongside-*
// these are the result of operator installations by olm and tent to be left behind after an e2e test
func (m *E2EKubeClient) GarbageCollectCRDs() error {
Logf("garbage collecting CRDs")
const operatorFrameworkAnnotation = "operatorframework.io/installed-alongside-"

crds := &extensionsv1.CustomResourceDefinitionList{}
err := m.Client.List(context.Background(), crds)
if err != nil {
return err
}

for _, crd := range crds.Items {
for key, _ := range crd.Annotations {
if strings.HasPrefix(key, operatorFrameworkAnnotation) {
Logf("deleting crd %s", crd.GetName())
if err := m.Client.Delete(context.Background(), &crd); err != nil {
return err
}
break
}
}
}
return nil
}

Expand Down
Loading

0 comments on commit a538831

Please sign in to comment.