1
1
package api
2
2
3
3
import (
4
- "encoding/json"
5
- "errors"
6
4
"fmt"
7
- "net/http"
8
- "strings"
9
5
10
- "github.com/gorilla/mux"
11
6
"github.com/replicatedhq/embedded-cluster/api/controllers/auth"
12
7
"github.com/replicatedhq/embedded-cluster/api/controllers/console"
13
- "github.com/replicatedhq/embedded-cluster/api/controllers/install"
14
- "github.com/replicatedhq/embedded-cluster/api/docs"
8
+ linuxinstall "github.com/replicatedhq/embedded-cluster/api/controllers/linux/install"
15
9
"github.com/replicatedhq/embedded-cluster/api/pkg/logger"
16
10
"github.com/replicatedhq/embedded-cluster/api/types"
17
- ecv1beta1 "github.com/replicatedhq/embedded-cluster/kinds/apis/v1beta1"
18
- "github.com/replicatedhq/embedded-cluster/pkg-new/hostutils"
19
11
"github.com/replicatedhq/embedded-cluster/pkg/metrics"
20
- "github.com/replicatedhq/embedded-cluster/pkg/release"
21
12
"github.com/replicatedhq/embedded-cluster/pkg/runtimeconfig"
22
- kotsv1beta1 "github.com/replicatedhq/kotskinds/apis/kots/v1beta1"
23
13
"github.com/sirupsen/logrus"
24
- httpSwagger "github.com/swaggo/http-swagger/v2"
25
14
)
26
15
27
16
// @title Embedded Cluster API
@@ -42,125 +31,62 @@ import (
42
31
43
32
// @externalDocs.description OpenAPI
44
33
// @externalDocs.url https://swagger.io/resources/open-api/
45
- type API struct {
46
- authController auth.Controller
47
- consoleController console.Controller
48
- installController install.Controller
49
- rc runtimeconfig.RuntimeConfig
50
- releaseData * release.ReleaseData
51
- tlsConfig types.TLSConfig
52
- license []byte
53
- airgapBundle string
54
- airgapInfo * kotsv1beta1.Airgap
55
- configValues string
56
- endUserConfig * ecv1beta1.Config
57
- allowIgnoreHostPreflights bool
58
- logger logrus.FieldLogger
59
- hostUtils hostutils.HostUtilsInterface
60
- metricsReporter metrics.ReporterInterface
34
+ type api struct {
35
+ cfg types.APIConfig
36
+
37
+ logger logrus.FieldLogger
38
+ metricsReporter metrics.ReporterInterface
39
+
40
+ authController auth.Controller
41
+ consoleController console.Controller
42
+ linuxInstallController linuxinstall.Controller
43
+
44
+ handlers handlers
61
45
}
62
46
63
- type APIOption func (* API )
47
+ type apiOption func (* api )
64
48
65
- func WithAuthController (authController auth.Controller ) APIOption {
66
- return func (a * API ) {
49
+ func WithAuthController (authController auth.Controller ) apiOption {
50
+ return func (a * api ) {
67
51
a .authController = authController
68
52
}
69
53
}
70
54
71
- func WithConsoleController (consoleController console.Controller ) APIOption {
72
- return func (a * API ) {
55
+ func WithConsoleController (consoleController console.Controller ) apiOption {
56
+ return func (a * api ) {
73
57
a .consoleController = consoleController
74
58
}
75
59
}
76
60
77
- func WithInstallController (installController install.Controller ) APIOption {
78
- return func (a * API ) {
79
- a .installController = installController
80
- }
81
- }
82
-
83
- func WithRuntimeConfig (rc runtimeconfig.RuntimeConfig ) APIOption {
84
- return func (a * API ) {
85
- a .rc = rc
61
+ func WithLinuxInstallController (linuxInstallController linuxinstall.Controller ) apiOption {
62
+ return func (a * api ) {
63
+ a .linuxInstallController = linuxInstallController
86
64
}
87
65
}
88
66
89
- func WithLogger (logger logrus.FieldLogger ) APIOption {
90
- return func (a * API ) {
67
+ func WithLogger (logger logrus.FieldLogger ) apiOption {
68
+ return func (a * api ) {
91
69
a .logger = logger
92
70
}
93
71
}
94
72
95
- func WithHostUtils (hostUtils hostutils.HostUtilsInterface ) APIOption {
96
- return func (a * API ) {
97
- a .hostUtils = hostUtils
98
- }
99
- }
100
-
101
- func WithMetricsReporter (metricsReporter metrics.ReporterInterface ) APIOption {
102
- return func (a * API ) {
73
+ func WithMetricsReporter (metricsReporter metrics.ReporterInterface ) apiOption {
74
+ return func (a * api ) {
103
75
a .metricsReporter = metricsReporter
104
76
}
105
77
}
106
78
107
- func WithReleaseData ( releaseData * release. ReleaseData ) APIOption {
108
- return func ( a * API ) {
109
- a . releaseData = releaseData
79
+ func New ( cfg types. APIConfig , opts ... apiOption ) ( * api , error ) {
80
+ api := & api {
81
+ cfg : cfg ,
110
82
}
111
- }
112
-
113
- func WithTLSConfig (tlsConfig types.TLSConfig ) APIOption {
114
- return func (a * API ) {
115
- a .tlsConfig = tlsConfig
116
- }
117
- }
118
-
119
- func WithLicense (license []byte ) APIOption {
120
- return func (a * API ) {
121
- a .license = license
122
- }
123
- }
124
-
125
- func WithAirgapBundle (airgapBundle string ) APIOption {
126
- return func (a * API ) {
127
- a .airgapBundle = airgapBundle
128
- }
129
- }
130
-
131
- func WithAirgapInfo (airgapInfo * kotsv1beta1.Airgap ) APIOption {
132
- return func (a * API ) {
133
- a .airgapInfo = airgapInfo
134
- }
135
- }
136
-
137
- func WithConfigValues (configValues string ) APIOption {
138
- return func (a * API ) {
139
- a .configValues = configValues
140
- }
141
- }
142
-
143
- func WithEndUserConfig (endUserConfig * ecv1beta1.Config ) APIOption {
144
- return func (a * API ) {
145
- a .endUserConfig = endUserConfig
146
- }
147
- }
148
-
149
- func WithAllowIgnoreHostPreflights (allowIgnoreHostPreflights bool ) APIOption {
150
- return func (a * API ) {
151
- a .allowIgnoreHostPreflights = allowIgnoreHostPreflights
152
- }
153
- }
154
-
155
- func New (password string , opts ... APIOption ) (* API , error ) {
156
- api := & API {}
157
83
158
84
for _ , opt := range opts {
159
85
opt (api )
160
86
}
161
87
162
- if api .rc == nil {
163
- api .rc = runtimeconfig .New (nil )
88
+ if api .cfg . RuntimeConfig == nil {
89
+ api .cfg . RuntimeConfig = runtimeconfig .New (nil )
164
90
}
165
91
166
92
if api .logger == nil {
@@ -171,139 +97,9 @@ func New(password string, opts ...APIOption) (*API, error) {
171
97
api .logger = l
172
98
}
173
99
174
- if api .hostUtils == nil {
175
- api .hostUtils = hostutils .New (
176
- hostutils .WithLogger (api .logger ),
177
- )
178
- }
179
-
180
- if api .authController == nil {
181
- authController , err := auth .NewAuthController (password )
182
- if err != nil {
183
- return nil , fmt .Errorf ("new auth controller: %w" , err )
184
- }
185
- api .authController = authController
186
- }
187
-
188
- if api .consoleController == nil {
189
- consoleController , err := console .NewConsoleController ()
190
- if err != nil {
191
- return nil , fmt .Errorf ("new console controller: %w" , err )
192
- }
193
- api .consoleController = consoleController
194
- }
195
-
196
- // TODO (@team): discuss which of these should / should not be pointers
197
- if api .installController == nil {
198
- installController , err := install .NewInstallController (
199
- install .WithRuntimeConfig (api .rc ),
200
- install .WithLogger (api .logger ),
201
- install .WithHostUtils (api .hostUtils ),
202
- install .WithMetricsReporter (api .metricsReporter ),
203
- install .WithReleaseData (api .releaseData ),
204
- install .WithPassword (password ),
205
- install .WithTLSConfig (api .tlsConfig ),
206
- install .WithLicense (api .license ),
207
- install .WithAirgapBundle (api .airgapBundle ),
208
- install .WithAirgapInfo (api .airgapInfo ),
209
- install .WithConfigValues (api .configValues ),
210
- install .WithEndUserConfig (api .endUserConfig ),
211
- install .WithAllowIgnoreHostPreflights (api .allowIgnoreHostPreflights ),
212
- )
213
- if err != nil {
214
- return nil , fmt .Errorf ("new install controller: %w" , err )
215
- }
216
- api .installController = installController
100
+ if err := api .initHandlers (); err != nil {
101
+ return nil , fmt .Errorf ("init handlers: %w" , err )
217
102
}
218
103
219
104
return api , nil
220
105
}
221
-
222
- func (a * API ) RegisterRoutes (router * mux.Router ) {
223
- router .HandleFunc ("/health" , a .getHealth ).Methods ("GET" )
224
-
225
- // Hack to fix issue
226
- // https://github.com/swaggo/swag/issues/1588#issuecomment-2797801240
227
- router .HandleFunc ("/swagger/doc.json" , func (w http.ResponseWriter , _ * http.Request ) {
228
- w .Header ().Set ("Content-Type" , "application/json" )
229
- w .WriteHeader (200 )
230
- w .Write ([]byte (docs .SwaggerInfo .ReadDoc ()))
231
- }).Methods ("GET" )
232
- router .PathPrefix ("/swagger/" ).Handler (httpSwagger .WrapHandler )
233
-
234
- router .HandleFunc ("/auth/login" , a .postAuthLogin ).Methods ("POST" )
235
-
236
- authenticatedRouter := router .PathPrefix ("/" ).Subrouter ()
237
- authenticatedRouter .Use (a .authMiddleware )
238
-
239
- installRouter := authenticatedRouter .PathPrefix ("/install" ).Subrouter ()
240
- installRouter .HandleFunc ("/installation/config" , a .getInstallInstallationConfig ).Methods ("GET" )
241
- installRouter .HandleFunc ("/installation/configure" , a .postInstallConfigureInstallation ).Methods ("POST" )
242
- installRouter .HandleFunc ("/installation/status" , a .getInstallInstallationStatus ).Methods ("GET" )
243
-
244
- installRouter .HandleFunc ("/host-preflights/run" , a .postInstallRunHostPreflights ).Methods ("POST" )
245
- installRouter .HandleFunc ("/host-preflights/status" , a .getInstallHostPreflightsStatus ).Methods ("GET" )
246
-
247
- installRouter .HandleFunc ("/infra/setup" , a .postInstallSetupInfra ).Methods ("POST" )
248
- installRouter .HandleFunc ("/infra/status" , a .getInstallInfraStatus ).Methods ("GET" )
249
-
250
- // TODO (@salah): remove this once the cli isn't responsible for setting the install status
251
- // and the ui isn't polling for it to know if the entire install is complete
252
- installRouter .HandleFunc ("/status" , a .getInstallStatus ).Methods ("GET" )
253
- installRouter .HandleFunc ("/status" , a .setInstallStatus ).Methods ("POST" )
254
-
255
- consoleRouter := authenticatedRouter .PathPrefix ("/console" ).Subrouter ()
256
- consoleRouter .HandleFunc ("/available-network-interfaces" , a .getListAvailableNetworkInterfaces ).Methods ("GET" )
257
- }
258
-
259
- func (a * API ) bindJSON (w http.ResponseWriter , r * http.Request , v any ) error {
260
- if err := json .NewDecoder (r .Body ).Decode (v ); err != nil {
261
- a .logError (r , err , fmt .Sprintf ("failed to decode %s %s request" , strings .ToLower (r .Method ), r .URL .Path ))
262
- a .jsonError (w , r , types .NewBadRequestError (err ))
263
- return err
264
- }
265
-
266
- return nil
267
- }
268
-
269
- func (a * API ) json (w http.ResponseWriter , r * http.Request , code int , payload any ) {
270
- response , err := json .Marshal (payload )
271
- if err != nil {
272
- a .logError (r , err , "failed to encode response" )
273
- w .WriteHeader (http .StatusInternalServerError )
274
- return
275
- }
276
-
277
- w .Header ().Set ("Content-Type" , "application/json" )
278
- w .WriteHeader (code )
279
- _ , _ = w .Write (response )
280
- }
281
-
282
- func (a * API ) jsonError (w http.ResponseWriter , r * http.Request , err error ) {
283
- var apiErr * types.APIError
284
- if ! errors .As (err , & apiErr ) {
285
- apiErr = types .NewInternalServerError (err )
286
- }
287
-
288
- response , err := json .Marshal (apiErr )
289
- if err != nil {
290
- a .logError (r , err , "failed to encode response" )
291
- http .Error (w , err .Error (), http .StatusInternalServerError )
292
- return
293
- }
294
-
295
- w .Header ().Set ("Content-Type" , "application/json" )
296
- w .WriteHeader (apiErr .StatusCode )
297
- _ , _ = w .Write (response )
298
- }
299
-
300
- func (a * API ) logError (r * http.Request , err error , args ... any ) {
301
- a .logger .WithFields (logrusFieldsFromRequest (r )).WithError (err ).Error (args ... )
302
- }
303
-
304
- func logrusFieldsFromRequest (r * http.Request ) logrus.Fields {
305
- return logrus.Fields {
306
- "method" : r .Method ,
307
- "path" : r .URL .Path ,
308
- }
309
- }
0 commit comments