Skip to content

Commit d7d4668

Browse files
authored
Merge pull request #3840 from telepresenceio/thallgren/chart-global
The Telepresence Helm chart could not be used as a chart dependency
2 parents 4a93c96 + 90bc273 commit d7d4668

File tree

9 files changed

+228
-11
lines changed

9 files changed

+228
-11
lines changed

CHANGELOG.yml

+8
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ items:
2727
- version: 2.22.3
2828
date: (TBD)
2929
notes:
30+
- type: bugfix
31+
title: The Telepresence Helm chart could not be used as a dependency in another chart.
32+
body: >-
33+
The JSON schema validation implemented in Telepresence 2.22.0 had a defect: it rejected the `global` object.
34+
This object, a Helm-managed construct, facilitates the propagation of arbitrary configurations from a parent
35+
chart to its dependencies. Consequently, charts intended for dependency use must permit the presence of the
36+
`global` object.
37+
docs: https://github.com/telepresenceio/telepresence/issues/3833
3038
- type: bugfix
3139
title: Recreating namespaces was not possible when using a dynamically namespaced Traffic Manager
3240
body: >-

charts/telepresence-oss/values.schema.yaml

+4
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,10 @@ properties:
251251
items:
252252
$ref: "#/$defs/subject"
253253

254+
global:
255+
type: object
256+
additionalProperties: true
257+
254258
grpc:
255259
type: object
256260
additionalProperties: false

docs/release-notes.md

+6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22
[comment]: # (Code generated by relnotesgen. DO NOT EDIT.)
33
# <img src="images/logo.png" height="64px"/> Telepresence Release Notes
44
## Version 2.22.3
5+
## <div style="display:flex;"><img src="images/bugfix.png" alt="bugfix" style="width:30px;height:fit-content;"/><div style="display:flex;margin-left:7px;">[The Telepresence Helm chart could not be used as a dependency in another chart.](https://github.com/telepresenceio/telepresence/issues/3833)</div></div>
6+
<div style="margin-left: 15px">
7+
8+
The JSON schema validation implemented in Telepresence 2.22.0 had a defect: it rejected the `global` object. This object, a Helm-managed construct, facilitates the propagation of arbitrary configurations from a parent chart to its dependencies. Consequently, charts intended for dependency use must permit the presence of the `global` object.
9+
</div>
10+
511
## <div style="display:flex;"><img src="images/bugfix.png" alt="bugfix" style="width:30px;height:fit-content;"/><div style="display:flex;margin-left:7px;">[Recreating namespaces was not possible when using a dynamically namespaced Traffic Manager](https://github.com/telepresenceio/telepresence/issues/3831)</div></div>
612
<div style="margin-left: 15px">
713

docs/release-notes.mdx

+6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ import { Note, Title, Body } from '@site/src/components/ReleaseNotes'
88

99
# Telepresence Release Notes
1010
## Version 2.22.3
11+
<Note>
12+
<Title type="bugfix" docs="https://github.com/telepresenceio/telepresence/issues/3833">The Telepresence Helm chart could not be used as a dependency in another chart.</Title>
13+
<Body>
14+
The JSON schema validation implemented in Telepresence 2.22.0 had a defect: it rejected the `global` object. This object, a Helm-managed construct, facilitates the propagation of arbitrary configurations from a parent chart to its dependencies. Consequently, charts intended for dependency use must permit the presence of the `global` object.
15+
</Body>
16+
</Note>
1117
<Note>
1218
<Title type="bugfix" docs="https://github.com/telepresenceio/telepresence/issues/3831">Recreating namespaces was not possible when using a dynamically namespaced Traffic Manager</Title>
1319
<Body>

integration_test/install_test.go

+113
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
package integration_test
22

33
import (
4+
"archive/tar"
5+
"compress/gzip"
46
"context"
57
"fmt"
8+
"io"
69
"os"
710
"path/filepath"
11+
"runtime"
812
"strings"
913
"time"
1014

@@ -330,3 +334,112 @@ func ensureTrafficManager(ctx context.Context, kc *k8s.Cluster) error {
330334
k8s.GetManagerNamespace(ctx),
331335
&helm.Request{Type: helm.Install})
332336
}
337+
338+
func unTgz(ctx context.Context, srcTgz, dstPath string) error {
339+
rd, err := os.Open(srcTgz)
340+
if err != nil {
341+
return err
342+
}
343+
defer rd.Close()
344+
345+
err = dos.MkdirAll(ctx, dstPath, 0o755)
346+
if err != nil {
347+
return err
348+
}
349+
350+
zrd, err := gzip.NewReader(rd)
351+
if err != nil {
352+
return err
353+
}
354+
src := tar.NewReader(zrd)
355+
for {
356+
header, err := src.Next()
357+
if err != nil {
358+
if err == io.EOF {
359+
break
360+
}
361+
return err
362+
}
363+
364+
dst := dstPath + "/" + header.Name
365+
mode := os.FileMode(header.Mode)
366+
switch header.Typeflag {
367+
case tar.TypeDir:
368+
err = dos.MkdirAll(ctx, dst, mode)
369+
if err != nil {
370+
return err
371+
}
372+
case tar.TypeReg:
373+
err = dos.MkdirAll(ctx, filepath.Dir(dst), 0o755)
374+
if err != nil {
375+
return err
376+
}
377+
w, err := dos.OpenFile(ctx, dst, os.O_CREATE|os.O_WRONLY, mode)
378+
if err != nil {
379+
return err
380+
}
381+
_, err = io.Copy(w, src)
382+
_ = w.Close()
383+
if err != nil {
384+
return err
385+
}
386+
default:
387+
return fmt.Errorf("unable to untar type : %c in file %s", header.Typeflag, header.Name)
388+
}
389+
}
390+
return nil
391+
}
392+
393+
func (is *installSuite) Test_HelmSubChart() {
394+
if runtime.GOOS == "windows" || !(is.ManagerVersion().EQ(version.Structured) && is.ClientVersion().EQ(version.Structured)) {
395+
is.T().Skip("Not part of compatibility tests. Need forward slashes in path, and PackageHelmChart assumes current version.")
396+
}
397+
ctx := is.Context()
398+
require := is.Require()
399+
400+
t := is.T()
401+
subChart, err := is.PackageHelmChart(ctx)
402+
require.NoError(err)
403+
404+
base := t.TempDir()
405+
require.NoError(unTgz(ctx, subChart, filepath.Join(base, "charts")))
406+
407+
chart := fmt.Sprintf(`apiVersion: v2
408+
dependencies:
409+
- name: telepresence-oss
410+
registry: ../charts/telepresence-oss
411+
version: %s
412+
condition: enabled
413+
description: Helm chart to deploy telepresence
414+
name: parent
415+
version: 1.0.0`, is.ClientVersion())
416+
417+
vals := is.GetSetArgsForHelm(ctx, map[string]any{
418+
"global": map[string]any{
419+
"some-string": "value",
420+
"some-obj": map[string]any{
421+
"foo": "bar",
422+
},
423+
"some-bool": true,
424+
},
425+
"telepresence-oss": map[string]any{
426+
"clientRbac": map[string]any{
427+
"create": true,
428+
"subjects": []rbac.Subject{
429+
{
430+
Kind: "ServiceAccount",
431+
Name: itest.TestUser,
432+
Namespace: is.ManagerNamespace(),
433+
},
434+
},
435+
},
436+
},
437+
}, false)
438+
require.NoError(dos.WriteFile(ctx, filepath.Join(base, "Chart.yaml"), []byte(chart), 0o644))
439+
440+
vals = append([]string{"template", "parent", base, "-n", is.ManagerNamespace()}, vals...)
441+
so, err := itest.Output(ctx, "helm", vals...)
442+
require.NoError(err)
443+
require.Contains(so, "# Source: parent/charts/telepresence-oss/templates/clientRbac/connect.yaml")
444+
require.Contains(so, "name: "+itest.TestUser)
445+
}

integration_test/itest/cluster.go

+19-10
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,21 @@ func (s *cluster) Initialize(ctx context.Context) context.Context {
195195
s.agentVersion = s.managerVersion
196196
}
197197

198+
// We cannot use t.TempDir() here, because it will not mount correctly in
199+
// rancher-desktop and docker-desktop (unless they are configured to allow
200+
// mounts directly from /tmp). So we use a tempdir in BUILD_OUTPUT instead
201+
// because it's believed to be both mountable and writable.
202+
tempDir := dos.Getenv(ctx, "TELEPRESENCE_TEMP_DIR")
203+
if tempDir == "" {
204+
tempDir = filepath.Join(BuildOutput(ctx), "tmp")
205+
}
206+
_ = dos.RemoveAll(ctx, tempDir)
207+
require.NoError(t, dos.MkdirAll(ctx, tempDir, 0o777))
208+
ctx = withTempDirBase(ctx, &tempDirBase{tempDir: tempDir})
209+
t.Cleanup(func() {
210+
_ = os.RemoveAll(tempDir)
211+
})
212+
198213
registry := dos.Getenv(ctx, "TELEPRESENCE_REGISTRY")
199214
if registry == "" {
200215
registry = "ghcr.io/telepresenceio"
@@ -290,11 +305,8 @@ func (s *cluster) Initialize(ctx context.Context) context.Context {
290305

291306
s.ensureQuit(ctx)
292307
s.ensureNoManager(ctx)
293-
_ = Run(ctx, "kubectl", "delete", "ns", "-l", AssignPurposeLabel)
294308
_ = Run(ctx, "kubectl", "delete", "-f", filepath.Join("testdata", "k8s", "client_rbac.yaml"))
295-
_ = Run(ctx, "kubectl", "delete", "ns", "-l", AssignPurposeLabel)
296-
_ = Run(ctx, "kubectl", "delete", "pv", "-l", AssignPurposeLabel)
297-
_ = Run(ctx, "kubectl", "delete", "storageclass", "-l", AssignPurposeLabel)
309+
_ = Run(ctx, "kubectl", "delete", "all", "-l", AssignPurposeLabel)
298310
return ctx
299311
}
300312

@@ -354,10 +366,7 @@ func (s *cluster) tearDown(ctx context.Context) {
354366
if s.kubeConfig != "" {
355367
ctx = WithWorkingDir(ctx, GetOSSRoot(ctx))
356368
_ = Run(ctx, "kubectl", "delete", "-f", filepath.Join("testdata", "k8s", "client_rbac.yaml"))
357-
_ = Run(ctx, "kubectl", "delete", "--wait=false", "ns", "-l", AssignPurposeLabel)
358-
_ = Run(ctx, "kubectl", "delete", "--wait=false", "pv", "-l", AssignPurposeLabel)
359-
_ = Run(ctx, "kubectl", "delete", "--wait=false", "storageclass", "-l", AssignPurposeLabel)
360-
_ = Run(ctx, "kubectl", "delete", "--wait=false", "mutatingwebhookconfigurations", "-l", AssignPurposeLabel)
369+
_ = Run(ctx, "kubectl", "delete", "--wait=false", "all", "-l", AssignPurposeLabel)
361370
}
362371
}
363372

@@ -439,7 +448,7 @@ func (s *cluster) withBasicConfig(c context.Context, t *testing.T) context.Conte
439448
require.NoError(t, err)
440449
configYamlStr := string(configYaml)
441450

442-
configDir := t.TempDir()
451+
configDir := TempDir(c)
443452
c = filelocation.WithAppUserConfigDir(c, configDir)
444453
c, err = SetConfig(c, configDir, configYamlStr)
445454
require.NoError(t, err)
@@ -1071,7 +1080,7 @@ func WithConfig(c context.Context, modifierFunc func(config client.Config)) cont
10711080
configYaml, err := configCopy.(client.Config).MarshalYAML()
10721081
require.NoError(t, err)
10731082
configYamlStr := string(configYaml)
1074-
configDir, err := os.MkdirTemp(t.TempDir(), "config")
1083+
configDir, err := os.MkdirTemp(TempDir(c), "config")
10751084
require.NoError(t, err)
10761085
c, err = SetConfig(c, configDir, configYamlStr)
10771086
require.NoError(t, err)

integration_test/itest/namespace.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,14 @@ func (s *nsPair) setup(ctx context.Context) bool {
103103
return false
104104
}
105105
err := Kubectl(ctx, s.Namespace, "apply", "-f", filepath.Join(GetOSSRoot(ctx), "testdata", "k8s", "client_sa.yaml"))
106-
assert.NoError(t, err, "failed to create connect ServiceAccount")
106+
if assert.NoError(t, err, "failed to create connect ServiceAccount") {
107+
db, err := ReadTemplate(ctx, filepath.Join("testdata", "k8s", "client_rancher.goyaml"), map[string]string{
108+
"ManagerNamespace": s.Namespace,
109+
})
110+
if assert.NoError(t, err) {
111+
assert.NoError(t, Kubectl(dos.WithStdin(ctx, bytes.NewReader(db)), s.Namespace, "apply", "-f", "-"))
112+
}
113+
}
107114
return !t.Failed()
108115
}
109116

integration_test/itest/tempdir.go

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package itest
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"os"
7+
"sync/atomic"
8+
9+
"github.com/stretchr/testify/require"
10+
)
11+
12+
type tempDirBase struct {
13+
tempDir string
14+
tempDirSeq uint64
15+
}
16+
17+
type tempDirBaseKey struct{}
18+
19+
func withTempDirBase(ctx context.Context, td *tempDirBase) context.Context {
20+
return context.WithValue(ctx, tempDirBaseKey{}, td)
21+
}
22+
23+
// TempDir returns a temporary directory for the test to use.
24+
// The directory is automatically removed when the test and
25+
// all its subtests complete.
26+
// Each subsequent call to t.TempDir returns a unique directory;
27+
// if the directory creation fails, TempDir terminates the test by calling Fatal.
28+
func TempDir(ctx context.Context) string {
29+
t := getT(ctx)
30+
if td, ok := ctx.Value(tempDirBaseKey{}).(*tempDirBase); ok {
31+
seq := atomic.AddUint64(&td.tempDirSeq, 1)
32+
dir := fmt.Sprintf("%s%c%03d", td.tempDir, os.PathSeparator, seq)
33+
require.NoError(t, os.Mkdir(dir, 0o777))
34+
return dir
35+
}
36+
return t.TempDir()
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
kind: ClusterRole
3+
apiVersion: rbac.authorization.k8s.io/v1
4+
metadata:
5+
name: rancher-inspect
6+
labels:
7+
purpose: tp-cli-testing
8+
rules:
9+
- apiGroups: [""]
10+
resources: ["nodes"]
11+
verbs: ["get", "list"]
12+
13+
---
14+
apiVersion: rbac.authorization.k8s.io/v1
15+
kind: ClusterRoleBinding
16+
metadata:
17+
name: rancher-inspect
18+
labels:
19+
purpose: tp-cli-testing
20+
subjects:
21+
- kind: ServiceAccount
22+
name: telepresence-test-developer
23+
namespace: {{ .ManagerNamespace }}
24+
roleRef:
25+
apiGroup: rbac.authorization.k8s.io
26+
name: rancher-inspect
27+
kind: ClusterRole

0 commit comments

Comments
 (0)