├── tools ├── generate-package-map.sh ├── lint.sh ├── lintfix.sh ├── buildifier.sh ├── BUILD └── buildifier.bzl ├── helm ├── BUILD └── helm.bzl ├── .cache-linux └── .gitignore ├── .gitignore ├── .dummy_test.sh ├── helm.BUILD ├── dockerfiles └── Dockerfile ├── docs ├── BUILD └── docs.md ├── BUILD ├── WORKSPACE ├── runfiles.bash ├── repos.bzl ├── helm.sh ├── Makefile └── README.md /tools/generate-package-map.sh: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /helm/BUILD: -------------------------------------------------------------------------------- 1 | exports_files(["helm.bzl"]) 2 | -------------------------------------------------------------------------------- /.cache-linux/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bazel-* 2 | .tags 3 | .tags.lock 4 | .tags.temp 5 | -------------------------------------------------------------------------------- /.dummy_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | echo "ok" 5 | -------------------------------------------------------------------------------- /tools/lint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | ./tools/buildifier -mode=check "$(find "${BUILD_WORKSPACE_DIRECTORY}" -name BUILD -or -name BUILD.bazel )" 3 | -------------------------------------------------------------------------------- /tools/lintfix.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | ./tools/buildifier -mode=fix "$(find "${BUILD_WORKSPACE_DIRECTORY}" -name BUILD -or -name BUILD.bazel -or -name *.bzl )" 3 | -------------------------------------------------------------------------------- /helm.BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | filegroup( 4 | name = "allfiles", 5 | srcs = glob([ 6 | "**/*", 7 | ]), 8 | ) 9 | -------------------------------------------------------------------------------- /dockerfiles/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:bionic 2 | 3 | RUN apt-get update # Last Modified: 2018-12-08 4 | RUN apt-get install -y build-essential 5 | RUN apt-get install -y curl unzip git 6 | ENV PATH=/root/bin/:$PATH 7 | 8 | WORKDIR /app 9 | -------------------------------------------------------------------------------- /tools/buildifier.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | platform=$(uname) 4 | if [ "$platform" == "Darwin" ]; then 5 | BINARY=external/buildifier_osx/file/downloaded 6 | elif [ "$platform" == "Linux" ]; then 7 | BINARY=external/buildifier/file/downloaded 8 | else 9 | echo "Buildifier does not have a binary for $platform" 10 | exit 1 11 | fi 12 | 13 | $BINARY $* 14 | -------------------------------------------------------------------------------- /tools/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | sh_binary( 4 | name = "buildifier", 5 | srcs = ["buildifier.sh"], 6 | data = [ 7 | "@buildifier//file", 8 | "@buildifier_osx//file", 9 | ], 10 | ) 11 | 12 | sh_binary( 13 | name = "lint", 14 | srcs = ["lint.sh"], 15 | data = [ 16 | ":buildifier", 17 | ], 18 | ) 19 | 20 | sh_binary( 21 | name = "lintfix", 22 | srcs = ["lintfix.sh"], 23 | data = [ 24 | ":buildifier", 25 | ], 26 | ) 27 | -------------------------------------------------------------------------------- /docs/BUILD: -------------------------------------------------------------------------------- 1 | load("@io_bazel_skydoc//stardoc:stardoc.bzl", "stardoc") 2 | load("@bazel_skylib//:bzl_library.bzl", "bzl_library") 3 | 4 | package(default_visibility = ["//visibility:public"]) 5 | 6 | load("@bazel_tools//tools/build_defs/pkg:pkg.bzl", "pkg_tar") 7 | 8 | bzl_library( 9 | name = "skylib_paths", 10 | srcs = ["@bazel_skylib//lib:paths.bzl"], 11 | ) 12 | 13 | stardoc( 14 | name = "docs", 15 | out = "docs.md", 16 | input = "//helm:helm.bzl", 17 | deps = [ 18 | ":skylib_paths", 19 | ], 20 | ) 21 | -------------------------------------------------------------------------------- /BUILD: -------------------------------------------------------------------------------- 1 | sh_binary( 2 | name = "helm", 3 | srcs = ["helm.sh"], 4 | data = [ 5 | "@helm_tiller//:allfiles", 6 | ] + select({ 7 | "@bazel_tools//src/conditions:linux_x86_64": ["@helm//:allfiles"], 8 | "@bazel_tools//src/conditions:darwin": ["@helm_osx//:allfiles"], 9 | }), 10 | visibility = ["//visibility:public"], 11 | deps = ["@bazel_tools//tools/bash/runfiles"], 12 | ) 13 | 14 | sh_library( 15 | name = "runfiles_bash", 16 | srcs = ["runfiles.bash"], 17 | visibility = ["//visibility:public"], 18 | ) 19 | 20 | sh_test( 21 | name = "dummy_test", 22 | size = "small", 23 | srcs = [ 24 | ".dummy_test.sh", 25 | ], 26 | ) 27 | -------------------------------------------------------------------------------- /tools/buildifier.bzl: -------------------------------------------------------------------------------- 1 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_file") 2 | 3 | def buildifier_repositories(): 4 | http_file( 5 | name = "buildifier", 6 | executable = True, 7 | sha256 = "25159de982ec8896fc8213499df0a7003dfb4a03dd861f90fa5679d16faf0f99", 8 | urls = ["https://github.com/bazelbuild/buildtools/releases/download/0.22.0/buildifier"], 9 | ) 10 | 11 | http_file( 12 | name = "buildifier_osx", 13 | executable = True, 14 | sha256 = "ceeedbd3ae0479dc2a5161e17adf7eccaba146b650b07063976df58bc37d7c44", 15 | urls = ["https://github.com/bazelbuild/buildtools/releases/download/0.22.0/buildifier.osx"], 16 | ) 17 | -------------------------------------------------------------------------------- /WORKSPACE: -------------------------------------------------------------------------------- 1 | workspace(name = "com_github_tmc_rules_helm") 2 | 3 | load(":repos.bzl", "helm_repositories") 4 | 5 | helm_repositories() 6 | 7 | load("//tools:buildifier.bzl", "buildifier_repositories") 8 | buildifier_repositories() 9 | 10 | # Start stardoc rules 11 | load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") 12 | git_repository( 13 | name = "io_bazel_skydoc", 14 | remote = "https://github.com/bazelbuild/skydoc.git", 15 | tag = "0.3.0", 16 | ) 17 | load("@io_bazel_skydoc//:setup.bzl", "skydoc_repositories") 18 | skydoc_repositories() 19 | load("@io_bazel_rules_sass//:package.bzl", "rules_sass_dependencies") 20 | rules_sass_dependencies() 21 | load("@build_bazel_rules_nodejs//:defs.bzl", "node_repositories") 22 | node_repositories() 23 | load("@io_bazel_rules_sass//:defs.bzl", "sass_repositories") 24 | sass_repositories() 25 | # End stardoc rules 26 | -------------------------------------------------------------------------------- /runfiles.bash: -------------------------------------------------------------------------------- 1 | # --- begin runfiles.bash initialization --- 2 | # Copy-pasted from Bazel's Bash runfiles library (tools/bash/runfiles/runfiles.bash). 3 | set -euo pipefail 4 | if [[ ! -d "${RUNFILES_DIR:-/dev/null}" && ! -f "${RUNFILES_MANIFEST_FILE:-/dev/null}" ]]; then 5 | if [[ -f "$0.runfiles_manifest" ]]; then 6 | export RUNFILES_MANIFEST_FILE="$0.runfiles_manifest" 7 | elif [[ -f "$0.runfiles/MANIFEST" ]]; then 8 | export RUNFILES_MANIFEST_FILE="$0.runfiles/MANIFEST" 9 | elif [[ -f "$0.runfiles/bazel_tools/tools/bash/runfiles/runfiles.bash" ]]; then 10 | export RUNFILES_DIR="$0.runfiles" 11 | fi 12 | fi 13 | if [[ -f "${RUNFILES_DIR:-/dev/null}/bazel_tools/tools/bash/runfiles/runfiles.bash" ]]; then 14 | source "${RUNFILES_DIR}/bazel_tools/tools/bash/runfiles/runfiles.bash" 15 | elif [[ -f "${RUNFILES_MANIFEST_FILE:-/dev/null}" ]]; then 16 | source "$(grep -m1 "^bazel_tools/tools/bash/runfiles/runfiles.bash " \ 17 | "$RUNFILES_MANIFEST_FILE" | cut -d ' ' -f 2-)" 18 | else 19 | echo >&2 "ERROR: cannot find @bazel_tools//tools/bash/runfiles:runfiles.bash" 20 | exit 1 21 | fi 22 | # --- end runfiles.bash initialization --- 23 | -------------------------------------------------------------------------------- /repos.bzl: -------------------------------------------------------------------------------- 1 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive", "http_file") 2 | load("@bazel_tools//tools/build_defs/repo:git.bzl", "new_git_repository") 3 | 4 | def helm_repositories(): 5 | skylib_version = "0.8.0" 6 | http_archive( 7 | name = "bazel_skylib", 8 | type = "tar.gz", 9 | url = "https://github.com/bazelbuild/bazel-skylib/releases/download/{}/bazel-skylib.{}.tar.gz".format(skylib_version, skylib_version), 10 | sha256 = "2ef429f5d7ce7111263289644d233707dba35e39696377ebab8b0bc701f7818e", 11 | ) 12 | 13 | http_archive( 14 | name = "helm", 15 | sha256 = "804f745e6884435ef1343f4de8940f9db64f935cd9a55ad3d9153d064b7f5896", 16 | urls = ["https://storage.googleapis.com/kubernetes-helm/helm-v2.14.1-linux-amd64.tar.gz"], 17 | build_file = "@com_github_tmc_rules_helm//:helm.BUILD", 18 | ) 19 | 20 | http_archive( 21 | name = "helm_osx", 22 | sha256 = "392ec847ecc5870a48a39cb0b8d13c8aa72aaf4365e0315c4d7a2553019a451c", 23 | urls = ["https://storage.googleapis.com/kubernetes-helm/helm-v2.14.1-darwin-amd64.tar.gz"], 24 | build_file = "@com_github_tmc_rules_helm//:helm.BUILD", 25 | ) 26 | 27 | new_git_repository( 28 | name = "helm_tiller", 29 | remote = "https://github.com/rimusz/helm-tiller", 30 | commit = "a77f505e062d8337e8fd638796bfecc8a4a00bcc", 31 | shallow_since = "1553679518 +0000", 32 | build_file = "@com_github_tmc_rules_helm//:helm.BUILD", 33 | ) 34 | -------------------------------------------------------------------------------- /helm.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | # --- begin runfiles.bash initialization --- 5 | # Copy-pasted from Bazel's Bash runfiles library (tools/bash/runfiles/runfiles.bash). 6 | set -euo pipefail 7 | if [[ ! -d "${RUNFILES_DIR:-/dev/null}" && ! -f "${RUNFILES_MANIFEST_FILE:-/dev/null}" ]]; then 8 | if [[ -f "$0.runfiles_manifest" ]]; then 9 | export RUNFILES_MANIFEST_FILE="$0.runfiles_manifest" 10 | elif [[ -f "$0.runfiles/MANIFEST" ]]; then 11 | export RUNFILES_MANIFEST_FILE="$0.runfiles/MANIFEST" 12 | elif [[ -f "$0.runfiles/bazel_tools/tools/bash/runfiles/runfiles.bash" ]]; then 13 | export RUNFILES_DIR="$0.runfiles" 14 | fi 15 | fi 16 | if [[ -f "${RUNFILES_DIR:-/dev/null}/bazel_tools/tools/bash/runfiles/runfiles.bash" ]]; then 17 | source "${RUNFILES_DIR}/bazel_tools/tools/bash/runfiles/runfiles.bash" 18 | elif [[ -f "${RUNFILES_MANIFEST_FILE:-/dev/null}" ]]; then 19 | source "$(grep -m1 "^bazel_tools/tools/bash/runfiles/runfiles.bash " \ 20 | "$RUNFILES_MANIFEST_FILE" | cut -d ' ' -f 2-)" 21 | else 22 | echo >&2 "ERROR: cannot find @bazel_tools//tools/bash/runfiles:runfiles.bash" 23 | exit 1 24 | fi 25 | # --- end runfiles.bash initialization --- 26 | #export RUNFILES_LIB_DEBUG=1 27 | 28 | platform=$(uname) 29 | if [ "$platform" == "Darwin" ]; then 30 | BINARY=$(rlocation helm_osx/darwin-amd64/helm) 31 | elif [ "$platform" == "Linux" ]; then 32 | BINARY=$(rlocation helm/linux-amd64/helm) 33 | else 34 | echo "Helm does not have a binary for $platform" 35 | exit 1 36 | fi 37 | 38 | export HELM_HOME="$(pwd)/.helm" 39 | export PATH="$(dirname $BINARY):$PATH" 40 | #export HELM_TILLER_SILENT=true 41 | helm init --client-only >/dev/null 42 | # Remove local repo to increase reproducibility and remove errors 43 | helm repo list |grep -qc local && $BINARY repo remove local >/dev/null 44 | 45 | helm plugin list | grep -qc tiller || $BINARY plugin install $(dirname $(rlocation __main__/external/helm_tiller/WORKSPACE)) 46 | 47 | cd "${BUILD_WORKING_DIRECTORY:-}" 48 | helm $* 49 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # This non-hermetic Makefile installs core dependencies such as bazel 2 | 3 | UNAME ?= $(shell uname -s) 4 | BAZEL ?= $(shell which bazel) 5 | CACHEDIR ?= .cache 6 | IMAGE ?= $(shell basename $(shell pwd)) 7 | 8 | .PHONY: all 9 | all: docs ci 10 | 11 | .PHONY: docs 12 | docs: deps 13 | bazel build //docs && cp bazel-bin/docs/docs.md docs 14 | @chmod +w docs/docs.md 15 | 16 | .PHONY: deps 17 | ifeq ($(UNAME),Darwin) 18 | deps: deps-darwin 19 | endif 20 | ifeq ($(UNAME),Linux) 21 | deps: deps-linux 22 | endif 23 | 24 | .PHONY: deps-common 25 | deps-common: deps-bazel 26 | 27 | .PHONY: deps-darwin 28 | deps-darwin: deps-common 29 | 30 | .PHONY: deps-linux 31 | deps-linux: deps-common 32 | sudo apt-get install -y build-essential curl unzip 33 | 34 | 35 | .PHONY: deps-bazel 36 | ifeq "$(BAZEL)" "" 37 | # default to bazel24 38 | deps-bazel: deps-bazel24 39 | else 40 | deps-bazel: 41 | @echo '[deps-bazel] Bazel already present.' 42 | endif 43 | 44 | .PHONY: ci 45 | ci: build test 46 | 47 | .PHONY: build 48 | build: 49 | bazel build //... 50 | 51 | .PHONY: test 52 | test: 53 | bazel test //... 54 | 55 | .PHONY: lint 56 | lint: 57 | bazel run //tools:lint 58 | 59 | .PHONY: lintfix 60 | lintfix: 61 | bazel run //tools:lintfix 62 | 63 | .PHONY: linux-ci-image 64 | linux-ci-image: dockerfiles/Dockerfile 65 | docker build -t ${IMAGE} -f dockerfiles/Dockerfile . 66 | 67 | .PHONY: linux-ci-from-host 68 | linux-ci-from-host: linux-ci-image 69 | docker run \ 70 | -v $(shell pwd):/app \ 71 | -e CACHEDIR=.cache-linux \ 72 | -ti ${IMAGE} make deps ci 73 | 74 | .PHONY: linux-ci-from-host-shell 75 | linux-ci-from-host-shell: linux-ci-image 76 | docker run \ 77 | -v $(shell pwd):/app \ 78 | -e CACHEDIR=.cache-linux \ 79 | -ti ${IMAGE} bash 80 | 81 | # requires https://github.com/buildkite/cli 82 | .PHONY: mac-ci-from-host 83 | mac-ci-from-host: 84 | bk run local 85 | 86 | # requires https://circleci.com/docs/2.0/local-cli 87 | .PHONY: circle-ci-from-host 88 | circle-ci-from-host: 89 | bk run local 90 | 91 | .PHONY: deps-bazel24 92 | deps-bazel24: ${CACHEDIR}/bazel-installer-24.sh 93 | $^ --user 94 | 95 | ${CACHEDIR}/bazel-installer-24.sh: 96 | ifeq ($(UNAME),Darwin) 97 | curl -L -o $@ https://github.com/bazelbuild/bazel/releases/download/0.24.0/bazel-0.24.0-installer-darwin-x86_64.sh 98 | chmod +x $@ 99 | endif 100 | ifeq ($(UNAME),Linux) 101 | curl -L -o $@ https://github.com/bazelbuild/bazel/releases/download/0.24.0/bazel-0.24.0-installer-linux-x86_64.sh 102 | chmod +x $@ 103 | endif 104 | 105 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rules_helm 2 | 3 | This repository contains Bazel rules to install and manipulate Helm charts with Bazel. 4 | 5 | This allows you to describe Kubernetes applications in a deterministic manner. 6 | 7 | ## Features 8 | 9 | * Tillerless - rules_helm uses [tillerless helm](https://rimusz.net/tillerless-helm/). 10 | 11 | ## Documentation 12 | 13 | * See [Rule and macro defintions](./docs/docs.md) for macro documentation. 14 | 15 | ### API 16 | 17 | * helm_chart - describes a helm chart. 18 | * helm_release - describes a helm release. 19 | 20 | ### Getting started 21 | 22 | In your Bazel `WORKSPACE` file add this repository as a dependency: 23 | 24 | ``` 25 | git_repository( 26 | name = "com_github_tmc_rules_helm", 27 | tag = "0.4.0", 28 | remote = "https://github.com/tmc/rules_helm.git", 29 | ) 30 | ``` 31 | 32 | Then in your `BUILD` files include the `helm_chart` and/or `helm_release` rules: 33 | 34 | `charts/a-great-chart/zBUILD`: 35 | ```python 36 | load("@com_github_tmc_rules_helm//:helm.bzl", "helm_chart") 37 | 38 | package(default_visibility = ["//visibility:public"]) 39 | 40 | helm_chart( 41 | name = "a_great_chart", 42 | srcs = glob(["**"]), 43 | ) 44 | ``` 45 | 46 | Referencing the chart with helm_release: 47 | 48 | `BUILD`: 49 | ```python 50 | load("@com_github_tmc_rules_helm//:helm.bzl", "helm_release") 51 | 52 | helm_release( 53 | name = "a_great_release", 54 | chart = "//charts/a-great-chart:chart", 55 | release_name = "a-great-release-1", 56 | values_yaml = "//:a-great-release-values.yaml", 57 | ) 58 | ``` 59 | 60 | This defines targets you can now use to manage the release: 61 | ``` 62 | :a_great_release.test.noclean 63 | :a_great_release.test 64 | :a_great_release.status 65 | :a_great_release.install.wait 66 | :a_great_release.install 67 | :a_great_release.delete 68 | ``` 69 | 70 | You could now install, test, and clean up the chart via: 71 | `bazel run :a_great_release.install.wait && bazel run :a_great_release.test && bazel run :a_great_release.delete` 72 | 73 | See [rules_helm_examples](https://github.com/tmc/rules_helm_example) for detailed usage examples. 74 | 75 | ### Istio Example 76 | 77 | These rules demonstrae describing an installation of Istio. See 78 | https://github.com/tmc/rules_helm_example/tree/master/charts/istio for details. 79 | 80 | ```python 81 | load("@com_github_tmc_rules_helm//:helm.bzl", "helm_release") 82 | 83 | package(default_visibility = ["//visibility:public"]) 84 | 85 | helm_release( 86 | name = "istio_init", 87 | chart = "@com_github_istio_istio//:istio_init", 88 | namespace = "istio-system", 89 | release_name = "istio-init", 90 | values_yaml = ":istio_values.yaml", 91 | ) 92 | 93 | helm_release( 94 | name = "istio", 95 | chart = "@com_github_istio_istio//:istio", 96 | namespace = "istio-system", 97 | release_name = "istio", 98 | values_yaml = ":istio_values.yaml", 99 | ) 100 | ``` 101 | 102 | The releases above create the following targets: 103 | ``` 104 | :istio_init.test.noclean 105 | :istio_init.test 106 | :istio_init.status 107 | :istio_init.install.wait 108 | :istio_init.install 109 | :istio_init.delete 110 | ``` 111 | And: 112 | ``` 113 | :istio.test.noclean 114 | :istio.test 115 | :istio.status 116 | :istio.install.wait 117 | :istio.install 118 | :istio.delete 119 | ``` 120 | 121 | Running `bazel run :istio_init.install` and a subsequent `bazel run :istio.install` (waiting for the CRDs to be created) will install Istio. See [rules_helm_examples](https://github.com/tmc/rules_helm_example) for detailed usage examples. 122 | -------------------------------------------------------------------------------- /docs/docs.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ## helm_chart 6 | 7 |
  8 | helm_chart(name, srcs, update_deps)
  9 | 
10 | 11 | Defines a helm chart (directory containing a Chart.yaml). 12 | 13 | ### Parameters 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 29 | 30 | 31 | 32 | 38 | 39 | 40 | 41 | 47 | 48 | 49 |
name 24 | required. 25 |

26 | A unique name for this rule. 27 |

28 |
srcs 33 | required. 34 |

35 | Source files to include as the helm chart. Typically this will just be glob(["**"]). 36 |

37 |
update_deps 42 | optional. default is False 43 |

44 | Whether or not to run a helm dependency update prior to packaging. 45 |

46 |
50 | 51 | 52 | 53 | 54 | ## helm_release 55 | 56 |
 57 | helm_release(name, release_name, chart, values_yaml, values, namespace)
 58 | 
59 | 60 | Defines a helm release. 61 | 62 | A given target has the following executable targets generated: 63 | 64 | `(target_name).install` 65 | `(target_name).install.wait` 66 | `(target_name).status` 67 | `(target_name).delete` 68 | `(target_name).test` 69 | `(target_name).test.noclean` 70 | 71 | 72 | ### Parameters 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 88 | 89 | 90 | 91 | 97 | 98 | 99 | 100 | 106 | 107 | 108 | 109 | 115 | 116 | 117 | 118 | 124 | 125 | 126 | 127 | 133 | 134 | 135 |
name 83 | required. 84 |

85 | A unique name for this rule. 86 |

87 |
release_name 92 | required. 93 |

94 | name of the release. 95 |

96 |
chart 101 | required. 102 |

103 | The chart defined by helm_chart. 104 |

105 |
values_yaml 110 | optional. default is None 111 |

112 | The values.yaml file to supply for the release. 113 |

114 |
values 119 | optional. default is None 120 |

121 | A map of additional values to supply for the release. 122 |

123 |
namespace 128 | optional. default is "" 129 |

130 | The namespace to install the release into. If empty will default the NAMESPACE environment variable and will fall back the the current username (via BUILD_USER). 131 |

132 |
136 | 137 | 138 | -------------------------------------------------------------------------------- /helm/helm.bzl: -------------------------------------------------------------------------------- 1 | load("@bazel_skylib//lib:paths.bzl", "paths") 2 | 3 | HELM_CMD_PREFIX = """ 4 | echo "#!/usr/bin/env bash" > $@ 5 | cat $(location @com_github_tmc_rules_helm//:runfiles_bash) >> $@ 6 | echo "export NAMESPACE=$$(grep NAMESPACE bazel-out/stable-status.txt | cut -d ' ' -f 2)" >> $@ 7 | echo "export BUILD_USER=$$(grep BUILD_USER bazel-out/stable-status.txt | cut -d ' ' -f 2)" >> $@ 8 | cat <> $@ 9 | #export RUNFILES_LIB_DEBUG=1 # For runfiles debugging 10 | 11 | export HELM=\$$(rlocation com_github_tmc_rules_helm/helm) 12 | PATH=\$$(dirname \$$HELM):\$$PATH 13 | """ 14 | 15 | def helm_chart(name, srcs, update_deps = False): 16 | """Defines a helm chart (directory containing a Chart.yaml). 17 | 18 | Args: 19 | name: A unique name for this rule. 20 | srcs: Source files to include as the helm chart. Typically this will just be glob(["**"]). 21 | update_deps: Whether or not to run a helm dependency update prior to packaging. 22 | """ 23 | filegroup_name = name + "_filegroup" 24 | helm_cmd_name = name + "_package.sh" 25 | package_flags = "" 26 | if update_deps: 27 | package_flags = "--dependency-update" 28 | native.filegroup( 29 | name = filegroup_name, 30 | srcs = srcs, 31 | ) 32 | native.genrule( 33 | name = name, 34 | srcs = [filegroup_name], 35 | outs = ["%s_chart.tar.gz" % name], 36 | tools = ["@com_github_tmc_rules_helm//:helm"], 37 | cmd = """ 38 | # find Chart.yaml in the filegroup 39 | CHARTLOC=missing 40 | for s in $(SRCS); do 41 | if [[ $$s =~ .*Chart.yaml ]]; then 42 | CHARTLOC=$$(dirname $$s) 43 | break 44 | fi 45 | done 46 | $(location @com_github_tmc_rules_helm//:helm) package {package_flags} $$CHARTLOC 47 | mv *tgz $@ 48 | """.format( 49 | package_flags = package_flags, 50 | ), 51 | ) 52 | 53 | def _build_helm_set_args(values): 54 | set_args = ["--set=%s=%s" % (key, values[key]) for key in sorted((values or {}).keys())] 55 | return " ".join(set_args) 56 | 57 | def _helm_cmd(cmd, args, name, helm_cmd_name, values_yaml = None, values = None): 58 | binary_data = ["@com_github_tmc_rules_helm//:helm"] 59 | if values_yaml: 60 | binary_data.append(values_yaml) 61 | if values: 62 | args.append(_build_helm_set_args(values)) 63 | 64 | native.sh_binary( 65 | name = name + "." + cmd, 66 | srcs = [helm_cmd_name], 67 | deps = ["@bazel_tools//tools/bash/runfiles"], 68 | data = binary_data, 69 | args = args, 70 | ) 71 | 72 | def helm_release(name, release_name, chart, values_yaml = None, values = None, namespace = ""): 73 | """Defines a helm release. 74 | 75 | A given target has the following executable targets generated: 76 | 77 | `(target_name).install` 78 | `(target_name).install.wait` 79 | `(target_name).status` 80 | `(target_name).delete` 81 | `(target_name).test` 82 | `(target_name).test.noclean` 83 | 84 | Args: 85 | name: A unique name for this rule. 86 | release_name: name of the release. 87 | chart: The chart defined by helm_chart. 88 | values_yaml: The values.yaml file to supply for the release. 89 | values: A map of additional values to supply for the release. 90 | namespace: The namespace to install the release into. If empty will default the NAMESPACE environment variable and will fall back the the current username (via BUILD_USER). 91 | """ 92 | helm_cmd_name = name + "_run_helm_cmd.sh" 93 | genrule_srcs = ["@com_github_tmc_rules_helm//:runfiles_bash", chart] 94 | 95 | # build --set params 96 | set_params = _build_helm_set_args(values) 97 | 98 | # build --values param 99 | values_param = "" 100 | if values_yaml: 101 | values_param = "--values=$(location %s)" % values_yaml 102 | genrule_srcs.append(values_yaml) 103 | 104 | native.genrule( 105 | name = name, 106 | stamp = True, 107 | srcs = genrule_srcs, 108 | outs = [helm_cmd_name], 109 | cmd = HELM_CMD_PREFIX + """ 110 | export CHARTLOC=$(location """ + chart + """) 111 | EXPLICIT_NAMESPACE=""" + namespace + """ 112 | NAMESPACE=\$${EXPLICIT_NAMESPACE:-\$$NAMESPACE} 113 | export NS=\$${NAMESPACE:-\$${BUILD_USER}} 114 | if [ "\$$1" == "upgrade" ]; then 115 | helm tiller run \$$NS -- helm \$$@ --namespace \$$NS """ + release_name + " " + set_params + " " + values_param + """ \$$CHARTLOC 116 | elif [ "\$$1" == "test" ]; then 117 | helm tiller run \$$NS -- helm test --cleanup """ + release_name + """ 118 | else 119 | helm tiller run \$$NS -- helm \$$@ """ + release_name + """ 120 | fi 121 | 122 | EOF""", 123 | ) 124 | _helm_cmd("install", ["upgrade", "--install"], name, helm_cmd_name, values_yaml, values) 125 | _helm_cmd("install.wait", ["upgrade", "--install", "--wait"], name, helm_cmd_name, values_yaml, values) 126 | _helm_cmd("status", ["status"], name, helm_cmd_name) 127 | _helm_cmd("delete", ["delete", "--purge"], name, helm_cmd_name) 128 | _helm_cmd("test", ["test", "--cleanup"], name, helm_cmd_name) 129 | _helm_cmd("test.noclean", ["test"], name, helm_cmd_name) 130 | --------------------------------------------------------------------------------