sigs.k8s.io/kueue@v0.6.2/test/integration/framework/framework.go (about)

     1  /*
     2  Copyright 2022 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package framework
    18  
    19  import (
    20  	"context"
    21  	"crypto/tls"
    22  	"fmt"
    23  	"net"
    24  	"time"
    25  
    26  	kubeflow "github.com/kubeflow/mpi-operator/pkg/apis/kubeflow/v2beta1"
    27  	kftraining "github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1"
    28  	"github.com/onsi/ginkgo/v2"
    29  	"github.com/onsi/gomega"
    30  	rayv1 "github.com/ray-project/kuberay/ray-operator/apis/ray/v1"
    31  	rayjobapi "github.com/ray-project/kuberay/ray-operator/apis/ray/v1alpha1"
    32  	zaplog "go.uber.org/zap"
    33  	"go.uber.org/zap/zapcore"
    34  	"k8s.io/client-go/kubernetes/scheme"
    35  	"k8s.io/client-go/rest"
    36  	ctrl "sigs.k8s.io/controller-runtime"
    37  	"sigs.k8s.io/controller-runtime/pkg/client"
    38  	"sigs.k8s.io/controller-runtime/pkg/envtest"
    39  	"sigs.k8s.io/controller-runtime/pkg/log/zap"
    40  	"sigs.k8s.io/controller-runtime/pkg/manager"
    41  	metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
    42  	"sigs.k8s.io/controller-runtime/pkg/webhook"
    43  	jobsetapi "sigs.k8s.io/jobset/api/jobset/v1alpha2"
    44  
    45  	config "sigs.k8s.io/kueue/apis/config/v1beta1"
    46  	kueuealpha "sigs.k8s.io/kueue/apis/kueue/v1alpha1"
    47  	kueue "sigs.k8s.io/kueue/apis/kueue/v1beta1"
    48  )
    49  
    50  type ManagerSetup func(manager.Manager, context.Context)
    51  
    52  type Framework struct {
    53  	CRDPath     string
    54  	DepCRDPaths []string
    55  	WebhookPath string
    56  	testEnv     *envtest.Environment
    57  	cancel      context.CancelFunc
    58  }
    59  
    60  func (f *Framework) Init() *rest.Config {
    61  	opts := func(o *zap.Options) {
    62  		o.TimeEncoder = zapcore.RFC3339NanoTimeEncoder
    63  		o.ZapOpts = []zaplog.Option{zaplog.AddCaller()}
    64  	}
    65  	ctrl.SetLogger(zap.New(
    66  		zap.WriteTo(ginkgo.GinkgoWriter),
    67  		zap.UseDevMode(true),
    68  		zap.Level(zapcore.Level(-3)),
    69  		opts),
    70  	)
    71  
    72  	ginkgo.By("bootstrapping test environment")
    73  	f.testEnv = &envtest.Environment{
    74  		CRDDirectoryPaths:     append(f.DepCRDPaths, f.CRDPath),
    75  		ErrorIfCRDPathMissing: true,
    76  	}
    77  	if len(f.WebhookPath) > 0 {
    78  		f.testEnv.WebhookInstallOptions.Paths = []string{f.WebhookPath}
    79  	}
    80  
    81  	cfg, err := f.testEnv.Start()
    82  	gomega.ExpectWithOffset(1, err).NotTo(gomega.HaveOccurred())
    83  	gomega.ExpectWithOffset(1, cfg).NotTo(gomega.BeNil())
    84  
    85  	return cfg
    86  }
    87  
    88  func (f *Framework) RunManager(cfg *rest.Config, managerSetup ManagerSetup) (context.Context, client.Client) {
    89  	err := config.AddToScheme(scheme.Scheme)
    90  	gomega.ExpectWithOffset(1, err).NotTo(gomega.HaveOccurred())
    91  
    92  	err = kueue.AddToScheme(scheme.Scheme)
    93  	gomega.ExpectWithOffset(1, err).NotTo(gomega.HaveOccurred())
    94  
    95  	err = kueuealpha.AddToScheme(scheme.Scheme)
    96  	gomega.ExpectWithOffset(1, err).NotTo(gomega.HaveOccurred())
    97  
    98  	err = kubeflow.AddToScheme(scheme.Scheme)
    99  	gomega.ExpectWithOffset(1, err).NotTo(gomega.HaveOccurred())
   100  
   101  	err = rayjobapi.AddToScheme(scheme.Scheme)
   102  	gomega.ExpectWithOffset(1, err).NotTo(gomega.HaveOccurred())
   103  
   104  	err = rayv1.AddToScheme(scheme.Scheme)
   105  	gomega.ExpectWithOffset(1, err).NotTo(gomega.HaveOccurred())
   106  
   107  	err = jobsetapi.AddToScheme(scheme.Scheme)
   108  	gomega.ExpectWithOffset(1, err).NotTo(gomega.HaveOccurred())
   109  
   110  	err = kftraining.AddToScheme(scheme.Scheme)
   111  	gomega.ExpectWithOffset(1, err).NotTo(gomega.HaveOccurred())
   112  
   113  	// +kubebuilder:scaffold:scheme
   114  
   115  	k8sClient, err := client.New(cfg, client.Options{Scheme: scheme.Scheme})
   116  	gomega.ExpectWithOffset(1, err).NotTo(gomega.HaveOccurred())
   117  	gomega.ExpectWithOffset(1, k8sClient).NotTo(gomega.BeNil())
   118  
   119  	webhookInstallOptions := &f.testEnv.WebhookInstallOptions
   120  	mgrOpts := manager.Options{
   121  		Scheme: scheme.Scheme,
   122  		Metrics: metricsserver.Options{
   123  			BindAddress: "0", // disable metrics to avoid conflicts between packages.
   124  		},
   125  		WebhookServer: webhook.NewServer(
   126  			webhook.Options{
   127  				Host:    webhookInstallOptions.LocalServingHost,
   128  				Port:    webhookInstallOptions.LocalServingPort,
   129  				CertDir: webhookInstallOptions.LocalServingCertDir,
   130  			}),
   131  	}
   132  	mgr, err := ctrl.NewManager(cfg, mgrOpts)
   133  	gomega.ExpectWithOffset(1, err).NotTo(gomega.HaveOccurred(), "failed to create manager")
   134  
   135  	ctx, cancel := context.WithCancel(context.Background())
   136  	f.cancel = cancel
   137  	managerSetup(mgr, ctx)
   138  
   139  	go func() {
   140  		defer ginkgo.GinkgoRecover()
   141  		err := mgr.Start(ctx)
   142  		gomega.ExpectWithOffset(1, err).NotTo(gomega.HaveOccurred(), "failed to run manager")
   143  	}()
   144  
   145  	if len(f.WebhookPath) > 0 {
   146  		// wait for the webhook server to get ready
   147  		dialer := &net.Dialer{Timeout: time.Second}
   148  		addrPort := fmt.Sprintf("%s:%d", webhookInstallOptions.LocalServingHost, webhookInstallOptions.LocalServingPort)
   149  		gomega.Eventually(func() error {
   150  			conn, err := tls.DialWithDialer(dialer, "tcp", addrPort, &tls.Config{InsecureSkipVerify: true})
   151  			if err != nil {
   152  				return err
   153  			}
   154  			conn.Close()
   155  			return nil
   156  		}).Should(gomega.Succeed())
   157  	}
   158  
   159  	return ctx, k8sClient
   160  }
   161  
   162  func (f *Framework) Teardown() {
   163  	ginkgo.By("tearing down the test environment")
   164  	f.cancel()
   165  	err := f.testEnv.Stop()
   166  	gomega.ExpectWithOffset(1, err).NotTo(gomega.HaveOccurred())
   167  }