Skip to content

Commit

Permalink
Implements DependencyUpdate for helm charts
Browse files Browse the repository at this point in the history
A new flag `disableDependencyUpdate` is added to the `fleet.yaml`
file in order to disable the feature, which is active by default.

A new package `helmupdater` is added to implement the dependencies
update.
The implementation is based on helm's when ussing the
`--dependency-update` flag in the install command.

Dependencies are applied to the bundle (upstream) to they're resolved
already when applying downstream.

Refers to: #1672

Signed-off-by: Xavi Garcia <[email protected]>
  • Loading branch information
0xavi0 committed Feb 9, 2024
1 parent 9da3f28 commit 331ccd3
Show file tree
Hide file tree
Showing 46 changed files with 867 additions and 12 deletions.
10 changes: 7 additions & 3 deletions .github/workflows/e2e-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,17 @@ jobs:
e2e/testenv/infra/infra setup --helm-registry=true
ginkgo --label-filter='helm-registry' e2e/single-cluster
e2e/testenv/infra/infra teardown --helm-registry=true
# 4. Run tests requiring a Helm registry and the git server
e2e/testenv/infra/infra setup --git-server=true
ginkgo --label-filter='infra-setup && helm-registry && !oci-registry' e2e/single-cluster/
e2e/testenv/infra/infra teardown --helm-registry=true --git-server=true
# 4. Run tests requiring an OCI registry
# 5. Run tests requiring an OCI registry
e2e/testenv/infra/infra setup --oci-registry=true
ginkgo --label-filter='oci-registry' e2e/single-cluster
# 5. Tear down all infra
# 6. Tear down all infra
e2e/testenv/infra/infra teardown
-
Expand Down
16 changes: 16 additions & 0 deletions charts/fleet-crd/templates/crds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,10 @@ spec:
description: DisableDNS can be used to customize Helm's
EnableDNS option, which Fleet sets to `true` by default.
type: boolean
disableDependencyUpdate:
description: DisableDependencyUpdate allows skipping chart
dependencies update
type: boolean
disablePreProcess:
description: DisablePreProcess disables template processing
in values
Expand Down Expand Up @@ -547,6 +551,10 @@ spec:
description: DisableDNS can be used to customize Helm's
EnableDNS option, which Fleet sets to `true` by default.
type: boolean
disableDependencyUpdate:
description: DisableDependencyUpdate allows skipping chart
dependencies update
type: boolean
disablePreProcess:
description: DisablePreProcess disables template processing
in values
Expand Down Expand Up @@ -1239,6 +1247,10 @@ spec:
description: DisableDNS can be used to customize Helm's EnableDNS
option, which Fleet sets to `true` by default.
type: boolean
disableDependencyUpdate:
description: DisableDependencyUpdate allows skipping chart dependencies
update
type: boolean
disablePreProcess:
description: DisablePreProcess disables template processing
in values
Expand Down Expand Up @@ -1934,6 +1946,10 @@ spec:
description: DisableDNS can be used to customize Helm's
EnableDNS option, which Fleet sets to `true` by default.
type: boolean
disableDependencyUpdate:
description: DisableDependencyUpdate allows skipping chart
dependencies update
type: boolean
disablePreProcess:
description: DisablePreProcess disables template processing
in values
Expand Down
11 changes: 11 additions & 0 deletions e2e/assets/deps-charts/gitrepo.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
kind: GitRepo
apiVersion: fleet.cattle.io/v1alpha1
metadata:
name: {{.Name}}
spec:
repo: {{.Repo}}
branch: {{.Branch}}
helmSecretName: "helm-secret"
targetNamespace: {{.TargetNamespace}}
paths:
- examples
10 changes: 10 additions & 0 deletions e2e/assets/deps-charts/no-fleet-yaml/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
apiVersion: v2
appVersion: 1.16.0
description: A chart for testing dependencies
name: deps-chart
type: application
version: 1.0.0
dependencies:
- name: sleeper-chart
version: "0.1.0"
repository: {{.HelmRepoUrl}}
7 changes: 7 additions & 0 deletions e2e/assets/deps-charts/no-fleet-yaml/templates/configmap.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: test-simple-deps-chart
data:
test: "valuedeps"
name: {{ .Values.name }}
1 change: 1 addition & 0 deletions e2e/assets/deps-charts/no-fleet-yaml/values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
name: deps-default-name
10 changes: 10 additions & 0 deletions e2e/assets/deps-charts/with-fleet-yaml/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
apiVersion: v2
appVersion: 1.16.0
description: A chart for testing dependencies
name: deps-chart
type: application
version: 1.0.0
dependencies:
- name: sleeper-chart
version: "0.1.0"
repository: {{.HelmRepoUrl}}
8 changes: 8 additions & 0 deletions e2e/assets/deps-charts/with-fleet-yaml/fleet.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace: {{.TestNamespace}}
helm:
releaseName: simple-with-fleet-yaml
chart: ""
repo: ""
version: ""
disableDependencyUpdate: {{.DisableDependencyUpdate}}

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: test-simple-deps-chart
data:
test: "valuedeps"
name: {{ .Values.name }}
1 change: 1 addition & 0 deletions e2e/assets/deps-charts/with-fleet-yaml/values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
name: deps-default-name
161 changes: 161 additions & 0 deletions e2e/single-cluster/helm_dependencies_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
package singlecluster_test

import (
"fmt"
"math/rand"
"os"
"path"
"path/filepath"
"strings"

"github.com/rancher/fleet/e2e/testenv"
"github.com/rancher/fleet/e2e/testenv/githelper"
"github.com/rancher/fleet/e2e/testenv/kubectl"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
cp "github.com/otiai10/copy"
)

func getChartMuseumExternalAddr(env *testenv.Env) string {
os.Getenv("GIT_HTTP_USER")
username := os.Getenv("GIT_HTTP_USER")
passwd := os.Getenv("GIT_HTTP_PASSWORD")
Expect(username).ToNot(Equal(""))
Expect(passwd).ToNot(Equal(""))
return fmt.Sprintf("https://%s:%s@chartmuseum-service.%s.svc.cluster.local:8081", username, passwd, env.Namespace)
}

func setupChartDepsInTmpDir(chartDir string, tmpDir string, namespace string, disableDependencyUpdate bool, env *testenv.Env) {
err := cp.Copy(chartDir, tmpDir)
Expect(err).ToNot(HaveOccurred())
// replace the helm repo url
helmRepoUrl := getChartMuseumExternalAddr(env)
out := filepath.Join(tmpDir, "Chart.yaml")
in := filepath.Join(chartDir, "Chart.yaml")
err = testenv.Template(out, in, struct {
HelmRepoUrl string
}{
helmRepoUrl,
})
Expect(err).ToNot(HaveOccurred())

if _, err = os.Stat(filepath.Join(chartDir, "fleet.yaml")); !os.IsNotExist(err) {
out = filepath.Join(tmpDir, "fleet.yaml")
in = filepath.Join(chartDir, "fleet.yaml")
err = testenv.Template(out, in, struct {
TestNamespace string
DisableDependencyUpdate bool
}{
namespace,
disableDependencyUpdate,
})
Expect(err).ToNot(HaveOccurred())
}
}

var _ = Describe("Helm dependency update tests", Label("infra-setup", "helm-registry"), func() {
var (
asset string
k kubectl.Command
gh *githelper.Git
clonedir string
inClusterRepoURL string
tmpDir string
gitrepoName string
r = rand.New(rand.NewSource(GinkgoRandomSeed()))
namespace string
disableDependencyUpdate bool
)

JustBeforeEach(func() {
k = env.Kubectl.Namespace(env.Namespace)
// Build git repo URL reachable _within_ the cluster, for the GitRepo
host, err := githelper.BuildGitHostname(env.Namespace)
Expect(err).ToNot(HaveOccurred())

addr, err := githelper.GetExternalRepoAddr(env, port, repoName)
Expect(err).ToNot(HaveOccurred())
gh = githelper.NewHTTP(addr)

inClusterRepoURL = gh.GetInClusterURL(host, port, repoName)

tmpDir, _ = os.MkdirTemp("", "fleet-")
clonedir = path.Join(tmpDir, repoName)

gitrepoName = testenv.RandomFilename("gitrepo-test", r)

// setup the tmp chart dir.
// we use a tmp dir because dependencies are downloaded to the directory
tmpChart := GinkgoT().TempDir()
setupChartDepsInTmpDir(testenv.AssetPath(asset), tmpChart, namespace, disableDependencyUpdate, env)

_, err = gh.Create(clonedir, tmpChart, "examples")
Expect(err).ToNot(HaveOccurred())

err = testenv.ApplyTemplate(k, testenv.AssetPath("deps-charts/gitrepo.yaml"), struct {
Name string
Repo string
Branch string
TargetNamespace string
}{
gitrepoName,
inClusterRepoURL,
gh.Branch,
namespace, // to avoid conflicts with other tests
})
Expect(err).ToNot(HaveOccurred())
})

AfterEach(func() {
out, err := k.Delete("gitrepo", gitrepoName)
Expect(err).ToNot(HaveOccurred(), out)
out, err = k.Delete("ns", namespace)
Expect(err).ToNot(HaveOccurred(), out)
})

When("applying a gitrepo resource", func() {
Context("containing a helm chart with dependencies and no fleet.yaml", func() {
BeforeEach(func() {
namespace = "no-fleet-yaml"
asset = "deps-charts/" + namespace
disableDependencyUpdate = false
})
It("deploys the chart plus its dependencies", func() {
Eventually(func() bool {
outConfigMaps, _ := k.Namespace(namespace).Get("configmaps")
outPods, _ := k.Namespace(namespace).Get("pods")
return strings.Contains(outConfigMaps, "test-simple-deps-chart") && strings.Contains(outPods, "sleeper-")
}).Should(BeTrue())
})
})
Context("containing a helm chart with dependencies and fleet.yaml with disableDependencyUpdate=false", func() {
BeforeEach(func() {
namespace = "with-fleet-yaml"
asset = "deps-charts/" + namespace
disableDependencyUpdate = false
})
It("deploys the chart plus its dependencies", func() {
Eventually(func() bool {
outConfigMaps, _ := k.Namespace(namespace).Get("configmaps")
outPods, _ := k.Namespace(namespace).Get("pods")
return strings.Contains(outConfigMaps, "test-simple-deps-chart") && strings.Contains(outPods, "sleeper-")
}).Should(BeTrue())
})
})
Context("containing a helm chart with dependencies and fleet.yaml with disableDependencyUpdate=true", func() {
BeforeEach(func() {
namespace = "with-fleet-yaml"
asset = "deps-charts/" + namespace
disableDependencyUpdate = true
})
It("deploys the chart, but not its dependencies", func() {
Eventually(func() bool {
outConfigMaps, _ := k.Namespace(namespace).Get("configmaps")
outPods, _ := k.Namespace(namespace).Get("pods")
return strings.Contains(outConfigMaps, "test-simple-deps-chart") && !strings.Contains(outPods, "sleeper-")
}).Should(BeTrue())
})
})
})
})
Loading

0 comments on commit 331ccd3

Please sign in to comment.