Skip to content

Commit 0601b43

Browse files
authored
allow a vendor to specify additional helm charts (#287)
* install vendor-specified charts upon initial install * install 'memcached' helmchart * avoid import cycle * test logging * ??? * metadata command... * expand version command to include vendor charts also test metadata command * installer version not expected as chart * correct lists * remove debug * imports
1 parent 4a11481 commit 0601b43

File tree

9 files changed

+139
-9
lines changed

9 files changed

+139
-9
lines changed

cmd/embedded-cluster/version.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010

1111
k0sconfig "github.com/k0sproject/k0s/pkg/apis/k0s/v1beta1"
1212
"github.com/replicatedhq/embedded-cluster/pkg/addons"
13+
"github.com/replicatedhq/embedded-cluster/pkg/config"
1314
"github.com/replicatedhq/embedded-cluster/pkg/defaults"
1415
"github.com/replicatedhq/embedded-cluster/pkg/goods"
1516
)
@@ -20,7 +21,7 @@ var versionCommand = &cli.Command{
2021
Subcommands: []*cli.Command{metadataCommand},
2122
Action: func(c *cli.Context) error {
2223
opts := []addons.Option{addons.Quiet(), addons.WithoutPrompt()}
23-
versions, err := addons.NewApplier(opts...).Versions()
24+
versions, err := addons.NewApplier(opts...).Versions(config.AdditionalCharts())
2425
if err != nil {
2526
return fmt.Errorf("unable to get versions: %w", err)
2627
}
@@ -55,7 +56,7 @@ var metadataCommand = &cli.Command{
5556
Hidden: true,
5657
Action: func(c *cli.Context) error {
5758
opts := []addons.Option{addons.Quiet(), addons.WithoutPrompt(), addons.OnlyDefaults()}
58-
versions, err := addons.NewApplier(opts...).Versions()
59+
versions, err := addons.NewApplier(opts...).Versions(config.AdditionalCharts())
5960
if err != nil {
6061
return fmt.Errorf("unable to get versions: %w", err)
6162
}
@@ -71,7 +72,7 @@ var metadataCommand = &cli.Command{
7172
K0sBinaryURL: defaults.K0sBinaryURL,
7273
}
7374
applier := addons.NewApplier(opts...)
74-
chtconfig, repconfig, err := applier.GenerateHelmConfigs()
75+
chtconfig, repconfig, err := applier.GenerateHelmConfigs(config.AdditionalCharts(), config.AdditionalRepositories())
7576
if err != nil {
7677
return fmt.Errorf("unable to apply addons: %w", err)
7778
}

e2e/install_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ func TestSingleNodeInstallation(t *testing.T) {
2828
}
2929
t.Log("installing embedded-cluster on node 0")
3030
line := []string{"single-node-install.sh"}
31-
if _, _, err := RunCommandOnNode(t, tc, 0, line); err != nil {
31+
if stdout, stderr, err := RunCommandOnNode(t, tc, 0, line); err != nil {
32+
t.Log("install stdout:", stdout)
33+
t.Log("install stderr:", stderr)
3234
t.Fatalf("fail to install embedded-cluster on node %s: %v", tc.Nodes[0], err)
3335
}
3436
t.Log("installing puppeteer on node 0")

e2e/kots-release/config.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,11 @@ spec:
2424
spec:
2525
telemetry:
2626
enabled: false
27+
extensions:
28+
helm:
29+
charts:
30+
- chartname: oci://registry-1.docker.io/bitnamicharts/memcached
31+
name: memcached-vendor-chart
32+
namespace: memcached
33+
order: 4
34+
version: 6.6.2

e2e/scripts/single-node-install.sh

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,22 @@ ensure_node_config() {
5858
fi
5959
}
6060

61+
wait_for_memcached_pods() {
62+
ready=$(kubectl get pods -n memcached | grep -c memcached || true)
63+
counter=0
64+
while [ "$ready" -lt "1" ]; do
65+
if [ "$counter" -gt 36 ]; then
66+
return 1
67+
fi
68+
sleep 5
69+
counter=$((counter+1))
70+
echo "Waiting for memcached pods"
71+
ready=$(kubectl get pods -n memcached | grep -c memcached || true)
72+
kubectl get pods -n memcached 2>&1 || true
73+
echo "$ready"
74+
done
75+
}
76+
6177
main() {
6278
if ! embedded-cluster install --no-prompt 2>&1 | tee /tmp/log ; then
6379
cat /etc/os-release
@@ -80,6 +96,10 @@ main() {
8096
echo "Failed to install embedded-cluster"
8197
exit 1
8298
fi
99+
if ! wait_for_memcached_pods; then
100+
echo "Failed waiting for memcached pods"
101+
exit 1
102+
fi
83103
if ! systemctl restart embedded-cluster; then
84104
echo "Failed to restart embedded-cluster service"
85105
exit 1

e2e/version_test.go

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package e2e
22

33
import (
4+
"encoding/json"
45
"fmt"
56
"strings"
67
"testing"
78

9+
k0sconfig "github.com/k0sproject/k0s/pkg/apis/k0s/v1beta1"
810
"github.com/replicatedhq/embedded-cluster/e2e/cluster"
911
)
1012

@@ -27,7 +29,7 @@ func TestVersion(t *testing.T) {
2729
}
2830
var failed bool
2931
output := fmt.Sprintf("%s\n%s", stdout, stderr)
30-
expected := []string{"Installer", "Kubernetes", "OpenEBS", "AdminConsole"}
32+
expected := []string{"Installer", "Kubernetes", "OpenEBS", "AdminConsole", "EmbeddedClusterOperator", "memcached-vendor-chart"}
3133
for _, component := range expected {
3234
if strings.Contains(output, component) {
3335
continue
@@ -37,5 +39,46 @@ func TestVersion(t *testing.T) {
3739
}
3840
if failed {
3941
t.Log(output)
42+
return
43+
}
44+
45+
line2 := []string{"embedded-cluster", "version", "metadata"}
46+
stdout, stderr, err = RunCommandOnNode(t, tc, 0, line2)
47+
if err != nil {
48+
t.Fatalf("fail to run metadata command on node %s: %v", tc.Nodes[0], err)
49+
}
50+
51+
output = fmt.Sprintf("%s\n%s", stdout, stderr)
52+
parsed := struct {
53+
Configs k0sconfig.HelmExtensions
54+
}{}
55+
if err := json.Unmarshal([]byte(output), &parsed); err != nil {
56+
t.Log(output)
57+
t.Fatalf("fail to parse metadata output: %v", err)
58+
}
59+
60+
expectedCharts := []string{"openebs", "embedded-cluster-operator", "admin-console", "memcached-vendor-chart"}
61+
if len(parsed.Configs.Charts) != len(expectedCharts) {
62+
t.Log(output)
63+
t.Fatalf("found %d charts in metadata, expected %d", len(parsed.Configs.Charts), len(expectedCharts))
64+
}
65+
66+
for _, expectedName := range expectedCharts {
67+
foundName := false
68+
for _, foundChart := range parsed.Configs.Charts {
69+
if foundChart.Name == expectedName {
70+
foundName = true
71+
break
72+
}
73+
}
74+
if !foundName {
75+
t.Errorf("failed to find chart %s in 'metadata' output", expectedName)
76+
failed = true
77+
}
78+
}
79+
80+
if failed {
81+
t.Log(output)
82+
return
4083
}
4184
}

go.mod

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ require (
1313
github.com/k0sproject/dig v0.2.0
1414
github.com/k0sproject/k0sctl v0.17.4
1515
github.com/k0sproject/rig v0.17.3
16-
github.com/replicatedhq/embedded-cluster-operator v0.16.0
16+
github.com/replicatedhq/embedded-cluster-operator v0.20.0
1717
github.com/replicatedhq/kotskinds v0.0.0-20230724164735-f83482cc9cfe
1818
github.com/replicatedhq/troubleshoot v0.79.1
1919
github.com/sirupsen/logrus v1.9.3
@@ -29,17 +29,26 @@ require (
2929
)
3030

3131
require (
32+
github.com/beorn7/perks v1.0.1 // indirect
3233
github.com/bodgit/ntlmssp v0.0.0-20231224131242-ee0981b06f47 // indirect
3334
github.com/bodgit/windows v1.0.1 // indirect
35+
github.com/cespare/xxhash/v2 v2.2.0 // indirect
3436
github.com/containerd/containerd v1.7.11 // indirect
3537
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
3638
github.com/frankban/quicktest v1.14.5 // indirect
39+
github.com/fsnotify/fsnotify v1.7.0 // indirect
40+
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
41+
github.com/google/go-cmp v0.6.0 // indirect
3742
github.com/google/pprof v0.0.0-20230323073829-e72429f035bd // indirect
3843
github.com/gorilla/mux v1.8.1 // indirect
3944
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
4045
github.com/jellydator/validation v1.1.0 // indirect
4146
github.com/mattn/go-shellwords v1.0.12 // indirect
47+
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
48+
github.com/ohler55/ojg v1.21.0 // indirect
4249
github.com/opencontainers/go-digest v1.0.0 // indirect
50+
github.com/prometheus/client_golang v1.17.0 // indirect
51+
github.com/prometheus/client_model v0.5.0 // indirect
4352
github.com/prometheus/common v0.45.0 // indirect
4453
github.com/rs/cors v1.10.1 // indirect
4554
github.com/tidwall/transform v0.0.0-20201103190739-32f242e2dbde // indirect
@@ -49,7 +58,9 @@ require (
4958
go.uber.org/goleak v1.3.0 // indirect
5059
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect
5160
golang.org/x/mod v0.14.0 // indirect
61+
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
5262
helm.sh/helm/v3 v3.13.3 // indirect
63+
k8s.io/component-base v0.29.0 // indirect
5364
)
5465

5566
require (

go.sum

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRx
113113
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
114114
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
115115
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
116+
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
117+
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
116118
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
117119
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
118120
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -275,6 +277,8 @@ github.com/muhlemmer/gu v0.3.1/go.mod h1:YHtHR+gxM+bKEIIs7Hmi9sPT3ZDUvTN/i88wQpZ
275277
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
276278
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
277279
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
280+
github.com/ohler55/ojg v1.21.0 h1:niqSS6yl3PQZJrqh7pKs/zinl4HebGe8urXEfpvlpYY=
281+
github.com/ohler55/ojg v1.21.0/go.mod h1:gQhDVpQLqrmnd2eqGAvJtn+NfKoYJbe/A4Sj3/Vro4o=
278282
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
279283
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
280284
github.com/onsi/ginkgo/v2 v2.13.2 h1:Bi2gGVkfn6gQcjNjZJVO8Gf0FHzMPf2phUei9tejVMs=
@@ -307,6 +311,8 @@ github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k
307311
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
308312
github.com/replicatedhq/embedded-cluster-operator v0.16.0 h1:keyj4l49FWaZT6WOcRU8Q9YBcLaH6UHN1FQKT0qq/Zw=
309313
github.com/replicatedhq/embedded-cluster-operator v0.16.0/go.mod h1:Gd099feJhkz/O8uxmPn0AS7r+VoBdX8jrv6CUbGggvw=
314+
github.com/replicatedhq/embedded-cluster-operator v0.20.0 h1:s9tlPeeOn6faj76bmW5PuMndj/uvUhrS/07iaGqIC0Q=
315+
github.com/replicatedhq/embedded-cluster-operator v0.20.0/go.mod h1:qkCOGMKxiCzSkqM+3IWACbAB/32G0V67HYreJ5iaa30=
310316
github.com/replicatedhq/kotskinds v0.0.0-20230724164735-f83482cc9cfe h1:3AJInd06UxzqHmgy8+24CPsT2tYSE0zToJZyuX9q+MA=
311317
github.com/replicatedhq/kotskinds v0.0.0-20230724164735-f83482cc9cfe/go.mod h1:QjhIUu3+OmHZ09u09j3FCoTt8F3BYtQglS+OLmftu9I=
312318
github.com/replicatedhq/troubleshoot v0.79.1 h1:BBsYA53w+vq0DJe2CrlqBdQESzgWWsqCGRBJ4aTzzZ0=
@@ -551,6 +557,8 @@ k8s.io/apimachinery v0.29.0 h1:+ACVktwyicPz0oc6MTMLwa2Pw3ouLAfAon1wPLtG48o=
551557
k8s.io/apimachinery v0.29.0/go.mod h1:eVBxQ/cwiJxH58eK/jd/vAk4mrxmVlnpBH5J2GbMeis=
552558
k8s.io/client-go v0.29.0 h1:KmlDtFcrdUzOYrBhXHgKw5ycWzc3ryPX5mQe0SkG3y8=
553559
k8s.io/client-go v0.29.0/go.mod h1:yLkXH4HKMAywcrD82KMSmfYg2DlE8mepPR4JGSo5n38=
560+
k8s.io/component-base v0.29.0 h1:T7rjd5wvLnPBV1vC4zWd/iWRbV8Mdxs+nGaoaFzGw3s=
561+
k8s.io/component-base v0.29.0/go.mod h1:sADonFTQ9Zc9yFLghpDpmNXEdHyQmFIGbiuZbqAXQ1M=
554562
k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0=
555563
k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo=
556564
k8s.io/kube-openapi v0.0.0-20231113174909-778a5567bc1e h1:snPmy96t93RredGRjKfMFt+gvxuVAncqSAyBveJtr4Q=

pkg/addons/applier.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,15 @@ func (a *Applier) Outro(ctx context.Context) error {
6262
}
6363

6464
// GenerateHelmConfigs generates the helm config for all the embedded charts.
65-
func (a *Applier) GenerateHelmConfigs() ([]v1beta1.Chart, []v1beta1.Repository, error) {
65+
func (a *Applier) GenerateHelmConfigs(additionalCharts []v1beta1.Chart, additionalRepositories []v1beta1.Repository) ([]v1beta1.Chart, []v1beta1.Repository, error) {
6666
charts := []v1beta1.Chart{}
6767
repositories := []v1beta1.Repository{}
6868
addons, err := a.load()
6969
if err != nil {
7070
return nil, nil, fmt.Errorf("unable to load addons: %w", err)
7171
}
72+
73+
// charts required by embedded-cluster
7274
for _, addon := range addons {
7375
addonChartConfig, addonRepositoryConfig, err := addon.GenerateHelmConfig(a.onlyDefaults)
7476
if err != nil {
@@ -77,6 +79,11 @@ func (a *Applier) GenerateHelmConfigs() ([]v1beta1.Chart, []v1beta1.Repository,
7779
charts = append(charts, addonChartConfig...)
7880
repositories = append(repositories, addonRepositoryConfig...)
7981
}
82+
83+
// charts required by the application
84+
charts = append(charts, additionalCharts...)
85+
repositories = append(repositories, additionalRepositories...)
86+
8087
return charts, repositories, nil
8188
}
8289

@@ -144,7 +151,7 @@ func (a *Applier) load() (map[string]AddOn, error) {
144151
}
145152

146153
// Versions returns a map with the version of each addon that will be applied.
147-
func (a *Applier) Versions() (map[string]string, error) {
154+
func (a *Applier) Versions(additionalCharts []v1beta1.Chart) (map[string]string, error) {
148155
addons, err := a.load()
149156
if err != nil {
150157
return nil, fmt.Errorf("unable to load addons: %w", err)
@@ -159,6 +166,10 @@ func (a *Applier) Versions() (map[string]string, error) {
159166
versions[k] = v
160167
}
161168
}
169+
for _, chart := range additionalCharts {
170+
versions[chart.Name] = chart.Version
171+
}
172+
162173
return versions, nil
163174
}
164175

pkg/config/config.go

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ func UpdateHelmConfigs(cfg *v1beta1.Cluster, opts ...addons.Option) error {
281281
return fmt.Errorf("unable to unmarshal k0s config: %w", err)
282282
}
283283
opts = append(opts, addons.WithConfig(k0s))
284-
chtconfig, repconfig, err := addons.NewApplier(opts...).GenerateHelmConfigs()
284+
chtconfig, repconfig, err := addons.NewApplier(opts...).GenerateHelmConfigs(AdditionalCharts(), AdditionalRepositories())
285285
if err != nil {
286286
return fmt.Errorf("unable to apply addons: %w", err)
287287
}
@@ -390,3 +390,29 @@ func additionalControllerLabels() map[string]string {
390390
}
391391
return map[string]string{}
392392
}
393+
394+
func AdditionalCharts() []k0sconfig.Chart {
395+
clusterConfig, err := embed.GetEmbeddedClusterConfig()
396+
397+
if err == nil {
398+
if clusterConfig != nil {
399+
if clusterConfig.Spec.Extensions.Helm != nil {
400+
return clusterConfig.Spec.Extensions.Helm.Charts
401+
}
402+
}
403+
}
404+
return []k0sconfig.Chart{}
405+
}
406+
407+
func AdditionalRepositories() []k0sconfig.Repository {
408+
clusterConfig, err := embed.GetEmbeddedClusterConfig()
409+
410+
if err == nil {
411+
if clusterConfig != nil {
412+
if clusterConfig.Spec.Extensions.Helm != nil {
413+
return clusterConfig.Spec.Extensions.Helm.Repositories
414+
}
415+
}
416+
}
417+
return []k0sconfig.Repository{}
418+
}

0 commit comments

Comments
 (0)