@@ -18,17 +18,22 @@ package main
18
18
19
19
import (
20
20
"flag"
21
+ "fmt"
21
22
"log/slog"
22
23
"os"
24
+ "path/filepath"
25
+ stdruntime "runtime"
23
26
"strconv"
24
27
28
+ "github.com/go-logr/logr"
29
+
25
30
ctrl "sigs.k8s.io/controller-runtime"
26
- metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
27
31
28
32
application "github.com/kubeflow/notebooks/workspaces/backend/api"
29
33
"github.com/kubeflow/notebooks/workspaces/backend/internal/auth"
30
34
"github.com/kubeflow/notebooks/workspaces/backend/internal/config"
31
35
"github.com/kubeflow/notebooks/workspaces/backend/internal/helper"
36
+ "github.com/kubeflow/notebooks/workspaces/backend/internal/k8sclientfactory"
32
37
"github.com/kubeflow/notebooks/workspaces/backend/internal/server"
33
38
)
34
39
@@ -47,7 +52,7 @@ import (
47
52
// @consumes application/json
48
53
// @produces application/json
49
54
50
- func main () {
55
+ func run () error {
51
56
// Define command line flags
52
57
cfg := & config.EnvConfig {}
53
58
flag .IntVar (& cfg .Port ,
@@ -93,44 +98,61 @@ func main() {
93
98
"Key of request header containing user groups" ,
94
99
)
95
100
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 ()
98
108
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 )
107
112
108
113
// Build the Kubernetes scheme
109
114
scheme , err := helper .BuildScheme ()
110
115
if err != nil {
111
116
logger .Error ("failed to build Kubernetes scheme" , "error" , err )
112
- os . Exit ( 1 )
117
+ return err
113
118
}
114
119
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
- })
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 )
130
+ }
131
+
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 , kubeconfig , envtestCleanupFunc , err := factory .GetManagerAndConfig (ctx )
143
+ defer envtestCleanupFunc ()
124
144
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
127
147
}
148
+ kubeconfig .QPS = float32 (cfg .ClientQPS )
149
+ kubeconfig .Burst = cfg .ClientBurst
128
150
129
151
// Create the request authenticator
130
152
reqAuthN , err := auth .NewRequestAuthenticator (cfg .UserIdHeader , cfg .UserIdPrefix , cfg .GroupsHeader )
131
153
if err != nil {
132
154
logger .Error ("failed to create request authenticator" , "error" , err )
133
- os . Exit ( 1 )
155
+ return err
134
156
}
135
157
136
158
// Create the request authorizer
@@ -143,22 +165,30 @@ func main() {
143
165
app , err := application .NewApp (cfg , logger , mgr .GetClient (), mgr .GetScheme (), reqAuthN , reqAuthZ )
144
166
if err != nil {
145
167
logger .Error ("failed to create app" , "error" , err )
146
- os . Exit ( 1 )
168
+ return err
147
169
}
148
170
svr , err := server .NewServer (app , logger )
149
171
if err != nil {
150
172
logger .Error ("failed to create server" , "error" , err )
151
- os . Exit ( 1 )
173
+ return err
152
174
}
153
175
if err := svr .SetupWithManager (mgr ); err != nil {
154
176
logger .Error ("failed to setup server with manager" , "error" , err )
155
- os .Exit (1 )
177
+ return err
178
+ }
179
+
180
+ logger .Info ("Starting manager..." )
181
+ if err := mgr .Start (ctx ); err != nil {
182
+ logger .Error ("Problem running manager" , "error" , err )
183
+ return err
156
184
}
157
185
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 )
186
+ return nil
187
+ }
188
+
189
+ func main () {
190
+ if err := run (); err != nil {
191
+ fmt .Fprintf (os .Stderr , "Application run failed: %v\n " , err )
162
192
os .Exit (1 )
163
193
}
164
194
}
0 commit comments