github.com/redhat-appstudio/e2e-tests@v0.0.0-20240520140907-9709f6f59323/pkg/clients/kubernetes/client.go (about) 1 package client 2 3 import ( 4 "context" 5 "crypto/tls" 6 "net" 7 "net/http" 8 "time" 9 10 toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1" 11 ecp "github.com/enterprise-contract/enterprise-contract-controller/api/v1alpha1" 12 imagecontroller "github.com/konflux-ci/image-controller/api/v1alpha1" 13 integrationservicev1beta1 "github.com/konflux-ci/integration-service/api/v1beta1" 14 pacv1alpha1 "github.com/openshift-pipelines/pipelines-as-code/pkg/apis/pipelinesascode/v1alpha1" 15 ocpOauth "github.com/openshift/api/config/v1" 16 routev1 "github.com/openshift/api/route/v1" 17 userv1 "github.com/openshift/api/user/v1" 18 routeclientset "github.com/openshift/client-go/route/clientset/versioned" 19 appstudioApi "github.com/redhat-appstudio/application-api/api/v1alpha1" 20 buildservice "github.com/redhat-appstudio/build-service/api/v1alpha1" 21 "github.com/redhat-appstudio/e2e-tests/pkg/sandbox" 22 "github.com/redhat-appstudio/e2e-tests/pkg/utils" 23 jvmbuildservice "github.com/redhat-appstudio/jvm-build-service/pkg/apis/jvmbuildservice/v1alpha1" 24 jvmbuildserviceclientset "github.com/redhat-appstudio/jvm-build-service/pkg/client/clientset/versioned" 25 26 release "github.com/redhat-appstudio/release-service/api/v1alpha1" 27 rs "github.com/redhat-appstudio/remote-secret/api/v1beta1" 28 spi "github.com/redhat-appstudio/service-provider-integration-operator/api/v1beta1" 29 tekton "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" 30 pipelineclientset "github.com/tektoncd/pipeline/pkg/client/clientset/versioned" 31 "k8s.io/apimachinery/pkg/runtime" 32 utilruntime "k8s.io/apimachinery/pkg/util/runtime" 33 "k8s.io/apimachinery/pkg/util/wait" 34 "k8s.io/client-go/dynamic" 35 "k8s.io/client-go/kubernetes" 36 clientgoscheme "k8s.io/client-go/kubernetes/scheme" 37 "k8s.io/client-go/rest" 38 crclient "sigs.k8s.io/controller-runtime/pkg/client" 39 "sigs.k8s.io/controller-runtime/pkg/client/config" 40 ) 41 42 const ( 43 DefaultRetryInterval = time.Millisecond * 100 // make it short because a "retry interval" is waited before the first test 44 DefaultTimeout = time.Second * 240 45 ) 46 47 type CustomClient struct { 48 kubeClient *kubernetes.Clientset 49 crClient crclient.Client 50 pipelineClient pipelineclientset.Interface 51 dynamicClient dynamic.Interface 52 jvmbuildserviceClient jvmbuildserviceclientset.Interface 53 routeClient routeclientset.Interface 54 } 55 56 type K8SClient struct { 57 AsKubeAdmin *CustomClient 58 AsKubeDeveloper *CustomClient 59 ProxyUrl string 60 SandboxController *sandbox.SandboxController 61 UserName string 62 UserNamespace string 63 UserToken string 64 } 65 66 var ( 67 scheme = runtime.NewScheme() 68 ) 69 70 func init() { 71 utilruntime.Must(clientgoscheme.AddToScheme(scheme)) 72 utilruntime.Must(appstudioApi.AddToScheme(scheme)) 73 utilruntime.Must(ocpOauth.AddToScheme(scheme)) 74 utilruntime.Must(tekton.AddToScheme(scheme)) 75 utilruntime.Must(routev1.AddToScheme(scheme)) 76 utilruntime.Must(spi.AddToScheme(scheme)) 77 utilruntime.Must(toolchainv1alpha1.AddToScheme(scheme)) 78 utilruntime.Must(release.AddToScheme(scheme)) 79 utilruntime.Must(integrationservicev1beta1.AddToScheme(scheme)) 80 utilruntime.Must(jvmbuildservice.AddToScheme(scheme)) 81 utilruntime.Must(ecp.AddToScheme(scheme)) 82 utilruntime.Must(buildservice.AddToScheme(scheme)) 83 utilruntime.Must(userv1.AddToScheme(scheme)) 84 utilruntime.Must(rs.AddToScheme(scheme)) 85 utilruntime.Must(imagecontroller.AddToScheme(scheme)) 86 utilruntime.Must(pacv1alpha1.AddToScheme(scheme)) 87 } 88 89 // Kube returns the clientset for Kubernetes upstream. 90 func (c *CustomClient) KubeInterface() kubernetes.Interface { 91 return c.kubeClient 92 } 93 94 // Return a rest client to perform CRUD operations on Kubernetes objects 95 func (c *CustomClient) KubeRest() crclient.Client { 96 return c.crClient 97 } 98 99 func (c *CustomClient) PipelineClient() pipelineclientset.Interface { 100 return c.pipelineClient 101 } 102 103 func (c *CustomClient) JvmbuildserviceClient() jvmbuildserviceclientset.Interface { 104 return c.jvmbuildserviceClient 105 } 106 107 func (c *CustomClient) RouteClient() routeclientset.Interface { 108 return c.routeClient 109 } 110 111 // Returns a DynamicClient interface. 112 // Note: other client interfaces are likely preferred, except in rare cases. 113 func (c *CustomClient) DynamicClient() dynamic.Interface { 114 return c.dynamicClient 115 } 116 117 // Creates Kubernetes clients: 118 // 1. Will create a kubernetes client from default kubeconfig as kubeadmin 119 // 2. Will create a sandbox user and will generate a client using user token a new client to create resources in RHTAP like a normal user 120 func NewDevSandboxProxyClient(userName string, isStage bool, options utils.Options) (*K8SClient, error) { 121 var err error 122 var asAdminClient *CustomClient = nil 123 var sandboxController *sandbox.SandboxController 124 var proxyAuthInfo *sandbox.SandboxUserAuthInfo 125 var sandboxProxyClient *CustomClient 126 127 if isStage { 128 sandboxController, err := sandbox.NewDevSandboxStageController() 129 if err != nil { 130 return nil, err 131 } 132 proxyAuthInfo, err = sandboxController.ReconcileUserCreationStage(userName, options.ToolchainApiUrl, options.KeycloakUrl, options.OfflineToken) 133 if err != nil { 134 return nil, err 135 } 136 137 } else { 138 asAdminClient, err = NewAdminKubernetesClient() 139 if err != nil { 140 return nil, err 141 } 142 143 sandboxController, err = sandbox.NewDevSandboxController(asAdminClient.KubeInterface(), asAdminClient.KubeRest()) 144 if err != nil { 145 return nil, err 146 } 147 148 proxyAuthInfo, err = sandboxController.ReconcileUserCreation(userName) 149 if err != nil { 150 return nil, err 151 } 152 } 153 154 sandboxProxyClient, err = CreateAPIProxyClient(proxyAuthInfo.UserToken, proxyAuthInfo.ProxyUrl) 155 if err != nil { 156 return nil, err 157 } 158 159 return &K8SClient{ 160 AsKubeAdmin: asAdminClient, 161 AsKubeDeveloper: sandboxProxyClient, 162 ProxyUrl: proxyAuthInfo.ProxyUrl, 163 SandboxController: sandboxController, 164 UserName: proxyAuthInfo.UserName, 165 UserNamespace: proxyAuthInfo.UserNamespace, 166 UserToken: proxyAuthInfo.UserToken, 167 }, nil 168 } 169 170 // Creates a kubernetes client from default kubeconfig. Will take it from KUBECONFIG env if it is defined and if in case is not defined 171 // will create the client from $HOME/.kube/config 172 func NewAdminKubernetesClient() (*CustomClient, error) { 173 adminKubeconfig, err := config.GetConfig() 174 if err != nil { 175 return nil, err 176 } 177 clientSets, err := createClientSetsFromConfig(adminKubeconfig) 178 if err != nil { 179 return nil, err 180 } 181 182 crClient, err := crclient.New(adminKubeconfig, crclient.Options{ 183 Scheme: scheme, 184 }) 185 186 if err != nil { 187 return nil, err 188 } 189 190 return &CustomClient{ 191 kubeClient: clientSets.kubeClient, 192 pipelineClient: clientSets.pipelineClient, 193 dynamicClient: clientSets.dynamicClient, 194 jvmbuildserviceClient: clientSets.jvmbuildserviceClient, 195 routeClient: clientSets.routeClient, 196 crClient: crClient, 197 }, nil 198 } 199 200 // CreateAPIProxyClient creates a client to the RHTAP api proxy using the given user token 201 func CreateAPIProxyClient(usertoken, proxyURL string) (*CustomClient, error) { 202 var proxyCl crclient.Client 203 var initProxyClError error 204 205 proxyKubeConfig := &rest.Config{ 206 Host: proxyURL, 207 BearerToken: usertoken, 208 Transport: noTimeoutDefaultTransport(), 209 } 210 211 // Getting the proxy client can fail from time to time if the proxy's informer cache has not been 212 // updated yet and we try to create the client to quickly so retry to reduce flakiness. 213 waitErr := wait.PollUntilContextTimeout(context.Background(), DefaultRetryInterval, DefaultTimeout, false, func(ctx context.Context) (done bool, err error) { 214 proxyCl, initProxyClError = crclient.New(proxyKubeConfig, crclient.Options{Scheme: scheme}) 215 return initProxyClError == nil, nil 216 }) 217 if waitErr != nil { 218 return nil, initProxyClError 219 } 220 221 clientSets, err := createClientSetsFromConfig(proxyKubeConfig) 222 if err != nil { 223 return nil, err 224 } 225 226 return &CustomClient{ 227 kubeClient: clientSets.kubeClient, 228 pipelineClient: clientSets.pipelineClient, 229 dynamicClient: clientSets.dynamicClient, 230 jvmbuildserviceClient: clientSets.jvmbuildserviceClient, 231 routeClient: clientSets.routeClient, 232 crClient: proxyCl, 233 }, nil 234 } 235 236 func noTimeoutDefaultTransport() *http.Transport { 237 transport := http.DefaultTransport.(interface { 238 Clone() *http.Transport 239 }).Clone() 240 transport.DialContext = noTimeoutDialerProxy 241 transport.TLSClientConfig = &tls.Config{ 242 InsecureSkipVerify: true, // nolint:gosec 243 } 244 return transport 245 } 246 247 var noTimeoutDialerProxy = func(ctx context.Context, network, addr string) (net.Conn, error) { 248 dialer := &net.Dialer{ 249 Timeout: 0, 250 KeepAlive: 0, 251 } 252 return dialer.DialContext(ctx, network, addr) 253 } 254 255 func createClientSetsFromConfig(cfg *rest.Config) (*CustomClient, error) { 256 client, err := kubernetes.NewForConfig(cfg) 257 if err != nil { 258 return nil, err 259 } 260 261 dynamicClient, err := dynamic.NewForConfig(cfg) 262 if err != nil { 263 return nil, err 264 } 265 266 pipelineClient, err := pipelineclientset.NewForConfig(cfg) 267 if err != nil { 268 return nil, err 269 } 270 271 jvmbuildserviceClient, err := jvmbuildserviceclientset.NewForConfig(cfg) 272 if err != nil { 273 return nil, err 274 } 275 276 routeClient, err := routeclientset.NewForConfig(cfg) 277 if err != nil { 278 return nil, err 279 } 280 281 return &CustomClient{ 282 kubeClient: client, 283 pipelineClient: pipelineClient, 284 dynamicClient: dynamicClient, 285 jvmbuildserviceClient: jvmbuildserviceClient, 286 routeClient: routeClient, 287 }, nil 288 }