github.com/redhat-appstudio/e2e-tests@v0.0.0-20240520140907-9709f6f59323/pkg/clients/spi/access_tokens.go (about)

     1  package spi
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"crypto/tls"
     7  	"fmt"
     8  	"net/http"
     9  	"time"
    10  
    11  	. "github.com/onsi/gomega"
    12  	"github.com/redhat-appstudio/e2e-tests/pkg/utils"
    13  	spi "github.com/redhat-appstudio/service-provider-integration-operator/api/v1beta1"
    14  	v1 "k8s.io/api/core/v1"
    15  	k8sErrors "k8s.io/apimachinery/pkg/api/errors"
    16  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    17  	"k8s.io/apimachinery/pkg/types"
    18  	"k8s.io/klog"
    19  	"sigs.k8s.io/controller-runtime/pkg/client"
    20  )
    21  
    22  const (
    23  	SPIAccessTokenBindingPrefixName = "e2e-access-token-binding"
    24  )
    25  
    26  // GetSPIAccessTokenBinding returns the requested SPIAccessTokenBinding object
    27  func (s *SPIController) GetSPIAccessToken(name, namespace string) (*spi.SPIAccessToken, error) {
    28  	namespacedName := types.NamespacedName{
    29  		Name:      name,
    30  		Namespace: namespace,
    31  	}
    32  
    33  	spiAccessToken := spi.SPIAccessToken{
    34  		Spec: spi.SPIAccessTokenSpec{},
    35  	}
    36  	err := s.KubeRest().Get(context.Background(), namespacedName, &spiAccessToken)
    37  	if err != nil {
    38  		return nil, err
    39  	}
    40  	return &spiAccessToken, nil
    41  }
    42  
    43  // Inject manually access tokens using spi API
    44  func (s *SPIController) InjectManualSPIToken(namespace string, repoUrl string, oauthCredentials string, secretType v1.SecretType, secretName string) string {
    45  	var spiAccessTokenBinding *spi.SPIAccessTokenBinding
    46  
    47  	// Get the token for the current openshift user
    48  	bearerToken, err := utils.GetOpenshiftToken()
    49  	Expect(err).NotTo(HaveOccurred())
    50  
    51  	// https://issues.redhat.com/browse/STONE-444. Is not possible to create more than 1 secret per user namespace
    52  	secret, err := s.KubeInterface().CoreV1().Secrets(namespace).Get(context.Background(), secretName, metav1.GetOptions{})
    53  	if k8sErrors.IsAlreadyExists(err) {
    54  		klog.Infof("secret %s already exists", secret.Name)
    55  
    56  		return secret.Name
    57  	}
    58  
    59  	spiAccessTokenBinding, err = s.CreateSPIAccessTokenBinding(SPIAccessTokenBindingPrefixName, namespace, repoUrl, secretName, secretType)
    60  	Expect(err).NotTo(HaveOccurred())
    61  	spiAccessTokenBindingName := spiAccessTokenBinding.Name
    62  
    63  	Eventually(func() spi.SPIAccessTokenBindingPhase {
    64  		// application info should be stored even after deleting the application in application variable
    65  		spiAccessTokenBinding, err = s.GetSPIAccessTokenBinding(spiAccessTokenBindingName, namespace)
    66  		Expect(err).NotTo(HaveOccurred())
    67  
    68  		return spiAccessTokenBinding.Status.Phase
    69  	}, 2*time.Minute, 5*time.Second).Should(Or(Equal(spi.SPIAccessTokenBindingPhaseInjected), Equal(spi.SPIAccessTokenBindingPhaseAwaitingTokenData)), fmt.Sprintf("SPIAccessTokenBinding %s/%s is not in %s or %s phase", spiAccessTokenBinding.GetNamespace(), spiAccessTokenBinding.GetName(), spi.SPIAccessTokenBindingPhaseInjected, spi.SPIAccessTokenBindingPhaseAwaitingTokenData))
    70  
    71  	Eventually(func() string {
    72  		// application info should be stored even after deleting the application in application variable
    73  		spiAccessTokenBinding, err = s.GetSPIAccessTokenBinding(spiAccessTokenBindingName, namespace)
    74  		Expect(err).NotTo(HaveOccurred())
    75  
    76  		return spiAccessTokenBinding.Status.UploadUrl
    77  	}, 5*time.Minute, 100*time.Millisecond).ShouldNot(BeEmpty(), fmt.Sprintf(".Status.UploadUrl for SPIAccessTokenBinding %s/%s is not set. Please check if spi oauth-config configmap contain all necessary providers for tests.", spiAccessTokenBinding.GetNamespace(), spiAccessTokenBinding.GetName()))
    78  
    79  	if spiAccessTokenBinding.Status.Phase == spi.SPIAccessTokenBindingPhaseAwaitingTokenData {
    80  		// If the phase is AwaitingTokenData then manually inject the git token
    81  		// Get the oauth url and linkedAccessTokenName from the spiaccesstokenbinding resource
    82  		Expect(err).NotTo(HaveOccurred())
    83  		linkedAccessTokenName := spiAccessTokenBinding.Status.LinkedAccessTokenName
    84  
    85  		// Before injecting the token, validate that the linkedaccesstoken resource exists, otherwise injecting will return a 404 error code
    86  		Eventually(func() bool {
    87  			// application info should be stored even after deleting the application in application variable
    88  			_, err := s.GetSPIAccessToken(linkedAccessTokenName, namespace)
    89  			return err == nil
    90  		}, 1*time.Minute, 100*time.Millisecond).Should(BeTrue(), "SPI controller didn't create the SPIAccessToken")
    91  
    92  		// Format for quay.io token injection: `{"access_token":"tokenToInject","username":"redhat-appstudio-qe+redhat_appstudio_qe_bot"}`
    93  		// Now that the spiaccesstokenbinding is in the AwaitingTokenData phase, inject the GitHub token
    94  		http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
    95  		req, err := http.NewRequest("POST", spiAccessTokenBinding.Status.UploadUrl, bytes.NewBuffer([]byte(oauthCredentials)))
    96  		Expect(err).NotTo(HaveOccurred())
    97  		req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", string(bearerToken)))
    98  		req.Header.Set("Content-Type", "application/json")
    99  
   100  		client := &http.Client{}
   101  		resp, err := client.Do(req)
   102  		Expect(err).NotTo(HaveOccurred())
   103  		Expect(resp.StatusCode).Should(Equal(204))
   104  		defer resp.Body.Close()
   105  
   106  		// Check to see if the token was successfully injected
   107  		Eventually(func() spi.SPIAccessTokenBindingPhase {
   108  			// application info should be stored even after deleting the application in application variable
   109  			spiAccessTokenBinding, err = s.GetSPIAccessTokenBinding(spiAccessTokenBindingName, namespace)
   110  			Expect(err).NotTo(HaveOccurred())
   111  
   112  			return spiAccessTokenBinding.Status.Phase
   113  		}, 1*time.Minute, 100*time.Millisecond).Should(Equal(spi.SPIAccessTokenBindingPhaseInjected), fmt.Sprintf("SPIAccessTokenBinding %s/%s is not in %s phase", spiAccessTokenBinding.GetNamespace(), spiAccessTokenBinding.GetName(), spi.SPIAccessTokenBindingPhaseInjected))
   114  	}
   115  	return secretName
   116  }
   117  
   118  // Remove all SPIAccessToken from a given namespace. Useful when creating a lot of resources and wanting to remove all of them
   119  func (s *SPIController) DeleteAllAccessTokensInASpecificNamespace(namespace string) error {
   120  	return s.KubeRest().DeleteAllOf(context.Background(), &spi.SPIAccessToken{}, client.InNamespace(namespace))
   121  }
   122  
   123  // Remove all SPIAccessTokenDataUpdate from a given namespace. Useful when creating a lot of resources and wanting to remove all of them
   124  func (s *SPIController) DeleteAllAccessTokenDataInASpecificNamespace(namespace string) error {
   125  	return s.KubeRest().DeleteAllOf(context.Background(), &spi.SPIAccessTokenDataUpdate{}, client.InNamespace(namespace))
   126  }