Skip to content

Commit 0678def

Browse files
authored
Install infra in the manager API / UI (#2292)
1 parent c96475d commit 0678def

File tree

97 files changed

+3552
-1389
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

97 files changed

+3552
-1389
lines changed

api/api.go

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/replicatedhq/embedded-cluster/api/docs"
1414
"github.com/replicatedhq/embedded-cluster/api/pkg/logger"
1515
"github.com/replicatedhq/embedded-cluster/api/types"
16+
ecv1beta1 "github.com/replicatedhq/embedded-cluster/kinds/apis/v1beta1"
1617
"github.com/replicatedhq/embedded-cluster/pkg-new/hostutils"
1718
"github.com/replicatedhq/embedded-cluster/pkg/metrics"
1819
"github.com/replicatedhq/embedded-cluster/pkg/release"
@@ -45,9 +46,11 @@ type API struct {
4546
installController install.Controller
4647
rc runtimeconfig.RuntimeConfig
4748
releaseData *release.ReleaseData
49+
tlsConfig types.TLSConfig
4850
licenseFile string
4951
airgapBundle string
50-
configChan chan<- *types.InstallationConfig
52+
configValues string
53+
endUserConfig *ecv1beta1.Config
5154
logger logrus.FieldLogger
5255
hostUtils hostutils.HostUtilsInterface
5356
metricsReporter metrics.ReporterInterface
@@ -103,9 +106,9 @@ func WithReleaseData(releaseData *release.ReleaseData) APIOption {
103106
}
104107
}
105108

106-
func WithConfigChan(configChan chan<- *types.InstallationConfig) APIOption {
109+
func WithTLSConfig(tlsConfig types.TLSConfig) APIOption {
107110
return func(a *API) {
108-
a.configChan = configChan
111+
a.tlsConfig = tlsConfig
109112
}
110113
}
111114

@@ -121,6 +124,18 @@ func WithAirgapBundle(airgapBundle string) APIOption {
121124
}
122125
}
123126

127+
func WithConfigValues(configValues string) APIOption {
128+
return func(a *API) {
129+
a.configValues = configValues
130+
}
131+
}
132+
133+
func WithEndUserConfig(endUserConfig *ecv1beta1.Config) APIOption {
134+
return func(a *API) {
135+
a.endUserConfig = endUserConfig
136+
}
137+
}
138+
124139
func New(password string, opts ...APIOption) (*API, error) {
125140
api := &API{}
126141

@@ -170,8 +185,12 @@ func New(password string, opts ...APIOption) (*API, error) {
170185
install.WithHostUtils(api.hostUtils),
171186
install.WithMetricsReporter(api.metricsReporter),
172187
install.WithReleaseData(api.releaseData),
188+
install.WithPassword(password),
189+
install.WithTLSConfig(api.tlsConfig),
173190
install.WithLicenseFile(api.licenseFile),
174191
install.WithAirgapBundle(api.airgapBundle),
192+
install.WithConfigValues(api.configValues),
193+
install.WithEndUserConfig(api.endUserConfig),
175194
)
176195
if err != nil {
177196
return nil, fmt.Errorf("new install controller: %w", err)
@@ -201,13 +220,14 @@ func (a *API) RegisterRoutes(router *mux.Router) {
201220

202221
installRouter := authenticatedRouter.PathPrefix("/install").Subrouter()
203222
installRouter.HandleFunc("/installation/config", a.getInstallInstallationConfig).Methods("GET")
204-
installRouter.HandleFunc("/installation/status", a.getInstallInstallationStatus).Methods("GET")
205223
installRouter.HandleFunc("/installation/configure", a.postInstallConfigureInstallation).Methods("POST")
224+
installRouter.HandleFunc("/installation/status", a.getInstallInstallationStatus).Methods("GET")
206225

207-
installRouter.HandleFunc("/host-preflights/status", a.getInstallHostPreflightsStatus).Methods("GET")
208226
installRouter.HandleFunc("/host-preflights/run", a.postInstallRunHostPreflights).Methods("POST")
227+
installRouter.HandleFunc("/host-preflights/status", a.getInstallHostPreflightsStatus).Methods("GET")
209228

210-
installRouter.HandleFunc("/node/setup", a.postInstallSetupNode).Methods("POST")
229+
installRouter.HandleFunc("/infra/setup", a.postInstallSetupInfra).Methods("POST")
230+
installRouter.HandleFunc("/infra/status", a.getInstallInfraStatus).Methods("GET")
211231

212232
// TODO (@salah): remove this once the cli isn't responsible for setting the install status
213233
// and the ui isn't polling for it to know if the entire install is complete

api/client/client.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ type Client interface {
1414
GetInstallationConfig() (*types.InstallationConfig, error)
1515
GetInstallationStatus() (*types.Status, error)
1616
ConfigureInstallation(config *types.InstallationConfig) (*types.Status, error)
17+
SetupInfra() (*types.Infra, error)
18+
GetInfraStatus() (*types.Infra, error)
1719
SetInstallStatus(status *types.Status) (*types.Status, error)
1820
}
1921

api/client/client_test.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,105 @@ func TestConfigureInstallation(t *testing.T) {
204204
assert.Equal(t, "Bad Request", apiErr.Message)
205205
}
206206

207+
func TestSetupInfra(t *testing.T) {
208+
// Create a test server
209+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
210+
assert.Equal(t, "POST", r.Method)
211+
assert.Equal(t, "/api/install/infra/setup", r.URL.Path)
212+
213+
assert.Equal(t, "application/json", r.Header.Get("Content-Type"))
214+
assert.Equal(t, "Bearer test-token", r.Header.Get("Authorization"))
215+
216+
// Return successful response
217+
w.WriteHeader(http.StatusOK)
218+
json.NewEncoder(w).Encode(types.Infra{
219+
Status: &types.Status{
220+
State: types.StateRunning,
221+
Description: "Installing infra",
222+
},
223+
})
224+
}))
225+
defer server.Close()
226+
227+
// Test successful setup
228+
c := New(server.URL, WithToken("test-token"))
229+
infra, err := c.SetupInfra()
230+
assert.NoError(t, err)
231+
assert.NotNil(t, infra)
232+
assert.NotNil(t, infra.Status)
233+
assert.Equal(t, types.StateRunning, infra.Status.State)
234+
assert.Equal(t, "Installing infra", infra.Status.Description)
235+
236+
// Test error response
237+
errorServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
238+
w.WriteHeader(http.StatusInternalServerError)
239+
json.NewEncoder(w).Encode(types.APIError{
240+
StatusCode: http.StatusInternalServerError,
241+
Message: "Internal Server Error",
242+
})
243+
}))
244+
defer errorServer.Close()
245+
246+
c = New(errorServer.URL, WithToken("test-token"))
247+
infra, err = c.SetupInfra()
248+
assert.Error(t, err)
249+
assert.Nil(t, infra)
250+
251+
apiErr, ok := err.(*types.APIError)
252+
require.True(t, ok, "Expected err to be of type *types.APIError")
253+
assert.Equal(t, http.StatusInternalServerError, apiErr.StatusCode)
254+
assert.Equal(t, "Internal Server Error", apiErr.Message)
255+
}
256+
257+
func TestGetInfraStatus(t *testing.T) {
258+
// Create a test server
259+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
260+
assert.Equal(t, "GET", r.Method)
261+
assert.Equal(t, "/api/install/infra/status", r.URL.Path)
262+
263+
assert.Equal(t, "application/json", r.Header.Get("Content-Type"))
264+
assert.Equal(t, "Bearer test-token", r.Header.Get("Authorization"))
265+
266+
// Return successful response
267+
w.WriteHeader(http.StatusOK)
268+
json.NewEncoder(w).Encode(types.Infra{
269+
Status: &types.Status{
270+
State: types.StateSucceeded,
271+
Description: "Installation successful",
272+
},
273+
})
274+
}))
275+
defer server.Close()
276+
277+
// Test successful get
278+
c := New(server.URL, WithToken("test-token"))
279+
infra, err := c.GetInfraStatus()
280+
assert.NoError(t, err)
281+
assert.NotNil(t, infra)
282+
assert.Equal(t, types.StateSucceeded, infra.Status.State)
283+
assert.Equal(t, "Installation successful", infra.Status.Description)
284+
285+
// Test error response
286+
errorServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
287+
w.WriteHeader(http.StatusInternalServerError)
288+
json.NewEncoder(w).Encode(types.APIError{
289+
StatusCode: http.StatusInternalServerError,
290+
Message: "Internal Server Error",
291+
})
292+
}))
293+
defer errorServer.Close()
294+
295+
c = New(errorServer.URL, WithToken("test-token"))
296+
infra, err = c.GetInfraStatus()
297+
assert.Error(t, err)
298+
assert.Nil(t, infra)
299+
300+
apiErr, ok := err.(*types.APIError)
301+
require.True(t, ok, "Expected err to be of type *types.APIError")
302+
assert.Equal(t, http.StatusInternalServerError, apiErr.StatusCode)
303+
assert.Equal(t, "Internal Server Error", apiErr.Message)
304+
}
305+
207306
func TestSetInstallStatus(t *testing.T) {
208307
// Create a test server
209308
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

api/client/install.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,60 @@ func (c *client) GetInstallationStatus() (*types.Status, error) {
9494
return &status, nil
9595
}
9696

97+
func (c *client) SetupInfra() (*types.Infra, error) {
98+
req, err := http.NewRequest("POST", c.apiURL+"/api/install/infra/setup", nil)
99+
if err != nil {
100+
return nil, err
101+
}
102+
req.Header.Set("Content-Type", "application/json")
103+
setAuthorizationHeader(req, c.token)
104+
105+
resp, err := c.httpClient.Do(req)
106+
if err != nil {
107+
return nil, err
108+
}
109+
defer resp.Body.Close()
110+
111+
if resp.StatusCode != http.StatusOK {
112+
return nil, errorFromResponse(resp)
113+
}
114+
115+
var infra types.Infra
116+
err = json.NewDecoder(resp.Body).Decode(&infra)
117+
if err != nil {
118+
return nil, err
119+
}
120+
121+
return &infra, nil
122+
}
123+
124+
func (c *client) GetInfraStatus() (*types.Infra, error) {
125+
req, err := http.NewRequest("GET", c.apiURL+"/api/install/infra/status", nil)
126+
if err != nil {
127+
return nil, err
128+
}
129+
req.Header.Set("Content-Type", "application/json")
130+
setAuthorizationHeader(req, c.token)
131+
132+
resp, err := c.httpClient.Do(req)
133+
if err != nil {
134+
return nil, err
135+
}
136+
defer resp.Body.Close()
137+
138+
if resp.StatusCode != http.StatusOK {
139+
return nil, errorFromResponse(resp)
140+
}
141+
142+
var infra types.Infra
143+
err = json.NewDecoder(resp.Body).Decode(&infra)
144+
if err != nil {
145+
return nil, err
146+
}
147+
148+
return &infra, nil
149+
}
150+
97151
func (c *client) SetInstallStatus(s *types.Status) (*types.Status, error) {
98152
b, err := json.Marshal(s)
99153
if err != nil {

api/controllers/install/controller.go

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ import (
44
"context"
55
"sync"
66

7+
"github.com/replicatedhq/embedded-cluster/api/internal/managers/infra"
78
"github.com/replicatedhq/embedded-cluster/api/internal/managers/installation"
89
"github.com/replicatedhq/embedded-cluster/api/internal/managers/preflight"
910
"github.com/replicatedhq/embedded-cluster/api/pkg/logger"
1011
"github.com/replicatedhq/embedded-cluster/api/types"
12+
ecv1beta1 "github.com/replicatedhq/embedded-cluster/kinds/apis/v1beta1"
1113
"github.com/replicatedhq/embedded-cluster/pkg-new/hostutils"
1214
"github.com/replicatedhq/embedded-cluster/pkg/metrics"
1315
"github.com/replicatedhq/embedded-cluster/pkg/release"
@@ -23,7 +25,8 @@ type Controller interface {
2325
GetHostPreflightStatus(ctx context.Context) (*types.Status, error)
2426
GetHostPreflightOutput(ctx context.Context) (*types.HostPreflightsOutput, error)
2527
GetHostPreflightTitles(ctx context.Context) ([]string, error)
26-
SetupNode(ctx context.Context) error
28+
SetupInfra(ctx context.Context) error
29+
GetInfra(ctx context.Context) (*types.Infra, error)
2730
SetStatus(ctx context.Context, status *types.Status) error
2831
GetStatus(ctx context.Context) (*types.Status, error)
2932
}
@@ -34,13 +37,18 @@ type InstallController struct {
3437
install *types.Install
3538
installationManager installation.InstallationManager
3639
hostPreflightManager preflight.HostPreflightManager
40+
infraManager infra.InfraManager
3741
rc runtimeconfig.RuntimeConfig
3842
logger logrus.FieldLogger
3943
hostUtils hostutils.HostUtilsInterface
4044
metricsReporter metrics.ReporterInterface
4145
releaseData *release.ReleaseData
46+
password string
47+
tlsConfig types.TLSConfig
4248
licenseFile string
4349
airgapBundle string
50+
configValues string
51+
endUserConfig *ecv1beta1.Config
4452
mu sync.RWMutex
4553
}
4654

@@ -76,6 +84,18 @@ func WithReleaseData(releaseData *release.ReleaseData) InstallControllerOption {
7684
}
7785
}
7886

87+
func WithPassword(password string) InstallControllerOption {
88+
return func(c *InstallController) {
89+
c.password = password
90+
}
91+
}
92+
93+
func WithTLSConfig(tlsConfig types.TLSConfig) InstallControllerOption {
94+
return func(c *InstallController) {
95+
c.tlsConfig = tlsConfig
96+
}
97+
}
98+
7999
func WithLicenseFile(licenseFile string) InstallControllerOption {
80100
return func(c *InstallController) {
81101
c.licenseFile = licenseFile
@@ -88,6 +108,18 @@ func WithAirgapBundle(airgapBundle string) InstallControllerOption {
88108
}
89109
}
90110

111+
func WithConfigValues(configValues string) InstallControllerOption {
112+
return func(c *InstallController) {
113+
c.configValues = configValues
114+
}
115+
}
116+
117+
func WithEndUserConfig(endUserConfig *ecv1beta1.Config) InstallControllerOption {
118+
return func(c *InstallController) {
119+
c.endUserConfig = endUserConfig
120+
}
121+
}
122+
91123
func WithInstallationManager(installationManager installation.InstallationManager) InstallControllerOption {
92124
return func(c *InstallController) {
93125
c.installationManager = installationManager
@@ -143,5 +175,19 @@ func NewInstallController(opts ...InstallControllerOption) (*InstallController,
143175
)
144176
}
145177

178+
if controller.infraManager == nil {
179+
controller.infraManager = infra.NewInfraManager(
180+
infra.WithRuntimeConfig(controller.rc),
181+
infra.WithLogger(controller.logger),
182+
infra.WithInfra(controller.install.Steps.Infra),
183+
infra.WithPassword(controller.password),
184+
infra.WithTLSConfig(controller.tlsConfig),
185+
infra.WithLicenseFile(controller.licenseFile),
186+
infra.WithAirgapBundle(controller.airgapBundle),
187+
infra.WithConfigValues(controller.configValues),
188+
infra.WithReleaseData(controller.releaseData),
189+
infra.WithEndUserConfig(controller.endUserConfig),
190+
)
191+
}
146192
return controller, nil
147193
}

0 commit comments

Comments
 (0)