github.com/operator-framework/operator-lifecycle-manager@v0.30.0/test/e2e/scoped_client_test.go (about)

     1  package e2e
     2  
     3  import (
     4  	"context"
     5  
     6  	. "github.com/onsi/ginkgo/v2"
     7  	. "github.com/onsi/gomega"
     8  	"github.com/sirupsen/logrus"
     9  	corev1 "k8s.io/api/core/v1"
    10  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    11  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    12  	"k8s.io/apimachinery/pkg/runtime/schema"
    13  	"k8s.io/client-go/rest"
    14  
    15  	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/clients"
    16  	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient"
    17  	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/scoped"
    18  	"github.com/operator-framework/operator-lifecycle-manager/test/e2e/ctx"
    19  )
    20  
    21  var _ = Describe("Scoped Client bound to a service account can be used to make API calls", func() {
    22  	// TestScopedClient ensures that we can create a scoped client bound to a
    23  	// service account and then we can use the scoped client to make API calls.
    24  	var (
    25  		config *rest.Config
    26  
    27  		kubeclient operatorclient.ClientInterface
    28  
    29  		logger *logrus.Logger
    30  	)
    31  
    32  	BeforeEach(func() {
    33  		config = ctx.Ctx().RESTConfig()
    34  
    35  		kubeclient = ctx.Ctx().KubeClient()
    36  
    37  		logger = logrus.New()
    38  		logger.SetOutput(GinkgoWriter)
    39  	})
    40  
    41  	type testParameter struct {
    42  		name       string
    43  		grant      func(namespace, name string) (cleanup cleanupFunc)
    44  		assertFunc func(errGot error)
    45  	}
    46  
    47  	tableEntries := []TableEntry{
    48  		// The parent test invokes 'Get' API on non existent objects. If the
    49  		// scoped client has enough permission, we expect a NotFound error code.
    50  		// Otherwise, we expect a 'Forbidden' error code due to lack of permission.
    51  
    52  		Entry("returns error on API calls as ServiceAccount does not have any permission", testParameter{
    53  			// The service account does not have any permission granted to it.
    54  			// We expect the get api call to return 'Forbidden' error due to
    55  			// lack of permission.
    56  			assertFunc: func(errGot error) {
    57  				Expect(apierrors.IsForbidden(errGot)).To(BeTrue())
    58  			},
    59  		}),
    60  		Entry("successfully allows API calls to be made when ServiceAccount has permission", testParameter{
    61  			// The service account does have permission granted to it.
    62  			// We expect the get api call to return 'NotFound' error.
    63  			grant: func(namespace, name string) (cleanup cleanupFunc) {
    64  				cleanup = grantPermission(GinkgoT(), kubeclient, namespace, name)
    65  				return
    66  			},
    67  			assertFunc: func(errGot error) {
    68  				Expect(apierrors.IsNotFound(errGot)).To(BeTrue())
    69  			},
    70  		}),
    71  	}
    72  
    73  	DescribeTable("API call using scoped client", func(tc testParameter) {
    74  		By(`Create a new namespace`)
    75  		namespace := genName("a")
    76  		_, cleanupNS := newNamespace(kubeclient, namespace)
    77  		defer cleanupNS()
    78  
    79  		By(`Create a service account.`)
    80  		saName := genName("user-defined-")
    81  		sa, cleanupSA := newServiceAccount(kubeclient, namespace, saName)
    82  		defer cleanupSA()
    83  		By(`Create token secret for the serviceaccount`)
    84  		secret, cleanupSE := newTokenSecret(kubeclient, namespace, saName)
    85  		defer cleanupSE()
    86  
    87  		By("Wait for token secret data to be available")
    88  		Eventually(func() (*corev1.Secret, error) {
    89  			se, err := kubeclient.KubernetesInterface().CoreV1().Secrets(secret.GetNamespace()).Get(context.TODO(), secret.GetName(), metav1.GetOptions{})
    90  			return se, err
    91  		}).ShouldNot(WithTransform(func(v *corev1.Secret) string {
    92  			return string(v.Data[corev1.ServiceAccountTokenKey])
    93  		}, BeEmpty()))
    94  
    95  		By(`Grant permission(s) to the service account if specified.`)
    96  		strategy := scoped.NewClientAttenuator(logger, config, kubeclient)
    97  		getter := func() (reference *corev1.ObjectReference, err error) {
    98  			reference = &corev1.ObjectReference{
    99  				Namespace: namespace,
   100  				Name:      saName,
   101  			}
   102  			return
   103  		}
   104  
   105  		if tc.grant != nil {
   106  			cleanupPerm := tc.grant(sa.GetNamespace(), sa.GetName())
   107  			defer cleanupPerm()
   108  		}
   109  
   110  		By("Get scoped client instance(s)")
   111  		attenuate, err := strategy.AttenuateToServiceAccount(getter)
   112  		Expect(err).ToNot(HaveOccurred())
   113  
   114  		factory := clients.NewFactory(config).WithConfigTransformer(attenuate)
   115  		kubeclientGot, err := factory.NewOperatorClient()
   116  		Expect(err).ToNot(HaveOccurred())
   117  		Expect(kubeclientGot).ToNot(BeNil())
   118  		crclientGot, err := factory.NewKubernetesClient()
   119  		Expect(err).ToNot(HaveOccurred())
   120  		Expect(crclientGot).ToNot(BeNil())
   121  		dynamicClientGot, err := factory.NewDynamicClient()
   122  		Expect(err).ToNot(HaveOccurred())
   123  		Expect(dynamicClientGot).ToNot(BeNil())
   124  
   125  		By(`Invoke Get API call on non existent object(s) to check if the call can be made successfully.`)
   126  		_, err = kubeclientGot.KubernetesInterface().CoreV1().ConfigMaps(namespace).Get(context.TODO(), genName("does-not-exist-"), metav1.GetOptions{})
   127  		Expect(err).To(HaveOccurred())
   128  		tc.assertFunc(err)
   129  
   130  		_, err = crclientGot.OperatorsV1alpha1().CatalogSources(namespace).Get(context.TODO(), genName("does-not-exist-"), metav1.GetOptions{})
   131  		Expect(err).To(HaveOccurred())
   132  		tc.assertFunc(err)
   133  
   134  		gvr := schema.GroupVersionResource{Group: "", Version: "v1", Resource: "ConfigMap"}
   135  		_, err = dynamicClientGot.Resource(gvr).Namespace(namespace).Get(context.TODO(), genName("does-not-exist-"), metav1.GetOptions{})
   136  		Expect(err).To(HaveOccurred())
   137  		tc.assertFunc(err)
   138  	}, tableEntries)
   139  })