Skip to content

Commit 5235538

Browse files
committed
Merge remote-tracking branch 'origin/main' into evansmungai/sc-123579/take-airgap-bundle-size-into-account-when
Signed-off-by: Evans Mungai <evans@replicated.com>
2 parents 5206aab + d52e8a9 commit 5235538

File tree

23 files changed

+1471
-143
lines changed

23 files changed

+1471
-143
lines changed

api/api.go

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -43,20 +43,21 @@ import (
4343
// @externalDocs.description OpenAPI
4444
// @externalDocs.url https://swagger.io/resources/open-api/
4545
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-
logger logrus.FieldLogger
58-
hostUtils hostutils.HostUtilsInterface
59-
metricsReporter metrics.ReporterInterface
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
6061
}
6162

6263
type APIOption func(*API)
@@ -145,6 +146,12 @@ func WithEndUserConfig(endUserConfig *ecv1beta1.Config) APIOption {
145146
}
146147
}
147148

149+
func WithAllowIgnoreHostPreflights(allowIgnoreHostPreflights bool) APIOption {
150+
return func(a *API) {
151+
a.allowIgnoreHostPreflights = allowIgnoreHostPreflights
152+
}
153+
}
154+
148155
func New(password string, opts ...APIOption) (*API, error) {
149156
api := &API{}
150157

@@ -201,6 +208,7 @@ func New(password string, opts ...APIOption) (*API, error) {
201208
install.WithAirgapInfo(api.airgapInfo),
202209
install.WithConfigValues(api.configValues),
203210
install.WithEndUserConfig(api.endUserConfig),
211+
install.WithAllowIgnoreHostPreflights(api.allowIgnoreHostPreflights),
204212
)
205213
if err != nil {
206214
return nil, fmt.Errorf("new install controller: %w", err)

api/controllers/install/controller.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ type Controller interface {
2929
GetHostPreflightStatus(ctx context.Context) (types.Status, error)
3030
GetHostPreflightOutput(ctx context.Context) (*types.HostPreflightsOutput, error)
3131
GetHostPreflightTitles(ctx context.Context) ([]string, error)
32-
SetupInfra(ctx context.Context) error
32+
SetupInfra(ctx context.Context, ignoreHostPreflights bool) error
3333
GetInfra(ctx context.Context) (types.Infra, error)
3434
SetStatus(ctx context.Context, status types.Status) error
3535
GetStatus(ctx context.Context) (types.Status, error)
@@ -57,12 +57,13 @@ type InstallController struct {
5757
configValues string
5858
endUserConfig *ecv1beta1.Config
5959

60-
install types.Install
61-
store store.Store
62-
rc runtimeconfig.RuntimeConfig
63-
stateMachine statemachine.Interface
64-
logger logrus.FieldLogger
65-
mu sync.RWMutex
60+
install types.Install
61+
store store.Store
62+
rc runtimeconfig.RuntimeConfig
63+
stateMachine statemachine.Interface
64+
logger logrus.FieldLogger
65+
mu sync.RWMutex
66+
allowIgnoreHostPreflights bool
6667
}
6768

6869
type InstallControllerOption func(*InstallController)
@@ -145,6 +146,12 @@ func WithEndUserConfig(endUserConfig *ecv1beta1.Config) InstallControllerOption
145146
}
146147
}
147148

149+
func WithAllowIgnoreHostPreflights(allowIgnoreHostPreflights bool) InstallControllerOption {
150+
return func(c *InstallController) {
151+
c.allowIgnoreHostPreflights = allowIgnoreHostPreflights
152+
}
153+
}
154+
148155
func WithInstallationManager(installationManager installation.InstallationManager) InstallControllerOption {
149156
return func(c *InstallController) {
150157
c.installationManager = installationManager

api/controllers/install/controller_test.go

Lines changed: 83 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ func TestConfigureInstallation(t *testing.T) {
246246
assert.Eventually(t, func() bool {
247247
return sm.CurrentState() == tt.expectedState
248248
}, time.Second, 100*time.Millisecond, "state should be %s but is %s", tt.expectedState, sm.CurrentState())
249+
assert.False(t, sm.IsLockAcquired(), "state machine should not be locked after configuration")
249250

250251
mockManager.AssertExpectations(t)
251252
})
@@ -413,6 +414,7 @@ func TestRunHostPreflights(t *testing.T) {
413414
assert.Eventually(t, func() bool {
414415
return sm.CurrentState() == tt.expectedState
415416
}, time.Second, 100*time.Millisecond, "state should be %s but is %s", tt.expectedState, sm.CurrentState())
417+
assert.False(t, sm.IsLockAcquired(), "state machine should not be locked after running preflights")
416418

417419
mockPreflightManager.AssertExpectations(t)
418420
})
@@ -639,27 +641,33 @@ func TestGetInstallationStatus(t *testing.T) {
639641

640642
func TestSetupInfra(t *testing.T) {
641643
tests := []struct {
642-
name string
643-
currentState statemachine.State
644-
expectedState statemachine.State
645-
setupMocks func(runtimeconfig.RuntimeConfig, *preflight.MockHostPreflightManager, *installation.MockInstallationManager, *infra.MockInfraManager, *metrics.MockReporter)
646-
expectedErr bool
644+
name string
645+
clientIgnoreHostPreflights bool // From HTTP request
646+
serverAllowIgnoreHostPreflights bool // From CLI flag
647+
currentState statemachine.State
648+
expectedState statemachine.State
649+
setupMocks func(runtimeconfig.RuntimeConfig, *preflight.MockHostPreflightManager, *installation.MockInstallationManager, *infra.MockInfraManager, *metrics.MockReporter)
650+
expectedErr error
647651
}{
648652
{
649-
name: "successful setup with passed preflights",
650-
currentState: StatePreflightsSucceeded,
651-
expectedState: StateSucceeded,
653+
name: "successful setup with passed preflights",
654+
clientIgnoreHostPreflights: false,
655+
serverAllowIgnoreHostPreflights: true,
656+
currentState: StatePreflightsSucceeded,
657+
expectedState: StateSucceeded,
652658
setupMocks: func(rc runtimeconfig.RuntimeConfig, pm *preflight.MockHostPreflightManager, im *installation.MockInstallationManager, fm *infra.MockInfraManager, r *metrics.MockReporter) {
653659
mock.InOrder(
654660
fm.On("Install", mock.Anything, rc).Return(nil),
655661
)
656662
},
657-
expectedErr: false,
663+
expectedErr: nil,
658664
},
659665
{
660-
name: "successful setup with failed preflights",
661-
currentState: StatePreflightsFailed,
662-
expectedState: StateSucceeded,
666+
name: "successful setup with failed preflights - ignored with CLI flag",
667+
clientIgnoreHostPreflights: true,
668+
serverAllowIgnoreHostPreflights: true,
669+
currentState: StatePreflightsFailed,
670+
expectedState: StateSucceeded,
663671
setupMocks: func(rc runtimeconfig.RuntimeConfig, pm *preflight.MockHostPreflightManager, im *installation.MockInstallationManager, fm *infra.MockInfraManager, r *metrics.MockReporter) {
664672
preflightOutput := &types.HostPreflightsOutput{
665673
Fail: []types.HostPreflightsRecord{
@@ -675,37 +683,73 @@ func TestSetupInfra(t *testing.T) {
675683
fm.On("Install", mock.Anything, rc).Return(nil),
676684
)
677685
},
678-
expectedErr: false,
686+
expectedErr: nil,
679687
},
680688
{
681-
name: "preflight output error",
682-
currentState: StatePreflightsFailed,
683-
expectedState: StatePreflightsFailed,
689+
name: "failed setup with failed preflights - not ignored",
690+
clientIgnoreHostPreflights: false,
691+
serverAllowIgnoreHostPreflights: true,
692+
currentState: StatePreflightsFailed,
693+
expectedState: StatePreflightsFailed,
694+
setupMocks: func(rc runtimeconfig.RuntimeConfig, pm *preflight.MockHostPreflightManager, im *installation.MockInstallationManager, fm *infra.MockInfraManager, r *metrics.MockReporter) {
695+
},
696+
expectedErr: types.NewBadRequestError(ErrPreflightChecksFailed),
697+
},
698+
{
699+
name: "preflight output error",
700+
clientIgnoreHostPreflights: true,
701+
serverAllowIgnoreHostPreflights: true,
702+
currentState: StatePreflightsFailed,
703+
expectedState: StatePreflightsFailed,
684704
setupMocks: func(rc runtimeconfig.RuntimeConfig, pm *preflight.MockHostPreflightManager, im *installation.MockInstallationManager, fm *infra.MockInfraManager, r *metrics.MockReporter) {
685705
mock.InOrder(
686706
pm.On("GetHostPreflightOutput", t.Context()).Return(nil, errors.New("get output error")),
687707
)
688708
},
689-
expectedErr: true,
709+
expectedErr: errors.New("any error"), // Just check that an error occurs, don't care about exact message
690710
},
691711
{
692-
name: "install infra error",
693-
currentState: StatePreflightsSucceeded,
694-
expectedState: StateFailed,
712+
name: "install infra error",
713+
clientIgnoreHostPreflights: false,
714+
serverAllowIgnoreHostPreflights: true,
715+
currentState: StatePreflightsSucceeded,
716+
expectedState: StateFailed,
695717
setupMocks: func(rc runtimeconfig.RuntimeConfig, pm *preflight.MockHostPreflightManager, im *installation.MockInstallationManager, fm *infra.MockInfraManager, r *metrics.MockReporter) {
696718
mock.InOrder(
697719
fm.On("Install", mock.Anything, rc).Return(errors.New("install error")),
698720
)
699721
},
700-
expectedErr: false,
722+
expectedErr: nil,
701723
},
702724
{
703-
name: "invalid state transition",
704-
currentState: StateInstallationConfigured,
705-
expectedState: StateInstallationConfigured,
725+
name: "invalid state transition",
726+
clientIgnoreHostPreflights: false,
727+
serverAllowIgnoreHostPreflights: true,
728+
currentState: StateInstallationConfigured,
729+
expectedState: StateInstallationConfigured,
706730
setupMocks: func(rc runtimeconfig.RuntimeConfig, pm *preflight.MockHostPreflightManager, im *installation.MockInstallationManager, fm *infra.MockInfraManager, r *metrics.MockReporter) {
707731
},
708-
expectedErr: true,
732+
expectedErr: errors.New("invalid transition"), // Just check that an error occurs, don't care about exact message
733+
},
734+
{
735+
name: "failed preflights with ignore flag but CLI flag disabled",
736+
clientIgnoreHostPreflights: true,
737+
serverAllowIgnoreHostPreflights: false,
738+
currentState: StatePreflightsFailed,
739+
expectedState: StatePreflightsFailed,
740+
setupMocks: func(rc runtimeconfig.RuntimeConfig, pm *preflight.MockHostPreflightManager, im *installation.MockInstallationManager, fm *infra.MockInfraManager, r *metrics.MockReporter) {
741+
},
742+
expectedErr: types.NewBadRequestError(ErrPreflightChecksFailed),
743+
},
744+
{
745+
name: "failed preflights without ignore flag and CLI flag disabled",
746+
clientIgnoreHostPreflights: false,
747+
serverAllowIgnoreHostPreflights: false,
748+
currentState: StatePreflightsFailed,
749+
expectedState: StatePreflightsFailed,
750+
setupMocks: func(rc runtimeconfig.RuntimeConfig, pm *preflight.MockHostPreflightManager, im *installation.MockInstallationManager, fm *infra.MockInfraManager, r *metrics.MockReporter) {
751+
},
752+
expectedErr: types.NewBadRequestError(ErrPreflightChecksFailed),
709753
},
710754
}
711755

@@ -730,13 +774,24 @@ func TestSetupInfra(t *testing.T) {
730774
WithInstallationManager(mockInstallationManager),
731775
WithInfraManager(mockInfraManager),
732776
WithMetricsReporter(mockMetricsReporter),
777+
WithAllowIgnoreHostPreflights(tt.serverAllowIgnoreHostPreflights),
733778
)
734779
require.NoError(t, err)
735780

736-
err = controller.SetupInfra(t.Context())
781+
err = controller.SetupInfra(t.Context(), tt.clientIgnoreHostPreflights)
737782

738-
if tt.expectedErr {
783+
if tt.expectedErr != nil {
739784
require.Error(t, err)
785+
786+
// Check for specific error types
787+
var expectedAPIErr *types.APIError
788+
if errors.As(tt.expectedErr, &expectedAPIErr) {
789+
// For API errors, check the exact type and status code
790+
var actualAPIErr *types.APIError
791+
require.True(t, errors.As(err, &actualAPIErr), "expected error to be of type *types.APIError, got %T", err)
792+
assert.Equal(t, expectedAPIErr.StatusCode, actualAPIErr.StatusCode, "status codes should match")
793+
assert.Contains(t, actualAPIErr.Error(), expectedAPIErr.Unwrap().Error(), "error messages should contain expected content")
794+
}
740795
} else {
741796
require.NoError(t, err)
742797

@@ -746,6 +801,7 @@ func TestSetupInfra(t *testing.T) {
746801
assert.Eventually(t, func() bool {
747802
return sm.CurrentState() == tt.expectedState
748803
}, time.Second, 100*time.Millisecond, "state should be %s but is %s", tt.expectedState, sm.CurrentState())
804+
assert.False(t, sm.IsLockAcquired(), "state machine should not be locked after running infra setup")
749805

750806
mockPreflightManager.AssertExpectations(t)
751807
mockInstallationManager.AssertExpectations(t)

api/controllers/install/infra.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,21 @@ package install
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67
"runtime/debug"
78

89
"github.com/replicatedhq/embedded-cluster/api/types"
910
)
1011

11-
func (c *InstallController) SetupInfra(ctx context.Context) (finalErr error) {
12+
var (
13+
ErrPreflightChecksFailed = errors.New("preflight checks failed")
14+
ErrPreflightChecksNotComplete = errors.New("preflight checks not complete")
15+
)
16+
17+
func (c *InstallController) SetupInfra(ctx context.Context, ignoreHostPreflights bool) (finalErr error) {
1218
if c.stateMachine.CurrentState() == StatePreflightsFailed {
13-
err := c.bypassPreflights(ctx)
19+
err := c.bypassPreflights(ctx, ignoreHostPreflights)
1420
if err != nil {
1521
return fmt.Errorf("bypass preflights: %w", err)
1622
}
@@ -68,7 +74,11 @@ func (c *InstallController) SetupInfra(ctx context.Context) (finalErr error) {
6874
return nil
6975
}
7076

71-
func (c *InstallController) bypassPreflights(ctx context.Context) error {
77+
func (c *InstallController) bypassPreflights(ctx context.Context, ignoreHostPreflights bool) error {
78+
if !ignoreHostPreflights || !c.allowIgnoreHostPreflights {
79+
return types.NewBadRequestError(ErrPreflightChecksFailed)
80+
}
81+
7282
lock, err := c.stateMachine.AcquireLock()
7383
if err != nil {
7484
return types.NewConflictError(err)
@@ -85,6 +95,8 @@ func (c *InstallController) bypassPreflights(ctx context.Context) error {
8595
if err != nil {
8696
return fmt.Errorf("get install host preflight output: %w", err)
8797
}
98+
99+
// Report that preflights were bypassed
88100
if preflightOutput != nil {
89101
c.metricsReporter.ReportPreflightsBypassed(ctx, preflightOutput)
90102
}

0 commit comments

Comments
 (0)