Skip to content

Commit 36f6600

Browse files
authored
feat(api): implement IsAirgap template function (#3056)
* feat(api): implement IsAirgap template function * fix * f * f * f * f
1 parent 6880001 commit 36f6600

File tree

11 files changed

+378
-6
lines changed

11 files changed

+378
-6
lines changed

.github/workflows/ci.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,7 @@ jobs:
385385
with:
386386
files: |
387387
e2e/**
388+
!e2e/kots-release-install-v3/**
388389
api/*.go
389390
api/types/**
390391
api/pkg/**

api/controllers/app/controller.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ func NewAppController(opts ...AppControllerOption) (*AppController, error) {
167167
appconfig.WithAppConfigStore(controller.store.AppConfigStore()),
168168
appconfig.WithReleaseData(controller.releaseData),
169169
appconfig.WithLicense(license),
170+
appconfig.WithIsAirgap(controller.airgapBundle != ""),
170171
appconfig.WithPrivateCACertConfigMapName(controller.privateCACertConfigMapName),
171172
)
172173
if err != nil {
@@ -199,6 +200,7 @@ func NewAppController(opts ...AppControllerOption) (*AppController, error) {
199200
appreleasemanager.WithLogger(controller.logger),
200201
appreleasemanager.WithReleaseData(controller.releaseData),
201202
appreleasemanager.WithLicense(license),
203+
appreleasemanager.WithIsAirgap(controller.airgapBundle != ""),
202204
appreleasemanager.WithPrivateCACertConfigMapName(controller.privateCACertConfigMapName),
203205
)
204206
if err != nil {

api/internal/managers/app/config/manager.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,11 @@ type appConfigManager struct {
3333
appConfigStore configstore.Store
3434
releaseData *release.ReleaseData
3535
license *kotsv1beta1.License
36-
logger logrus.FieldLogger
37-
templateEngine *apitemplate.Engine
36+
isAirgap bool
3837
privateCACertConfigMapName string
38+
39+
logger logrus.FieldLogger
40+
templateEngine *apitemplate.Engine
3941
}
4042

4143
type AppConfigManagerOption func(*appConfigManager)
@@ -64,6 +66,12 @@ func WithLicense(license *kotsv1beta1.License) AppConfigManagerOption {
6466
}
6567
}
6668

69+
func WithIsAirgap(isAirgap bool) AppConfigManagerOption {
70+
return func(c *appConfigManager) {
71+
c.isAirgap = isAirgap
72+
}
73+
}
74+
6775
func WithPrivateCACertConfigMapName(configMapName string) AppConfigManagerOption {
6876
return func(c *appConfigManager) {
6977
c.privateCACertConfigMapName = configMapName
@@ -92,8 +100,9 @@ func NewAppConfigManager(config kotsv1beta1.Config, opts ...AppConfigManagerOpti
92100
manager.templateEngine = apitemplate.NewEngine(
93101
&manager.rawConfig,
94102
apitemplate.WithMode(apitemplate.ModeConfig),
95-
apitemplate.WithLicense(manager.license),
96103
apitemplate.WithReleaseData(manager.releaseData),
104+
apitemplate.WithLicense(manager.license),
105+
apitemplate.WithIsAirgap(manager.isAirgap),
97106
apitemplate.WithPrivateCACertConfigMapName(manager.privateCACertConfigMapName),
98107
)
99108
}

api/internal/managers/app/config/template_test.go

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,4 +316,111 @@ status: {}
316316
assert.NotEmpty(t, result1)
317317
assert.NotEmpty(t, result2)
318318
})
319+
320+
// Test IsAirgap template function
321+
t.Run("IsAirgap template function", func(t *testing.T) {
322+
airgapConfig := kotsv1beta1.Config{
323+
TypeMeta: metav1.TypeMeta{
324+
APIVersion: "kots.io/v1beta1",
325+
Kind: "Config",
326+
},
327+
ObjectMeta: metav1.ObjectMeta{
328+
Name: "airgap-test-config",
329+
},
330+
Spec: kotsv1beta1.ConfigSpec{
331+
Groups: []kotsv1beta1.ConfigGroup{
332+
{
333+
Name: "airgap_tests",
334+
Title: "Airgap Tests",
335+
Items: []kotsv1beta1.ConfigItem{
336+
{
337+
Name: "airgap_mode",
338+
Title: "Airgap Mode",
339+
Type: "text",
340+
Default: multitype.FromString(`{{repl IsAirgap | ternary "airgap" "online" }}`),
341+
Value: multitype.FromString(`{{repl IsAirgap }}`),
342+
},
343+
{
344+
Name: "installation_type",
345+
Title: "Installation Type",
346+
Type: "text",
347+
Default: multitype.FromString(`{{repl if IsAirgap }}Airgap Installation{{repl else }}Online Installation{{repl end }}`),
348+
Value: multitype.FromString(`{{repl if IsAirgap }}Disconnected{{repl else }}Connected{{repl end }}`),
349+
},
350+
},
351+
},
352+
},
353+
},
354+
}
355+
356+
// Test with airgap bundle set (airgap installation)
357+
t.Run("with airgap bundle", func(t *testing.T) {
358+
manager, err := NewAppConfigManager(airgapConfig, WithIsAirgap(true))
359+
require.NoError(t, err)
360+
require.NotNil(t, manager)
361+
362+
result, err := manager.executeConfigTemplate(types.AppConfigValues{})
363+
require.NoError(t, err)
364+
require.NotEmpty(t, result)
365+
366+
expectedYAML := `apiVersion: kots.io/v1beta1
367+
kind: Config
368+
metadata:
369+
name: airgap-test-config
370+
spec:
371+
groups:
372+
- items:
373+
- default: airgap
374+
name: airgap_mode
375+
title: Airgap Mode
376+
type: text
377+
value: "true"
378+
- default: Airgap Installation
379+
name: installation_type
380+
title: Installation Type
381+
type: text
382+
value: Disconnected
383+
name: airgap_tests
384+
title: Airgap Tests
385+
status: {}
386+
`
387+
388+
assert.Equal(t, expectedYAML, result)
389+
})
390+
391+
// Test without airgap bundle (online installation)
392+
t.Run("without airgap bundle", func(t *testing.T) {
393+
manager, err := NewAppConfigManager(airgapConfig)
394+
require.NoError(t, err)
395+
require.NotNil(t, manager)
396+
397+
result, err := manager.executeConfigTemplate(types.AppConfigValues{})
398+
require.NoError(t, err)
399+
require.NotEmpty(t, result)
400+
401+
expectedYAML := `apiVersion: kots.io/v1beta1
402+
kind: Config
403+
metadata:
404+
name: airgap-test-config
405+
spec:
406+
groups:
407+
- items:
408+
- default: online
409+
name: airgap_mode
410+
title: Airgap Mode
411+
type: text
412+
value: "false"
413+
- default: Online Installation
414+
name: installation_type
415+
title: Installation Type
416+
type: text
417+
value: Connected
418+
name: airgap_tests
419+
title: Airgap Tests
420+
status: {}
421+
`
422+
423+
assert.Equal(t, expectedYAML, result)
424+
})
425+
})
319426
}

api/internal/managers/app/release/manager.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@ type AppReleaseManager interface {
2222
type appReleaseManager struct {
2323
rawConfig kotsv1beta1.Config
2424
releaseData *release.ReleaseData
25-
templateEngine *template.Engine
2625
license *kotsv1beta1.License
27-
logger logrus.FieldLogger
26+
isAirgap bool
2827
privateCACertConfigMapName string
28+
29+
templateEngine *template.Engine
30+
logger logrus.FieldLogger
2931
}
3032

3133
type AppReleaseManagerOption func(*appReleaseManager)
@@ -54,6 +56,12 @@ func WithLicense(license *kotsv1beta1.License) AppReleaseManagerOption {
5456
}
5557
}
5658

59+
func WithIsAirgap(isAirgap bool) AppReleaseManagerOption {
60+
return func(m *appReleaseManager) {
61+
m.isAirgap = isAirgap
62+
}
63+
}
64+
5765
func WithPrivateCACertConfigMapName(configMapName string) AppReleaseManagerOption {
5866
return func(m *appReleaseManager) {
5967
m.privateCACertConfigMapName = configMapName
@@ -81,8 +89,9 @@ func NewAppReleaseManager(config kotsv1beta1.Config, opts ...AppReleaseManagerOp
8189
if manager.templateEngine == nil {
8290
manager.templateEngine = template.NewEngine(
8391
&manager.rawConfig,
84-
template.WithLicense(manager.license),
8592
template.WithReleaseData(manager.releaseData),
93+
template.WithLicense(manager.license),
94+
template.WithIsAirgap(manager.isAirgap),
8695
template.WithPrivateCACertConfigMapName(manager.privateCACertConfigMapName),
8796
)
8897
}

api/internal/managers/app/release/template_test.go

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,7 @@ func TestAppReleaseManager_templateHelmChartCRs(t *testing.T) {
368368
configValues types.AppConfigValues
369369
proxySpec *ecv1beta1.ProxySpec
370370
registrySettings *types.RegistrySettings
371+
isAirgap bool
371372
expected []*kotsv1beta2.HelmChart
372373
expectError bool
373374
}{
@@ -850,6 +851,136 @@ spec:
850851
repository: "proxy.replicated.com/external/path/nginx"
851852
imagePullSecrets:
852853
- name: ""
854+
`),
855+
},
856+
expectError: false,
857+
},
858+
{
859+
name: "helm chart with IsAirgap template function - airgap mode",
860+
isAirgap: true,
861+
helmChartCRs: [][]byte{
862+
[]byte(`
863+
apiVersion: kots.io/v1beta2
864+
kind: HelmChart
865+
metadata:
866+
name: airgap-chart
867+
namespace: default
868+
spec:
869+
chart:
870+
name: nginx
871+
chartVersion: "1.0.0"
872+
values:
873+
installationMode: '{{repl IsAirgap | ternary "airgap" "online"}}'
874+
downloadImages: '{{repl IsAirgap}}'
875+
environment:
876+
type: '{{repl if IsAirgap}}Airgap Installation{{repl else}}Online Installation{{repl end}}'
877+
optionalValues:
878+
- when: '{{repl IsAirgap}}'
879+
values:
880+
registry:
881+
enabled: true
882+
host: "local-registry.example.com"
883+
- when: '{{repl if not IsAirgap}}true{{repl else}}false{{repl end}}'
884+
values:
885+
externalAccess:
886+
enabled: true
887+
`),
888+
},
889+
configValues: types.AppConfigValues{},
890+
proxySpec: &ecv1beta1.ProxySpec{},
891+
registrySettings: &types.RegistrySettings{
892+
HasLocalRegistry: true,
893+
},
894+
expected: []*kotsv1beta2.HelmChart{
895+
createHelmChartCRFromYAML(`
896+
apiVersion: kots.io/v1beta2
897+
kind: HelmChart
898+
metadata:
899+
name: airgap-chart
900+
namespace: default
901+
spec:
902+
chart:
903+
name: nginx
904+
chartVersion: "1.0.0"
905+
values:
906+
installationMode: airgap
907+
downloadImages: "true"
908+
environment:
909+
type: Airgap Installation
910+
optionalValues:
911+
- when: "true"
912+
values:
913+
registry:
914+
enabled: true
915+
host: "local-registry.example.com"
916+
- when: "false"
917+
values:
918+
externalAccess:
919+
enabled: true
920+
`),
921+
},
922+
expectError: false,
923+
},
924+
{
925+
name: "helm chart with IsAirgap template function - online mode",
926+
isAirgap: false,
927+
helmChartCRs: [][]byte{
928+
[]byte(`
929+
apiVersion: kots.io/v1beta2
930+
kind: HelmChart
931+
metadata:
932+
name: online-chart
933+
namespace: default
934+
spec:
935+
chart:
936+
name: nginx
937+
chartVersion: "1.0.0"
938+
values:
939+
installationMode: '{{repl IsAirgap | ternary "airgap" "online"}}'
940+
downloadImages: '{{repl IsAirgap}}'
941+
environment:
942+
type: '{{repl if IsAirgap}}Airgap Installation{{repl else}}Online Installation{{repl end}}'
943+
optionalValues:
944+
- when: '{{repl IsAirgap}}'
945+
values:
946+
registry:
947+
enabled: true
948+
- when: '{{repl if not IsAirgap}}true{{repl else}}false{{repl end}}'
949+
values:
950+
externalAccess:
951+
enabled: true
952+
url: "https://external-api.example.com"
953+
`),
954+
},
955+
configValues: types.AppConfigValues{},
956+
proxySpec: &ecv1beta1.ProxySpec{},
957+
registrySettings: nil, // No registry settings means online mode
958+
expected: []*kotsv1beta2.HelmChart{
959+
createHelmChartCRFromYAML(`
960+
apiVersion: kots.io/v1beta2
961+
kind: HelmChart
962+
metadata:
963+
name: online-chart
964+
namespace: default
965+
spec:
966+
chart:
967+
name: nginx
968+
chartVersion: "1.0.0"
969+
values:
970+
installationMode: online
971+
downloadImages: "false"
972+
environment:
973+
type: Online Installation
974+
optionalValues:
975+
- when: "false"
976+
values:
977+
registry:
978+
enabled: true
979+
- when: "true"
980+
values:
981+
externalAccess:
982+
enabled: true
983+
url: "https://external-api.example.com"
853984
`),
854985
},
855986
expectError: false,
@@ -870,6 +1001,7 @@ spec:
8701001
manager, err := NewAppReleaseManager(
8711002
config,
8721003
WithReleaseData(releaseData),
1004+
WithIsAirgap(tt.isAirgap),
8731005
)
8741006
require.NoError(t, err)
8751007

api/pkg/template/airgap.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package template
2+
3+
// isAirgap returns true if this is an airgap installation
4+
func (e *Engine) isAirgap() bool {
5+
return e.isAirgapInstallation
6+
}

0 commit comments

Comments
 (0)