From a09b97a0fc1f759563b3f4879bf3ff36dcb06148 Mon Sep 17 00:00:00 2001 From: Michael Bridgen Date: Tue, 16 Oct 2018 11:35:53 +0100 Subject: [PATCH 1/4] Add repositories.yaml to helm-operator image We want to be able to update the dependencies of a Helm chart. Helm (whether the client library or the command-line tool) makes it difficult to do this without also having other equipment, notably the repositories.yaml file which records aliases and possibly credentials for Helm repos (e.g., "stable"). This commit adds a default repositories.yaml file to the image, containing just the conventional location of "stable". --- Makefile | 2 +- docker/Dockerfile.helm-operator | 3 +++ docker/helm-repositories.yaml | 11 +++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 docker/helm-repositories.yaml diff --git a/Makefile b/Makefile index 88d6ebf4a..55529ae96 100644 --- a/Makefile +++ b/Makefile @@ -49,7 +49,7 @@ build/.%.done: docker/Dockerfile.% touch $@ build/.flux.done: build/fluxd build/kubectl docker/ssh_config docker/kubeconfig docker/verify_known_hosts.sh -build/.helm-operator.done: build/helm-operator build/kubectl docker/ssh_config docker/verify_known_hosts.sh +build/.helm-operator.done: build/helm-operator build/kubectl docker/ssh_config docker/verify_known_hosts.sh docker/helm-repositories.yaml build/fluxd: $(FLUXD_DEPS) build/fluxd: cmd/fluxd/*.go diff --git a/docker/Dockerfile.helm-operator b/docker/Dockerfile.helm-operator index 7bbde9902..a14b86879 100644 --- a/docker/Dockerfile.helm-operator +++ b/docker/Dockerfile.helm-operator @@ -32,6 +32,9 @@ LABEL maintainer="Weaveworks " \ ENTRYPOINT [ "/sbin/tini", "--", "helm-operator" ] +ENV HELM_HOME=/var/fluxd/helm +COPY ./helm-repositories.yaml /var/fluxd/helm/repository/repositories.yaml + COPY ./helm-operator /usr/local/bin/ ARG BUILD_DATE diff --git a/docker/helm-repositories.yaml b/docker/helm-repositories.yaml new file mode 100644 index 000000000..3b99db533 --- /dev/null +++ b/docker/helm-repositories.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +generated: 2018-10-16T11:13:32.846851484+01:00 +repositories: +- caFile: "" + cache: /var/fluxd/helm/repository/cache/stable-index.yaml + certFile: "" + keyFile: "" + name: stable + password: "" + url: https://kubernetes-charts.storage.googleapis.com + username: "" From 34b2e99b7ba5af18a7e00623789a771bae2410b7 Mon Sep 17 00:00:00 2001 From: Michael Bridgen Date: Wed, 26 Sep 2018 18:01:46 +0100 Subject: [PATCH 2/4] Add the helm binary to the helm-op image This makes trouble-shooting a bit easier, since you can exec into the container and have a look around with `helm`. --- Makefile | 17 ++++++++++++++++- docker/Dockerfile.helm-operator | 2 ++ docker/helm.version | 4 ++++ 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 docker/helm.version diff --git a/Makefile b/Makefile index 55529ae96..a8fed8872 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,7 @@ SUDO := $(shell docker info > /dev/null 2> /dev/null || echo "sudo") TEST_FLAGS?= include docker/kubectl.version +include docker/helm.version # NB because this outputs absolute file names, you have to be careful # if you're testing out the Makefile with `-W` (pretend a file is @@ -49,7 +50,7 @@ build/.%.done: docker/Dockerfile.% touch $@ build/.flux.done: build/fluxd build/kubectl docker/ssh_config docker/kubeconfig docker/verify_known_hosts.sh -build/.helm-operator.done: build/helm-operator build/kubectl docker/ssh_config docker/verify_known_hosts.sh docker/helm-repositories.yaml +build/.helm-operator.done: build/helm-operator build/kubectl build/helm docker/ssh_config docker/verify_known_hosts.sh docker/helm-repositories.yaml build/fluxd: $(FLUXD_DEPS) build/fluxd: cmd/fluxd/*.go @@ -64,9 +65,23 @@ build/kubectl: cache/kubectl-$(KUBECTL_VERSION) docker/kubectl.version strip $@ chmod a+x $@ +build/helm: cache/helm-$(HELM_VERSION) docker/helm.version + cp cache/helm-$(HELM_VERSION) $@ + strip $@ + chmod a+x $@ + cache/kubectl-$(KUBECTL_VERSION): mkdir -p cache curl -L -o $@ "https://storage.googleapis.com/kubernetes-release/release/$(KUBECTL_VERSION)/bin/linux/amd64/kubectl" + +cache/helm-$(HELM_VERSION): + mkdir -p cache + curl -L -o ./cache/helm-$(HELM_VERSION).tar.gz "https://storage.googleapis.com/kubernetes-helm/helm-v$(HELM_VERSION)-linux-amd64.tar.gz" + echo "$(HELM_CHECKSUM) ./cache/helm-$(HELM_VERSION).tar.gz" > ./cache/helm-$(HELM_VERSION).checksum + sha256sum -c ./cache/helm-$(HELM_VERSION).checksum + tar -C ./cache -xzf ./cache/helm-$(HELM_VERSION).tar.gz linux-amd64/helm + mv ./cache/linux-amd64/helm $@ + $(GOPATH)/bin/fluxctl: $(FLUXCTL_DEPS) $(GOPATH)/bin/fluxctl: ./cmd/fluxctl/*.go go install ./cmd/fluxctl diff --git a/docker/Dockerfile.helm-operator b/docker/Dockerfile.helm-operator index a14b86879..46cd905c3 100644 --- a/docker/Dockerfile.helm-operator +++ b/docker/Dockerfile.helm-operator @@ -15,6 +15,8 @@ ADD ./verify_known_hosts.sh /home/flux/verify_known_hosts.sh RUN sh /home/flux/verify_known_hosts.sh /etc/ssh/ssh_known_hosts && rm /home/flux/verify_known_hosts.sh COPY ./kubectl /usr/local/bin/ +# The Helm client is included as a convenience for troubleshooting +COPY ./helm /usr/local/bin/ # These are pretty static LABEL maintainer="Weaveworks " \ diff --git a/docker/helm.version b/docker/helm.version new file mode 100644 index 000000000..66b766061 --- /dev/null +++ b/docker/helm.version @@ -0,0 +1,4 @@ +# NB Helm clients will refuse to play with Tiller that is older. 2.8.2 +# is the first release that had checksums, so it's used. +HELM_VERSION=2.8.2 +HELM_CHECKSUM=614b5ac79de4336b37c9b26d528c6f2b94ee6ccacb94b0f4b8d9583a8dd122d3 From 60fc2a9ca75b8f75e154fe1f814e6bb6ec5090e5 Mon Sep 17 00:00:00 2001 From: Michael Bridgen Date: Tue, 16 Oct 2018 14:34:05 +0100 Subject: [PATCH 3/4] Run `helm dep build` with every release The easiest thing to do is use the Helm binary; since there's no communication with Tiller involved, there are fewer compatibility pitfalls (possibly none). --- cmd/helm-operator/main.go | 3 ++ docker/Dockerfile.helm-operator | 1 + docker/helm-repositories.yaml | 1 - integrations/helm/release/deps.go | 46 ++++++++++++++++++++++++++++ integrations/helm/release/release.go | 8 +++++ 5 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 integrations/helm/release/deps.go diff --git a/cmd/helm-operator/main.go b/cmd/helm-operator/main.go index da4443be7..aee1745b5 100644 --- a/cmd/helm-operator/main.go +++ b/cmd/helm-operator/main.go @@ -51,6 +51,7 @@ var ( chartsSyncInterval *time.Duration chartsSyncTimeout *time.Duration logReleaseDiffs *bool + updateDependencies *bool gitURL *string gitBranch *string @@ -103,6 +104,7 @@ func init() { chartsSyncInterval = fs.Duration("charts-sync-interval", 3*time.Minute, "Interval at which to check for changed charts") chartsSyncTimeout = fs.Duration("charts-sync-timeout", 1*time.Minute, "Timeout when checking for changed charts") logReleaseDiffs = fs.Bool("log-release-diffs", false, "Log the diff when a chart release diverges; potentially insecure") + updateDependencies = fs.Bool("update-chart-deps", true, "Update chart dependencies before installing/upgrading a release") gitURL = fs.String("git-url", "", "URL of git repo with Helm Charts; e.g., git@github.com:weaveworks/flux-example") gitBranch = fs.String("git-branch", "master", "branch of git repo") @@ -214,6 +216,7 @@ func main() { releaseConfig := release.Config{ ChartsPath: *gitChartsPath, + UpdateDeps: *updateDependencies, } repoConfig := helmop.RepoConfig{ Repo: repo, diff --git a/docker/Dockerfile.helm-operator b/docker/Dockerfile.helm-operator index 46cd905c3..c9bcf595e 100644 --- a/docker/Dockerfile.helm-operator +++ b/docker/Dockerfile.helm-operator @@ -36,6 +36,7 @@ ENTRYPOINT [ "/sbin/tini", "--", "helm-operator" ] ENV HELM_HOME=/var/fluxd/helm COPY ./helm-repositories.yaml /var/fluxd/helm/repository/repositories.yaml +RUN mkdir -p /var/fluxd/helm/repository/cache/ COPY ./helm-operator /usr/local/bin/ diff --git a/docker/helm-repositories.yaml b/docker/helm-repositories.yaml index 3b99db533..d3ddc7e42 100644 --- a/docker/helm-repositories.yaml +++ b/docker/helm-repositories.yaml @@ -1,5 +1,4 @@ apiVersion: v1 -generated: 2018-10-16T11:13:32.846851484+01:00 repositories: - caFile: "" cache: /var/fluxd/helm/repository/cache/stable-index.yaml diff --git a/integrations/helm/release/deps.go b/integrations/helm/release/deps.go new file mode 100644 index 000000000..2e018afbb --- /dev/null +++ b/integrations/helm/release/deps.go @@ -0,0 +1,46 @@ +package release + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" +) + +func updateDependencies(chartDir string) error { + var hasLockFile bool + + // We are going to use `helm dep build`, which tries to update the + // dependencies in charts/ by looking at the file + // `requirements.lock` in the chart directory. If the lockfile + // does not match what is specified in requirements.yaml, it will + // error out. + // + // If that file doesn't exist, `helm dep build` will fall back on + // `helm dep update`, which populates the charts/ directory _and_ + // creates the lockfile. So that it will have the same behaviour + // the next time it attempts a release, remove the lockfile if it + // was created by helm. + lockfilePath := filepath.Join(chartDir, "requirements.lock") + info, err := os.Stat(lockfilePath) + hasLockFile = (err == nil && !info.IsDir()) + if !hasLockFile { + defer os.Remove(lockfilePath) + } + + cmd := exec.Command("helm", "repo", "update") + out, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("could not update repo: %s", string(out)) + } + + cmd = exec.Command("helm", "dep", "build", ".") + cmd.Dir = chartDir + + out, err = cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("could not update dependencies in %s: %s", chartDir, string(out)) + } + + return nil +} diff --git a/integrations/helm/release/release.go b/integrations/helm/release/release.go index 9e59e5bb5..9d6eb93ec 100644 --- a/integrations/helm/release/release.go +++ b/integrations/helm/release/release.go @@ -30,6 +30,7 @@ const ( type Config struct { ChartsPath string + UpdateDeps bool } // Release contains clients needed to provide functionality related to helm releases @@ -147,6 +148,13 @@ func (r *Release) Install(repoDir, releaseName string, fhr ifv1.FluxHelmRelease, chartDir := filepath.Join(repoDir, r.config.ChartsPath, chartPath) + if r.config.UpdateDeps { + if err := updateDependencies(chartDir); err != nil { + r.logger.Log("error", "problem updating dependencies of chart", "releaseName", releaseName, "dir", chartDir, "err", err) + return nil, err + } + } + strVals, err := fhr.Spec.Values.YAML() if err != nil { r.logger.Log("error", fmt.Sprintf("Problem with supplied customizations for Chart release [%s]: %#v", releaseName, err)) From 4f2fbd02daae28e8400897978c321cc99f3333c8 Mon Sep 17 00:00:00 2001 From: Michael Bridgen Date: Wed, 17 Oct 2018 16:26:42 +0100 Subject: [PATCH 4/4] Update version of bundled helm client Apparently 2.8.2 didn't support authentication for chart repos; 2.9.1 does. --- docker/helm.version | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docker/helm.version b/docker/helm.version index 66b766061..428e8a1a5 100644 --- a/docker/helm.version +++ b/docker/helm.version @@ -1,4 +1,6 @@ # NB Helm clients will refuse to play with Tiller that is older. 2.8.2 -# is the first release that had checksums, so it's used. -HELM_VERSION=2.8.2 -HELM_CHECKSUM=614b5ac79de4336b37c9b26d528c6f2b94ee6ccacb94b0f4b8d9583a8dd122d3 +# is the first release that had checksums; but 2.9.1 appears the first +# that reliably supports authenticating against chart repos, so that +# wins. +HELM_VERSION=2.9.1 +HELM_CHECKSUM=56ae2d5d08c68d6e7400d462d6ed10c929effac929fedce18d2636a9b4e166ba