Skip to content

Commit 3ee08cf

Browse files
authored
Extract Charts tarballs and v1beta2 HelmChart custom resources (#2570)
1 parent efa9f93 commit 3ee08cf

File tree

4 files changed

+201
-2
lines changed

4 files changed

+201
-2
lines changed

api/pkg/template/engine_test.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,8 +1079,8 @@ repl{{ toJson $tls }}`),
10791079
assert.True(t, firstCachedDuration < time.Millisecond*20, "First cached execution should be under 20ms")
10801080

10811081
// Verify caching provides significant speedup
1082-
assert.True(t, firstCachedDuration < firstDuration/2,
1083-
"Cached execution should be at least 2x faster. First: %v, Cached: %v",
1082+
assert.True(t, firstCachedDuration < firstDuration/5,
1083+
"Cached execution should be at least 5x faster. First: %v, Cached: %v",
10841084
firstDuration, firstCachedDuration)
10851085

10861086
// Verify cached result is identical to first execution
@@ -1104,6 +1104,11 @@ repl{{ toJson $tls }}`),
11041104
assert.True(t, secondDuration > time.Millisecond*100, "Second execution should take at least 100ms (cert generation)")
11051105
assert.True(t, secondCachedDuration < time.Millisecond*20, "Second cached execution should be under 20ms")
11061106

1107+
// Verify caching provides significant speedup
1108+
assert.True(t, secondCachedDuration < secondDuration/5,
1109+
"Cached execution should be at least 5x faster. Second: %v, Cached: %v",
1110+
secondDuration, secondCachedDuration)
1111+
11071112
// Verify second cached result is identical to second execution
11081113
assert.Equal(t, secondResult, secondCachedResult, "Second cached execution should return identical result")
11091114

pkg/release/release.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ import (
77
"fmt"
88
"io"
99
"os"
10+
"strings"
1011

1112
ecv1beta1 "github.com/replicatedhq/embedded-cluster/kinds/apis/v1beta1"
1213
"github.com/replicatedhq/embedded-cluster/utils/pkg/embed"
1314
kotsv1beta1 "github.com/replicatedhq/kotskinds/apis/kots/v1beta1"
15+
kotsv1beta2 "github.com/replicatedhq/kotskinds/apis/kots/v1beta2"
1416
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
1517
velerov1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
1618
"gopkg.in/yaml.v2"
@@ -33,6 +35,8 @@ type ReleaseData struct {
3335
ChannelRelease *ChannelRelease
3436
VeleroBackup *velerov1.Backup
3537
VeleroRestore *velerov1.Restore
38+
HelmChartCRs []*kotsv1beta2.HelmChart
39+
HelmChartArchives [][]byte
3640
}
3741

3842
// GetReleaseData returns the release data.
@@ -93,6 +97,24 @@ func GetChannelRelease() *ChannelRelease {
9397
return _releaseData.ChannelRelease
9498
}
9599

100+
// GetHelmChartCRs reads and returns the HelmChart custom resources embedded as part of the release.
101+
// If no HelmChart CRs are found, returns an empty slice.
102+
func GetHelmChartCRs() []*kotsv1beta2.HelmChart {
103+
if _releaseData.HelmChartCRs == nil {
104+
return []*kotsv1beta2.HelmChart{}
105+
}
106+
return _releaseData.HelmChartCRs
107+
}
108+
109+
// GetHelmChartArchives reads and returns the Helm chart archives embedded as part of the release.
110+
// If no chart archives are found, returns an empty slice.
111+
func GetHelmChartArchives() [][]byte {
112+
if _releaseData.HelmChartArchives == nil {
113+
return [][]byte{}
114+
}
115+
return _releaseData.HelmChartArchives
116+
}
117+
96118
func init() {
97119
rd, err := parseReleaseDataFromBinary()
98120
if err != nil {
@@ -208,6 +230,17 @@ func parseVeleroRestore(data []byte) (*velerov1.Restore, error) {
208230
return &restore, nil
209231
}
210232

233+
func parseHelmChartCR(data []byte) (*kotsv1beta2.HelmChart, error) {
234+
if len(data) == 0 {
235+
return nil, nil
236+
}
237+
var helmChart kotsv1beta2.HelmChart
238+
if err := kyaml.Unmarshal(data, &helmChart); err != nil {
239+
return nil, fmt.Errorf("unable to unmarshal helm chart CR: %w", err)
240+
}
241+
return &helmChart, nil
242+
}
243+
211244
// ChannelRelease contains information about a specific app release inside a channel.
212245
type ChannelRelease struct {
213246
VersionLabel string `yaml:"versionLabel"`
@@ -324,11 +357,32 @@ func (r *ReleaseData) parse() error {
324357
}
325358
}
326359

360+
case bytes.Contains(content.Bytes(), []byte("apiVersion: kots.io/v1beta2")):
361+
if bytes.Contains(content.Bytes(), []byte("kind: HelmChart")) {
362+
helmChart, err := parseHelmChartCR(content.Bytes())
363+
if err != nil {
364+
return fmt.Errorf("failed to parse helm chart CR: %w", err)
365+
}
366+
if helmChart != nil {
367+
if r.HelmChartCRs == nil {
368+
r.HelmChartCRs = []*kotsv1beta2.HelmChart{}
369+
}
370+
r.HelmChartCRs = append(r.HelmChartCRs, helmChart)
371+
}
372+
}
373+
327374
case bytes.Contains(content.Bytes(), []byte("# channel release object")):
328375
r.ChannelRelease, err = parseChannelRelease(content.Bytes())
329376
if err != nil {
330377
return fmt.Errorf("failed to parse channel release: %w", err)
331378
}
379+
380+
case strings.HasSuffix(header.Name, ".tgz"):
381+
// This is a chart archive (.tgz file)
382+
if r.HelmChartArchives == nil {
383+
r.HelmChartArchives = [][]byte{}
384+
}
385+
r.HelmChartArchives = append(r.HelmChartArchives, content.Bytes())
332386
}
333387
}
334388
}

pkg/release/release_test.go

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,127 @@ func TestGetAppTitle(t *testing.T) {
6363
assert.Equal(t, "Embedded Cluster Smoke Test App", title)
6464
}
6565

66+
func TestGetHelmChartCRs(t *testing.T) {
67+
release, err := newReleaseDataFrom(testReleaseData)
68+
assert.NoError(t, err)
69+
helmCharts := release.HelmChartCRs
70+
assert.NoError(t, err)
71+
assert.NotNil(t, helmCharts)
72+
assert.Len(t, helmCharts, 1) // One HelmChart CR in test data
73+
}
74+
75+
func TestGetHelmChartArchives(t *testing.T) {
76+
release, err := newReleaseDataFrom(testReleaseData)
77+
assert.NoError(t, err)
78+
archives := release.HelmChartArchives
79+
assert.NoError(t, err)
80+
assert.NotNil(t, archives)
81+
assert.Len(t, archives, 1) // One .tgz file in test data
82+
}
83+
84+
func TestParseHelmChartCR(t *testing.T) {
85+
tests := []struct {
86+
name string
87+
data []byte
88+
wantErr bool
89+
wantNil bool
90+
}{
91+
{
92+
name: "empty data",
93+
data: []byte{},
94+
wantErr: false,
95+
wantNil: true,
96+
},
97+
{
98+
name: "valid helm chart CR",
99+
data: []byte(`apiVersion: kots.io/v1beta2
100+
kind: HelmChart
101+
metadata:
102+
name: test-chart
103+
spec:
104+
chart:
105+
chartVersion: "1.0.0"
106+
name: test-chart`),
107+
wantErr: false,
108+
wantNil: false,
109+
},
110+
{
111+
name: "invalid yaml",
112+
data: []byte(`invalid: yaml: content`),
113+
wantErr: true,
114+
wantNil: true,
115+
},
116+
}
117+
118+
for _, tt := range tests {
119+
t.Run(tt.name, func(t *testing.T) {
120+
result, err := parseHelmChartCR(tt.data)
121+
if tt.wantErr {
122+
assert.Error(t, err)
123+
} else {
124+
assert.NoError(t, err)
125+
}
126+
if tt.wantNil {
127+
assert.Nil(t, result)
128+
} else {
129+
assert.NotNil(t, result)
130+
}
131+
})
132+
}
133+
}
134+
135+
func TestParseWithHelmChartData(t *testing.T) {
136+
// Create test data with HelmChart CR and .tgz file
137+
helmChartYAML := `apiVersion: kots.io/v1beta2
138+
kind: HelmChart
139+
metadata:
140+
name: test-chart
141+
spec:
142+
chart:
143+
chartVersion: "1.0.0"
144+
name: test-chart`
145+
146+
chartArchive := []byte("fake-chart-archive-content")
147+
148+
testData := map[string][]byte{
149+
"helmchart.yaml": []byte(helmChartYAML),
150+
"test-chart-1.0.0.tgz": chartArchive,
151+
}
152+
153+
// Create tar.gz from test data
154+
buf := bytes.NewBuffer([]byte{})
155+
gw := gzip.NewWriter(buf)
156+
tw := tar.NewWriter(gw)
157+
158+
for name, content := range testData {
159+
err := tw.WriteHeader(&tar.Header{
160+
Name: name,
161+
Size: int64(len(content)),
162+
})
163+
assert.NoError(t, err)
164+
_, err = tw.Write(content)
165+
assert.NoError(t, err)
166+
}
167+
168+
err := tw.Close()
169+
assert.NoError(t, err)
170+
err = gw.Close()
171+
assert.NoError(t, err)
172+
173+
// Parse the test data
174+
release, err := newReleaseDataFrom(buf.Bytes())
175+
assert.NoError(t, err)
176+
assert.NotNil(t, release)
177+
178+
// Verify HelmChart CRs
179+
assert.Len(t, release.HelmChartCRs, 1)
180+
assert.NotNil(t, release.HelmChartCRs[0])
181+
182+
// Verify chart archives
183+
assert.Len(t, release.HelmChartArchives, 1)
184+
assert.Equal(t, chartArchive, release.HelmChartArchives[0])
185+
}
186+
66187
func generateReleaseTGZ() ([]byte, error) {
67188
content, err := os.ReadFile("testdata/release.yaml")
68189
if err != nil {

pkg/release/testdata/release.yaml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,22 @@ host-preflights.yaml: |-
6464
message: The filesystem at {{ .DataDir }} is more than 80% full. Ensure sufficient space is available, or use --data-dir to specify an alternative data directory.
6565
- pass:
6666
message: The filesystem at {{ .DataDir }} has sufficient space
67+
68+
helmchart.yaml: |-
69+
apiVersion: kots.io/v1beta2
70+
kind: HelmChart
71+
metadata:
72+
name: test-chart
73+
spec:
74+
chart:
75+
name: test-chart
76+
chartVersion: "1.0.0"
77+
namespace: test-namespace
78+
values:
79+
replicaCount: 1
80+
image:
81+
repository: nginx
82+
tag: "1.21"
83+
84+
test-chart-1.0.0.tgz: |-
85+
fake-chart-archive-content-for-testing

0 commit comments

Comments
 (0)