@@ -18,17 +18,22 @@ package main
1818
1919import (
2020 "flag"
21+ "fmt"
2122 "log/slog"
2223 "os"
24+ "path/filepath"
25+ stdruntime "runtime"
2326 "strconv"
2427
28+ "github.com/go-logr/logr"
29+
2530 ctrl "sigs.k8s.io/controller-runtime"
26- metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
2731
2832 application "github.com/kubeflow/notebooks/workspaces/backend/api"
2933 "github.com/kubeflow/notebooks/workspaces/backend/internal/auth"
3034 "github.com/kubeflow/notebooks/workspaces/backend/internal/config"
3135 "github.com/kubeflow/notebooks/workspaces/backend/internal/helper"
36+ "github.com/kubeflow/notebooks/workspaces/backend/internal/k8sclientfactory"
3237 "github.com/kubeflow/notebooks/workspaces/backend/internal/server"
3338)
3439
@@ -47,7 +52,7 @@ import (
4752// @consumes application/json
4853// @produces application/json
4954
50- func main () {
55+ func run () error {
5156 // Define command line flags
5257 cfg := & config.EnvConfig {}
5358 flag .IntVar (& cfg .Port ,
@@ -93,44 +98,59 @@ func main() {
9398 "Key of request header containing user groups" ,
9499 )
95100
96- // Initialize the logger
97- logger := slog .New (slog .NewTextHandler (os .Stdout , nil ))
101+ var enableEnvTest bool
102+ flag .BoolVar (& enableEnvTest ,
103+ "enable-envtest" ,
104+ getEnvAsBool ("ENABLE_ENVTEST" , false ),
105+ "Enable envtest for local development without a real k8s cluster" ,
106+ )
107+ flag .Parse ()
98108
99- // Build the Kubernetes client configuration
100- kubeconfig , err := ctrl .GetConfig ()
101- if err != nil {
102- logger .Error ("failed to get Kubernetes config" , "error" , err )
103- os .Exit (1 )
104- }
105- kubeconfig .QPS = float32 (cfg .ClientQPS )
106- kubeconfig .Burst = cfg .ClientBurst
109+ // Initialize the logger
110+ slogTextHandler := slog .NewTextHandler (os .Stdout , nil )
111+ logger := slog .New (slogTextHandler )
107112
108113 // Build the Kubernetes scheme
109114 scheme , err := helper .BuildScheme ()
110115 if err != nil {
111116 logger .Error ("failed to build Kubernetes scheme" , "error" , err )
112- os .Exit (1 )
117+ return err
118+ }
119+
120+ // Defining CRD's path
121+ crdPath := os .Getenv ("CRD_PATH" )
122+ if crdPath == "" {
123+ _ , currentFile , _ , ok := stdruntime .Caller (0 )
124+ if ! ok {
125+ logger .Info ("Failed to get current file path using stdruntime.Caller" )
126+ }
127+ testFileDir := filepath .Dir (currentFile )
128+ crdPath = filepath .Join (testFileDir , ".." , ".." , "controller" , "config" , "crd" , "bases" )
129+ logger .Info ("CRD_PATH not set, using guessed default" , "path" , crdPath )
113130 }
114131
115- // Create the controller manager
116- mgr , err := ctrl .NewManager (kubeconfig , ctrl.Options {
117- Scheme : scheme ,
118- Metrics : metricsserver.Options {
119- BindAddress : "0" , // disable metrics serving
120- },
121- HealthProbeBindAddress : "0" , // disable health probe serving
122- LeaderElection : false ,
123- })
132+ // ctx creates a context that listens for OS signals (e.g., SIGINT, SIGTERM) for graceful shutdown.
133+ ctx := ctrl .SetupSignalHandler ()
134+
135+ logrlogger := logr .FromSlogHandler (slogTextHandler )
136+
137+ // factory creates a new Kubernetes client factory, configured for envtest if enabled.
138+ factory := k8sclientfactory .NewClientFactory (logrlogger , scheme , enableEnvTest , []string {crdPath }, cfg )
139+
140+ // Create the controller manager, build Kubernetes client configuration
141+ // envtestCleanupFunc is a function to clean envtest if it was created, otherwise it's an empty function.
142+ mgr , _ , envtestCleanupFunc , err := factory .GetManagerAndConfig (ctx )
143+ defer envtestCleanupFunc ()
124144 if err != nil {
125- logger .Error ("unable to create manager" , "error" , err )
126- os . Exit ( 1 )
145+ logger .Error ("Failed to get Kubernetes manager/config from factory " , "error" , err )
146+ return err
127147 }
128148
129149 // Create the request authenticator
130150 reqAuthN , err := auth .NewRequestAuthenticator (cfg .UserIdHeader , cfg .UserIdPrefix , cfg .GroupsHeader )
131151 if err != nil {
132152 logger .Error ("failed to create request authenticator" , "error" , err )
133- os . Exit ( 1 )
153+ return err
134154 }
135155
136156 // Create the request authorizer
@@ -143,22 +163,30 @@ func main() {
143163 app , err := application .NewApp (cfg , logger , mgr .GetClient (), mgr .GetScheme (), reqAuthN , reqAuthZ )
144164 if err != nil {
145165 logger .Error ("failed to create app" , "error" , err )
146- os . Exit ( 1 )
166+ return err
147167 }
148168 svr , err := server .NewServer (app , logger )
149169 if err != nil {
150170 logger .Error ("failed to create server" , "error" , err )
151- os . Exit ( 1 )
171+ return err
152172 }
153173 if err := svr .SetupWithManager (mgr ); err != nil {
154174 logger .Error ("failed to setup server with manager" , "error" , err )
155- os .Exit (1 )
175+ return err
176+ }
177+
178+ logger .Info ("Starting manager..." )
179+ if err := mgr .Start (ctx ); err != nil {
180+ logger .Error ("Problem running manager" , "error" , err )
181+ return err
156182 }
157183
158- // Start the controller manager
159- logger .Info ("starting manager" )
160- if err := mgr .Start (ctrl .SetupSignalHandler ()); err != nil {
161- logger .Error ("problem running manager" , "error" , err )
184+ return nil
185+ }
186+
187+ func main () {
188+ if err := run (); err != nil {
189+ fmt .Fprintf (os .Stderr , "Application run failed: %v\n " , err )
162190 os .Exit (1 )
163191 }
164192}
0 commit comments