├── 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 |
name |
23 |
24 | required.
25 | 26 | A unique name for this rule. 27 | 28 | |
29 |
srcs |
32 |
33 | required.
34 | 35 | Source files to include as the helm chart. Typically this will just be glob(["**"]). 36 | 37 | |
38 |
update_deps |
41 |
42 | optional. default is False
43 | 44 | Whether or not to run a helm dependency update prior to packaging. 45 | 46 | |
47 |
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 |
name |
82 |
83 | required.
84 | 85 | A unique name for this rule. 86 | 87 | |
88 |
release_name |
91 |
92 | required.
93 | 94 | name of the release. 95 | 96 | |
97 |
chart |
100 |
101 | required.
102 | 103 | The chart defined by helm_chart. 104 | 105 | |
106 |
values_yaml |
109 |
110 | optional. default is None
111 | 112 | The values.yaml file to supply for the release. 113 | 114 | |
115 |
values |
118 |
119 | optional. default is None
120 | 121 | A map of additional values to supply for the release. 122 | 123 | |
124 |
namespace |
127 |
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 | |
133 |