Skip to content

Commit 1290ed1

Browse files
committed
Revert "chore(v3): revert milestone 7 (#2741)"
This reverts commit 1096f42.
1 parent 144639b commit 1290ed1

38 files changed

+2195
-208
lines changed

api/controllers/app/install/controller.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/replicatedhq/embedded-cluster/pkg/release"
1717
kotsv1beta1 "github.com/replicatedhq/kotskinds/apis/kots/v1beta1"
1818
"github.com/sirupsen/logrus"
19+
"k8s.io/cli-runtime/pkg/genericclioptions"
1920
kyaml "sigs.k8s.io/yaml"
2021
)
2122

@@ -27,7 +28,7 @@ type Controller interface {
2728
GetAppPreflightStatus(ctx context.Context) (types.Status, error)
2829
GetAppPreflightOutput(ctx context.Context) (*types.PreflightsOutput, error)
2930
GetAppPreflightTitles(ctx context.Context) ([]string, error)
30-
InstallApp(ctx context.Context, ignoreAppPreflights bool) error
31+
InstallApp(ctx context.Context, opts InstallAppOptions) error
3132
GetAppInstallStatus(ctx context.Context) (types.AppInstall, error)
3233
}
3334

@@ -47,6 +48,8 @@ type InstallController struct {
4748
clusterID string
4849
airgapBundle string
4950
privateCACertConfigMapName string
51+
restClientGetter genericclioptions.RESTClientGetter
52+
kubeConfigPath string
5053
}
5154

5255
type InstallControllerOption func(*InstallController)
@@ -129,6 +132,18 @@ func WithPrivateCACertConfigMapName(configMapName string) InstallControllerOptio
129132
}
130133
}
131134

135+
func WithRESTClientGetter(restClientGetter genericclioptions.RESTClientGetter) InstallControllerOption {
136+
return func(c *InstallController) {
137+
c.restClientGetter = restClientGetter
138+
}
139+
}
140+
141+
func WithKubeConfigPath(kubeConfigPath string) InstallControllerOption {
142+
return func(c *InstallController) {
143+
c.kubeConfigPath = kubeConfigPath
144+
}
145+
}
146+
132147
func NewInstallController(opts ...InstallControllerOption) (*InstallController, error) {
133148
controller := &InstallController{
134149
logger: logger.NewDiscardLogger(),
@@ -205,6 +220,8 @@ func NewInstallController(opts ...InstallControllerOption) (*InstallController,
205220
appinstallmanager.WithClusterID(controller.clusterID),
206221
appinstallmanager.WithAirgapBundle(controller.airgapBundle),
207222
appinstallmanager.WithAppInstallStore(controller.store.AppInstallStore()),
223+
appinstallmanager.WithRESTClientGetter(controller.restClientGetter),
224+
appinstallmanager.WithKubeConfigPath(controller.kubeConfigPath),
208225
)
209226
if err != nil {
210227
return nil, fmt.Errorf("create app install manager: %w", err)

api/controllers/app/install/controller_mock.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ func (m *MockController) GetAppPreflightTitles(ctx context.Context) ([]string, e
6969
}
7070

7171
// InstallApp mocks the InstallApp method
72-
func (m *MockController) InstallApp(ctx context.Context, ignoreAppPreflights bool) error {
73-
args := m.Called(ctx, ignoreAppPreflights)
72+
func (m *MockController) InstallApp(ctx context.Context, opts InstallAppOptions) error {
73+
args := m.Called(ctx, opts)
7474
return args.Error(0)
7575
}
7676

api/controllers/app/install/install.go

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,21 @@ import (
88

99
states "github.com/replicatedhq/embedded-cluster/api/internal/states/install"
1010
"github.com/replicatedhq/embedded-cluster/api/types"
11+
ecv1beta1 "github.com/replicatedhq/embedded-cluster/kinds/apis/v1beta1"
1112
)
1213

1314
var (
1415
ErrAppPreflightChecksFailed = errors.New("app preflight checks failed")
1516
)
1617

18+
type InstallAppOptions struct {
19+
IgnoreAppPreflights bool
20+
ProxySpec *ecv1beta1.ProxySpec
21+
RegistrySettings *types.RegistrySettings
22+
}
23+
1724
// InstallApp triggers app installation with proper state transitions and panic handling
18-
func (c *InstallController) InstallApp(ctx context.Context, ignoreAppPreflights bool) (finalErr error) {
25+
func (c *InstallController) InstallApp(ctx context.Context, opts InstallAppOptions) (finalErr error) {
1926
lock, err := c.stateMachine.AcquireLock()
2027
if err != nil {
2128
return types.NewConflictError(err)
@@ -33,7 +40,7 @@ func (c *InstallController) InstallApp(ctx context.Context, ignoreAppPreflights
3340
// Check if app preflights have failed and if we should ignore them
3441
if c.stateMachine.CurrentState() == states.StateAppPreflightsFailed {
3542
allowIgnoreAppPreflights := true // TODO: implement once we check for strict app preflights
36-
if !ignoreAppPreflights || !allowIgnoreAppPreflights {
43+
if !opts.IgnoreAppPreflights || !allowIgnoreAppPreflights {
3744
return types.NewBadRequestError(ErrAppPreflightChecksFailed)
3845
}
3946
err = c.stateMachine.Transition(lock, states.StateAppPreflightsFailedBypassed)
@@ -47,9 +54,15 @@ func (c *InstallController) InstallApp(ctx context.Context, ignoreAppPreflights
4754
}
4855

4956
// Get config values for app installation
50-
configValues, err := c.appConfigManager.GetKotsadmConfigValues()
57+
appConfigValues, err := c.GetAppConfigValues(ctx)
58+
if err != nil {
59+
return fmt.Errorf("get app config values for app install: %w", err)
60+
}
61+
62+
// Get KOTS config values for the KOTS CLI
63+
kotsConfigValues, err := c.appConfigManager.GetKotsadmConfigValues()
5164
if err != nil {
52-
return fmt.Errorf("get kotsadm config values for app install: %w", err)
65+
return fmt.Errorf("get kots config values for app install: %w", err)
5366
}
5467

5568
err = c.stateMachine.Transition(lock, states.StateAppInstalling)
@@ -80,8 +93,14 @@ func (c *InstallController) InstallApp(ctx context.Context, ignoreAppPreflights
8093
}
8194
}()
8295

83-
// Install the app
84-
err := c.appInstallManager.Install(ctx, configValues)
96+
// Extract installable Helm charts from release manager
97+
installableCharts, err := c.appReleaseManager.ExtractInstallableHelmCharts(ctx, appConfigValues, opts.ProxySpec, opts.RegistrySettings)
98+
if err != nil {
99+
return fmt.Errorf("extract installable helm charts: %w", err)
100+
}
101+
102+
// Install the app with installable charts and kots config values
103+
err = c.appInstallManager.Install(ctx, installableCharts, kotsConfigValues)
85104
if err != nil {
86105
return fmt.Errorf("install app: %w", err)
87106
}

api/controllers/app/install/test_suite.go

Lines changed: 114 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
states "github.com/replicatedhq/embedded-cluster/api/internal/states/install"
1414
"github.com/replicatedhq/embedded-cluster/api/internal/store"
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/release"
1718
kotsv1beta1 "github.com/replicatedhq/kotskinds/apis/kots/v1beta1"
1819
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
@@ -503,16 +504,18 @@ func (s *AppInstallControllerTestSuite) TestInstallApp() {
503504
tests := []struct {
504505
name string
505506
ignoreAppPreflights bool
507+
proxySpec *ecv1beta1.ProxySpec
508+
registrySettings *types.RegistrySettings
506509
currentState statemachine.State
507510
expectedState statemachine.State
508-
setupMocks func(*appconfig.MockAppConfigManager, *appinstallmanager.MockAppInstallManager)
511+
setupMocks func(*appconfig.MockAppConfigManager, *appreleasemanager.MockAppReleaseManager, *appinstallmanager.MockAppInstallManager)
509512
expectedErr bool
510513
}{
511514
{
512515
name: "invalid state transition from succeeded state",
513516
currentState: states.StateSucceeded,
514517
expectedState: states.StateSucceeded,
515-
setupMocks: func(acm *appconfig.MockAppConfigManager, aim *appinstallmanager.MockAppInstallManager) {
518+
setupMocks: func(acm *appconfig.MockAppConfigManager, arm *appreleasemanager.MockAppReleaseManager, aim *appinstallmanager.MockAppInstallManager) {
516519
// No mocks needed for invalid state transition
517520
},
518521
expectedErr: true,
@@ -521,27 +524,37 @@ func (s *AppInstallControllerTestSuite) TestInstallApp() {
521524
name: "invalid state transition from infrastructure installing state",
522525
currentState: states.StateInfrastructureInstalling,
523526
expectedState: states.StateInfrastructureInstalling,
524-
setupMocks: func(acm *appconfig.MockAppConfigManager, aim *appinstallmanager.MockAppInstallManager) {
527+
setupMocks: func(acm *appconfig.MockAppConfigManager, arm *appreleasemanager.MockAppReleaseManager, aim *appinstallmanager.MockAppInstallManager) {
525528
// No mocks needed for invalid state transition
526529
},
527530
expectedErr: true,
528531
},
529532
{
530-
name: "successful app installation from app preflights succeeded state",
533+
name: "successful app installation from app preflights succeeded state with helm charts",
531534
currentState: states.StateAppPreflightsSucceeded,
532535
expectedState: states.StateSucceeded,
533-
setupMocks: func(acm *appconfig.MockAppConfigManager, aim *appinstallmanager.MockAppInstallManager) {
534-
mock.InOrder(
535-
acm.On("GetKotsadmConfigValues").Return(kotsv1beta1.ConfigValues{
536-
Spec: kotsv1beta1.ConfigValuesSpec{
537-
Values: map[string]kotsv1beta1.ConfigValue{
538-
"test-key": {Value: "test-value"},
539-
},
536+
setupMocks: func(acm *appconfig.MockAppConfigManager, arm *appreleasemanager.MockAppReleaseManager, aim *appinstallmanager.MockAppInstallManager) {
537+
configValues := kotsv1beta1.ConfigValues{
538+
Spec: kotsv1beta1.ConfigValuesSpec{
539+
Values: map[string]kotsv1beta1.ConfigValue{
540+
"test-key": {Value: "test-value"},
540541
},
541-
}, nil),
542-
aim.On("Install", mock.Anything, mock.MatchedBy(func(cv kotsv1beta1.ConfigValues) bool {
543-
return cv.Spec.Values["test-key"].Value == "test-value"
544-
})).Return(nil),
542+
},
543+
}
544+
expectedCharts := []types.InstallableHelmChart{
545+
{
546+
Archive: []byte("chart-archive-data"),
547+
Values: map[string]any{"key": "value"},
548+
},
549+
}
550+
appConfigValues := types.AppConfigValues{
551+
"test-key": types.AppConfigValue{Value: "test-value"},
552+
}
553+
mock.InOrder(
554+
acm.On("GetConfigValues").Return(appConfigValues, nil),
555+
acm.On("GetKotsadmConfigValues").Return(configValues, nil),
556+
arm.On("ExtractInstallableHelmCharts", mock.Anything, appConfigValues, mock.AnythingOfType("*v1beta1.ProxySpec"), mock.AnythingOfType("*types.RegistrySettings")).Return(expectedCharts, nil),
557+
aim.On("Install", mock.Anything, expectedCharts, configValues).Return(nil),
545558
)
546559
},
547560
expectedErr: false,
@@ -550,18 +563,22 @@ func (s *AppInstallControllerTestSuite) TestInstallApp() {
550563
name: "successful app installation from app preflights failed bypassed state",
551564
currentState: states.StateAppPreflightsFailedBypassed,
552565
expectedState: states.StateSucceeded,
553-
setupMocks: func(acm *appconfig.MockAppConfigManager, aim *appinstallmanager.MockAppInstallManager) {
554-
mock.InOrder(
555-
acm.On("GetKotsadmConfigValues").Return(kotsv1beta1.ConfigValues{
556-
Spec: kotsv1beta1.ConfigValuesSpec{
557-
Values: map[string]kotsv1beta1.ConfigValue{
558-
"test-key": {Value: "test-value"},
559-
},
566+
setupMocks: func(acm *appconfig.MockAppConfigManager, arm *appreleasemanager.MockAppReleaseManager, aim *appinstallmanager.MockAppInstallManager) {
567+
configValues := kotsv1beta1.ConfigValues{
568+
Spec: kotsv1beta1.ConfigValuesSpec{
569+
Values: map[string]kotsv1beta1.ConfigValue{
570+
"test-key": {Value: "test-value"},
560571
},
561-
}, nil),
562-
aim.On("Install", mock.Anything, mock.MatchedBy(func(cv kotsv1beta1.ConfigValues) bool {
563-
return cv.Spec.Values["test-key"].Value == "test-value"
564-
})).Return(nil),
572+
},
573+
}
574+
appConfigValues := types.AppConfigValues{
575+
"test-key": types.AppConfigValue{Value: "test-value"},
576+
}
577+
mock.InOrder(
578+
acm.On("GetConfigValues").Return(appConfigValues, nil),
579+
acm.On("GetKotsadmConfigValues").Return(configValues, nil),
580+
arm.On("ExtractInstallableHelmCharts", mock.Anything, appConfigValues, mock.AnythingOfType("*v1beta1.ProxySpec"), mock.AnythingOfType("*types.RegistrySettings")).Return([]types.InstallableHelmChart{}, nil),
581+
aim.On("Install", mock.Anything, []types.InstallableHelmChart{}, configValues).Return(nil),
565582
)
566583
},
567584
expectedErr: false,
@@ -570,7 +587,11 @@ func (s *AppInstallControllerTestSuite) TestInstallApp() {
570587
name: "get config values error",
571588
currentState: states.StateAppPreflightsSucceeded,
572589
expectedState: states.StateAppPreflightsSucceeded,
573-
setupMocks: func(acm *appconfig.MockAppConfigManager, aim *appinstallmanager.MockAppInstallManager) {
590+
setupMocks: func(acm *appconfig.MockAppConfigManager, arm *appreleasemanager.MockAppReleaseManager, aim *appinstallmanager.MockAppInstallManager) {
591+
appConfigValues := types.AppConfigValues{
592+
"test-key": types.AppConfigValue{Value: "test-value"},
593+
}
594+
acm.On("GetConfigValues").Return(appConfigValues, nil)
574595
acm.On("GetKotsadmConfigValues").Return(kotsv1beta1.ConfigValues{}, errors.New("config values error"))
575596
},
576597
expectedErr: true,
@@ -580,18 +601,22 @@ func (s *AppInstallControllerTestSuite) TestInstallApp() {
580601
ignoreAppPreflights: true,
581602
currentState: states.StateAppPreflightsFailed,
582603
expectedState: states.StateSucceeded,
583-
setupMocks: func(acm *appconfig.MockAppConfigManager, aim *appinstallmanager.MockAppInstallManager) {
584-
mock.InOrder(
585-
acm.On("GetKotsadmConfigValues").Return(kotsv1beta1.ConfigValues{
586-
Spec: kotsv1beta1.ConfigValuesSpec{
587-
Values: map[string]kotsv1beta1.ConfigValue{
588-
"test-key": {Value: "test-value"},
589-
},
604+
setupMocks: func(acm *appconfig.MockAppConfigManager, arm *appreleasemanager.MockAppReleaseManager, aim *appinstallmanager.MockAppInstallManager) {
605+
configValues := kotsv1beta1.ConfigValues{
606+
Spec: kotsv1beta1.ConfigValuesSpec{
607+
Values: map[string]kotsv1beta1.ConfigValue{
608+
"test-key": {Value: "test-value"},
590609
},
591-
}, nil),
592-
aim.On("Install", mock.Anything, mock.MatchedBy(func(cv kotsv1beta1.ConfigValues) bool {
593-
return cv.Spec.Values["test-key"].Value == "test-value"
594-
})).Return(nil),
610+
},
611+
}
612+
appConfigValues := types.AppConfigValues{
613+
"test-key": types.AppConfigValue{Value: "test-value"},
614+
}
615+
mock.InOrder(
616+
acm.On("GetConfigValues").Return(appConfigValues, nil),
617+
acm.On("GetKotsadmConfigValues").Return(configValues, nil),
618+
arm.On("ExtractInstallableHelmCharts", mock.Anything, appConfigValues, mock.AnythingOfType("*v1beta1.ProxySpec"), mock.AnythingOfType("*types.RegistrySettings")).Return([]types.InstallableHelmChart{}, nil),
619+
aim.On("Install", mock.Anything, []types.InstallableHelmChart{}, configValues).Return(nil),
595620
)
596621
},
597622
expectedErr: false,
@@ -601,11 +626,54 @@ func (s *AppInstallControllerTestSuite) TestInstallApp() {
601626
ignoreAppPreflights: false,
602627
currentState: states.StateAppPreflightsFailed,
603628
expectedState: states.StateAppPreflightsFailed,
604-
setupMocks: func(acm *appconfig.MockAppConfigManager, aim *appinstallmanager.MockAppInstallManager) {
629+
setupMocks: func(acm *appconfig.MockAppConfigManager, arm *appreleasemanager.MockAppReleaseManager, aim *appinstallmanager.MockAppInstallManager) {
605630
// No mocks needed as method should return early with error
606631
},
607632
expectedErr: true,
608633
},
634+
{
635+
name: "successful app installation with proxy spec passed to helm chart extraction",
636+
currentState: states.StateAppPreflightsSucceeded,
637+
expectedState: states.StateSucceeded,
638+
proxySpec: &ecv1beta1.ProxySpec{
639+
HTTPProxy: "http://proxy.example.com:8080",
640+
HTTPSProxy: "https://proxy.example.com:8080",
641+
NoProxy: "localhost,127.0.0.1",
642+
},
643+
registrySettings: &types.RegistrySettings{
644+
HasLocalRegistry: true,
645+
Host: "10.128.0.11:5000",
646+
},
647+
setupMocks: func(acm *appconfig.MockAppConfigManager, arm *appreleasemanager.MockAppReleaseManager, aim *appinstallmanager.MockAppInstallManager) {
648+
configValues := kotsv1beta1.ConfigValues{
649+
Spec: kotsv1beta1.ConfigValuesSpec{
650+
Values: map[string]kotsv1beta1.ConfigValue{
651+
"test-key": {Value: "test-value"},
652+
},
653+
},
654+
}
655+
appConfigValues := types.AppConfigValues{
656+
"test-key": types.AppConfigValue{Value: "test-value"},
657+
}
658+
expectedCharts := []types.InstallableHelmChart{
659+
{
660+
Archive: []byte("chart-with-proxy-template"),
661+
Values: map[string]any{"proxy_url": "http://proxy.example.com:8080"},
662+
},
663+
}
664+
mock.InOrder(
665+
acm.On("GetConfigValues").Return(appConfigValues, nil),
666+
acm.On("GetKotsadmConfigValues").Return(configValues, nil),
667+
arm.On("ExtractInstallableHelmCharts", mock.Anything, appConfigValues, mock.MatchedBy(func(proxySpec *ecv1beta1.ProxySpec) bool {
668+
return proxySpec != nil
669+
}), mock.MatchedBy(func(registrySettings *types.RegistrySettings) bool {
670+
return registrySettings != nil
671+
})).Return(expectedCharts, nil),
672+
aim.On("Install", mock.Anything, expectedCharts, configValues).Return(nil),
673+
)
674+
},
675+
expectedErr: false,
676+
},
609677
}
610678

611679
for _, tt := range tests {
@@ -627,8 +695,12 @@ func (s *AppInstallControllerTestSuite) TestInstallApp() {
627695
)
628696
require.NoError(t, err, "failed to create install controller")
629697

630-
tt.setupMocks(appConfigManager, appInstallManager)
631-
err = controller.InstallApp(t.Context(), tt.ignoreAppPreflights)
698+
tt.setupMocks(appConfigManager, appReleaseManager, appInstallManager)
699+
err = controller.InstallApp(t.Context(), InstallAppOptions{
700+
IgnoreAppPreflights: tt.ignoreAppPreflights,
701+
ProxySpec: tt.proxySpec,
702+
RegistrySettings: tt.registrySettings,
703+
})
632704

633705
if tt.expectedErr {
634706
assert.Error(t, err)
@@ -643,6 +715,7 @@ func (s *AppInstallControllerTestSuite) TestInstallApp() {
643715
assert.False(t, sm.IsLockAcquired(), "state machine should not be locked after app installation")
644716

645717
appConfigManager.AssertExpectations(s.T())
718+
appReleaseManager.AssertExpectations(s.T())
646719
appInstallManager.AssertExpectations(s.T())
647720
})
648721
}

api/controllers/kubernetes/install/controller.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ func NewInstallController(opts ...InstallControllerOption) (*InstallController,
192192
appcontroller.WithConfigValues(controller.configValues),
193193
appcontroller.WithAirgapBundle(controller.airgapBundle),
194194
appcontroller.WithPrivateCACertConfigMapName(""), // Private CA ConfigMap functionality not yet implemented for Kubernetes installations
195+
appcontroller.WithRESTClientGetter(controller.restClientGetter),
195196
)
196197
if err != nil {
197198
return nil, fmt.Errorf("create app install controller: %w", err)

api/controllers/kubernetes/install/controller_mock.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,8 @@ func (m *MockController) RunAppPreflights(ctx context.Context, opts appcontrolle
109109
}
110110

111111
// InstallApp mocks the InstallApp method
112-
func (m *MockController) InstallApp(ctx context.Context, ignoreAppPreflights bool) error {
113-
args := m.Called(ctx, ignoreAppPreflights)
112+
func (m *MockController) InstallApp(ctx context.Context, opts appcontroller.InstallAppOptions) error {
113+
args := m.Called(ctx, opts)
114114
return args.Error(0)
115115
}
116116

api/controllers/linux/install/controller.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ func NewInstallController(opts ...InstallControllerOption) (*InstallController,
266266
appcontroller.WithClusterID(controller.clusterID),
267267
appcontroller.WithAirgapBundle(controller.airgapBundle),
268268
appcontroller.WithPrivateCACertConfigMapName(adminconsole.PrivateCASConfigMapName), // Linux installations use the ConfigMap
269+
appcontroller.WithKubeConfigPath(controller.rc.PathToKubeConfig()),
269270
)
270271
if err != nil {
271272
return nil, fmt.Errorf("create app install controller: %w", err)

0 commit comments

Comments
 (0)