From b3ee085c322125494606d0dc48206137fef858cd Mon Sep 17 00:00:00 2001 From: Jean-Daniel Dupas Date: Tue, 2 Mar 2021 17:44:09 +0100 Subject: [PATCH 01/11] [kap-9] Rewrite helm_fetch to use helm_cli. An actually difference with the cffi implementation is that if something goes wrong, it raises a HelmFetchingError instead of silently failing. It is consistent with Git and Http behaviour which raise errors too if the fetch operation fails. --- .travis.yml | 8 +- Dockerfile | 12 +- Dockerfile.ci | 9 +- MANIFEST.in | 1 - Makefile | 4 - docs/external_dependencies.md | 2 +- kapitan/dependency_manager/base.py | 107 ++- kapitan/dependency_manager/helm/build.sh | 33 - kapitan/dependency_manager/helm/cffi_build.py | 21 - kapitan/dependency_manager/helm/go.mod | 11 - kapitan/dependency_manager/helm/go.sum | 760 ------------------ kapitan/dependency_manager/helm/helm_fetch.go | 74 -- .../helm/helm_fetch_binding.py | 8 - kapitan/errors.py | 4 + kapitan/helm_cli.py | 10 + pyproject.toml | 1 - tests/test_dependency_manager.py | 22 +- 17 files changed, 97 insertions(+), 990 deletions(-) delete mode 100755 kapitan/dependency_manager/helm/build.sh delete mode 100644 kapitan/dependency_manager/helm/cffi_build.py delete mode 100644 kapitan/dependency_manager/helm/go.mod delete mode 100644 kapitan/dependency_manager/helm/go.sum delete mode 100644 kapitan/dependency_manager/helm/helm_fetch.go delete mode 100644 kapitan/dependency_manager/helm/helm_fetch_binding.py create mode 100644 kapitan/helm_cli.py diff --git a/.travis.yml b/.travis.yml index 83faff9ca..8b76c4ef2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,18 +25,22 @@ before_install: - sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 762E3157 # Loop until update succeeds (timeouts can occur) - travis_retry $(! sudo apt-get -qq update 2>&1 | grep Failed) - - sudo apt-get install -y gnupg2 git - sudo apt-get install -y golang-1.14 - export PATH="/usr/lib/go-1.14/bin:$PATH" - export GOROOT=/usr/lib/go-1.14 - go version + - sudo apt-get install -y gnupg2 git curl + # Install Helm Binary + - curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 + - chmod 700 get_helm.sh + - sudo ./get_helm.sh install: - pip3 install -r requirements.txt - pip3 install coverage black script: - - make build_helm_binding && make build_helm_fetch_binding + - make build_helm_binding - make test && make test_coverage after_success: diff --git a/Dockerfile b/Dockerfile index 02e6e7c90..c7590c45e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,10 +8,6 @@ COPY ./kapitan/inputs/helm ./kapitan/inputs/helm RUN chmod +x ./kapitan/inputs/helm/build.sh \ && ./kapitan/inputs/helm/build.sh -COPY ./kapitan/dependency_manager/helm ./kapitan/dependency_manager/helm -RUN chmod +x ./kapitan/dependency_manager/helm/build.sh \ - && ./kapitan/dependency_manager/helm/build.sh - COPY ./kapitan ./kapitan COPY ./MANIFEST.in ./MANIFEST.in COPY ./requirements.txt ./requirements.txt @@ -32,9 +28,15 @@ RUN apt-get update \ && pip install --upgrade pip yq wheel \ && pip install -r requirements.txt \ && ./kapitan/inputs/helm/build.sh \ - && ./kapitan/dependency_manager/helm/build.sh \ && pip install . +# Install Helm +RUN apt-get install --no-install-recommends -y curl \ + && curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 \ + && chmod 700 get_helm.sh \ + && HELM_INSTALL_DIR=/opt/venv/bin ./get_helm.sh --no-sudo \ + && rm get_helm.sh + # Final image with virtualenv built in previous step FROM python:3.7-slim-stretch diff --git a/Dockerfile.ci b/Dockerfile.ci index b7459cb89..6c28583b9 100644 --- a/Dockerfile.ci +++ b/Dockerfile.ci @@ -17,10 +17,6 @@ COPY ./kapitan/inputs/helm ./kapitan/inputs/helm RUN chmod +x ./kapitan/inputs/helm/build.sh \ && ./kapitan/inputs/helm/build.sh -COPY ./kapitan/dependency_manager/helm ./kapitan/dependency_manager/helm -RUN chmod +x ./kapitan/dependency_manager/helm/build.sh \ - && ./kapitan/dependency_manager/helm/build.sh - COPY ./kapitan ./kapitan COPY ./MANIFEST.in ./MANIFEST.in COPY ./requirements.txt ./requirements.txt @@ -73,9 +69,12 @@ RUN apt-get update \ && pip install --upgrade pip yq wheel \ && pip install -r ./kapitan/requirements.txt \ && ./kapitan/kapitan/inputs/helm/build.sh \ - && ./kapitan/kapitan/dependency_manager/helm/build.sh \ && pip install ./kapitan \ && rm -rf ./kapitan \ + && curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 \ + && chmod 700 get_helm.sh \ + && HELM_INSTALL_DIR=/opt/venv/bin ./get_helm.sh --no-sudo \ + && rm get_helm.sh \ && curl -L -o /usr/local/bin/kapp ${KAPP_URL} \ && chmod +x /usr/local/bin/kapp \ && curl -L -o /usr/local/bin/kbld ${KBLD_URL} \ diff --git a/MANIFEST.in b/MANIFEST.in index f7ccf520b..f9a9aa1cd 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -3,4 +3,3 @@ include kapitan/lib/*.libjsonnet include requirements.txt recursive-include kapitan/inputs/templates * recursive-include kapitan/inputs/helm * -recursive-include kapitan/dependency_manager/helm * diff --git a/Makefile b/Makefile index 337d215e8..f4afe8ca4 100644 --- a/Makefile +++ b/Makefile @@ -53,7 +53,3 @@ format_codestyle: # ignores line length and reclass black . @echo - -.PHONY: build_helm_fetch_binding -build_helm_fetch_binding: - bash kapitan/dependency_manager/helm/build.sh diff --git a/docs/external_dependencies.md b/docs/external_dependencies.md index 3cada6237..660c5455b 100644 --- a/docs/external_dependencies.md +++ b/docs/external_dependencies.md @@ -171,7 +171,7 @@ Setting `unpack: True` will unpack zip or tar files onto the `output_path`. In s ## Helm type Fetches helm charts and any specific subcharts in the `requirements.yaml` file. -Currently only works on linux with the `helm_fetch_binding`. +Requires that `helm` be present in the PATH. ### Usage diff --git a/kapitan/dependency_manager/base.py b/kapitan/dependency_manager/base.py index d535dcc33..4614e3feb 100644 --- a/kapitan/dependency_manager/base.py +++ b/kapitan/dependency_manager/base.py @@ -6,16 +6,16 @@ import logging import multiprocessing import os -from collections import defaultdict +from collections import defaultdict, namedtuple from distutils.dir_util import copy_tree from functools import partial -from shutil import copyfile, rmtree -import platform from mimetypes import MimeTypes +from shutil import copyfile, rmtree + from git import GitCommandError from git import Repo - -from kapitan.errors import GitSubdirNotFoundError, GitFetchingError, HelmBindingUnavailableError +from kapitan.errors import GitSubdirNotFoundError, GitFetchingError, HelmFetchingError +from kapitan.helm_cli import helm_cli from kapitan.utils import ( make_request, unpack_downloaded_file, @@ -24,14 +24,9 @@ normalise_join_path, ) - logger = logging.getLogger(__name__) -try: - from kapitan.dependency_manager.helm.helm_fetch_binding import ffi -except ImportError as ie: - logger.debug("Error importing ffi from kapitan.dependency_manager.helm.helm_fetch_binding: %s", ie) - pass # make this feature optional +HelmSource = namedtuple("HelmSource", ["repo", "chart_name", "version"]) def fetch_dependencies(output_path, target_objs, save_dir, force, pool): @@ -75,9 +70,7 @@ def fetch_dependencies(output_path, target_objs, save_dir, force, pool): http_deps[source_uri].append(item) elif dependency_type == "helm": version = item.get("version", "") - if version == "": - version = "latest" - helm_deps[item["chart_name"] + "-" + version].append(item) + helm_deps[HelmSource(source_uri, item["chart_name"], version)].append(item) else: logger.warning("%s is not a valid source type", dependency_type) @@ -89,7 +82,7 @@ def fetch_dependencies(output_path, target_objs, save_dir, force, pool): git_worker = partial(fetch_git_dependency, save_dir=save_dir, force=force) http_worker = partial(fetch_http_dependency, save_dir=save_dir, force=force) - helm_worker = partial(fetch_helm_chart) + helm_worker = partial(fetch_helm_chart, save_dir=save_dir, force=force) [p.get() for p in pool.imap_unordered(http_worker, http_deps.items()) if p] [p.get() for p in pool.imap_unordered(git_worker, git_deps.items()) if p] [p.get() for p in pool.imap_unordered(helm_worker, helm_deps.items()) if p] @@ -220,56 +213,56 @@ def fetch_http_source(source, save_path, item_type): return None -def fetch_helm_chart(dep_mapping): +def fetch_helm_chart(dep_mapping, save_dir, force): """ downloads a helm chart and its subcharts from source then untars and moves it to save_dir """ - lib = initialise_helm_fetch_binding() - unique_chart, deps = dep_mapping - for dep in deps: - chart_name = dep["chart_name"] - version = dep.get("version", "") - repo_url = dep["source"] - destination_dir = dep["output_path"] - - if version == "": - logger.info( - "Dependency helm chart %s being fetch with using latest version available", chart_name - ) + source, deps = dep_mapping - logger.info("Dependency helm chart %s and version %s: fetching now", chart_name, version) - c_chart_name = ffi.new("char[]", chart_name.encode("ascii")) - c_version = ffi.new("char[]", version.encode("ascii")) - c_repo_url = ffi.new("char[]", repo_url.encode("ascii")) - c_destination_dir = ffi.new("char[]", destination_dir.encode("ascii")) + # to avoid collisions between source.chart_name/source.version + path_hash = hashlib.sha256(source.repo.encode()).hexdigest()[:8] + cached_repo_path = os.path.join( + save_dir, path_hash, source.chart_name + "-" + (source.version or "latest") + ) + if force or not exists_in_cache(cached_repo_path): + fetch_helm_archive(source.repo, source.chart_name, source.version, cached_repo_path) + else: + logger.debug("Using cached {} {}".format(item_type, cached_repo_path)) - res = lib.fetchHelmChart(c_repo_url, c_chart_name, c_version, c_destination_dir) - response = ffi.string(res).decode("utf-8") - if response != "": - logger.warning("Dependency helm chart %s and version %s: %s", chart_name, version, response) + for dep in deps: + output_path = dep["output_path"] + + parent_dir = os.path.dirname(output_path) + if parent_dir != "": + os.makedirs(parent_dir, exist_ok=True) + if force: + copy_tree(cached_repo_path, output_path) else: - logger.info("Dependency helm chart %s and version %s: successfully fetched", chart_name, version) - logger.info( - "Dependency helm chart %s and version %s: saved to %s", chart_name, version, destination_dir - ) + safe_copy_tree(cached_repo_path, output_path) + logger.info("Dependency %s: saved to %s", source.chart_name, output_path) -def initialise_helm_fetch_binding(): - """returns the dl_opened library (.so file) if exists, otherwise None""" - if platform.system() not in ("Linux", "Darwin"): # TODO: later add binding for Mac - return None - # binding_path is kapitan/dependency_manager/helm/helm_fetch.so - binding_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "helm/helm_fetch.so") - if not os.path.exists(binding_path): - logger.debug("The helm_fetch binding does not exist at %s", binding_path) - return None - try: - lib = ffi.dlopen(binding_path) - except (NameError, OSError) as e: - raise HelmBindingUnavailableError( - "There was an error opening helm_fetch.so binding. " "Refer to the exception below:\n" + str(e) - ) - return lib +def fetch_helm_archive(repo, chart_name, version, save_path): + logger.info("Dependency helm chart %s and version %s: fetching now", chart_name, version or "latest") + # Fetch archive and untar it into parent dir + save_dir = os.path.dirname(save_path) + args = ["pull", "--destination", save_dir, "--untar", "--repo", repo] + + if version: + args.append("--version") + args.append(version) + + args.append(chart_name) + + response = helm_cli(args) + if response != "": + logger.warning("Dependency helm chart %s and version %s: %s", chart_name, version, response) + raise HelmFetchingError(response) + else: + # rename chart to requested name + os.rename(os.path.join(save_dir, chart_name), save_path) + logger.info("Dependency helm chart %s and version %s: successfully fetched", chart_name, version) + logger.info("Dependency helm chart %s and version %s: saved to %s", chart_name, version, save_path) def exists_in_cache(item_path): diff --git a/kapitan/dependency_manager/helm/build.sh b/kapitan/dependency_manager/helm/build.sh deleted file mode 100755 index 6e8c0c039..000000000 --- a/kapitan/dependency_manager/helm/build.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -cd $(dirname "$0") -pwd - -so_name="helm_fetch.so" - -# Compile the binding if a Go runtime exists -if [[ -z $(which go) ]]; then - echo "[WARN] go is not available on this system -- skipping Helm binding build!" -else - go build -buildmode=c-shared -o $so_name helm_fetch.go -fi - -# Validate that the compiled binding exists -if [[ -e $so_name ]]; then - echo "[INFO] $so_name built successfully or already exists" -else - echo "[ERROR] $so_name does not exist!" - exit 1 -fi - -# Compile the Python ffi binding if Python is available -if [[ -z $(which python3) ]]; then - echo "[WARN] python3 is not available on this system -- skipping cffi build!" -else - echo "[INFO] Building the Python binding using cffi" - python3 cffi_build.py -fi - -exit 0 diff --git a/kapitan/dependency_manager/helm/cffi_build.py b/kapitan/dependency_manager/helm/cffi_build.py deleted file mode 100644 index bf5ef778a..000000000 --- a/kapitan/dependency_manager/helm/cffi_build.py +++ /dev/null @@ -1,21 +0,0 @@ -from cffi import FFI - - -def main(): - ffi = FFI() - - # declare functions to export - ffi.cdef( - """ - char* fetchHelmChart(char* p0, char* p1, char* p2, char* p3); - void free(void* ptr); - """ - ) - - ffi.set_source("helm_fetch_binding", None) # specify name for importing this module - - ffi.compile(verbose=True) - - -if __name__ == "__main__": - main() diff --git a/kapitan/dependency_manager/helm/go.mod b/kapitan/dependency_manager/helm/go.mod deleted file mode 100644 index dc8b7db77..000000000 --- a/kapitan/dependency_manager/helm/go.mod +++ /dev/null @@ -1,11 +0,0 @@ -module dmhelm - -go 1.14 - -require ( - github.com/docker/go-metrics v0.0.1 // indirect - github.com/gorilla/mux v1.7.4 // indirect - github.com/otiai10/copy v1.2.0 - helm.sh/helm/v3 v3.2.0 - rsc.io/letsencrypt v0.0.3 // indirect -) diff --git a/kapitan/dependency_manager/helm/go.sum b/kapitan/dependency_manager/helm/go.sum deleted file mode 100644 index cd7e31139..000000000 --- a/kapitan/dependency_manager/helm/go.sum +++ /dev/null @@ -1,760 +0,0 @@ -bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= -github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= -github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/DATA-DOG/go-sqlmock v1.4.1 h1:ThlnYciV1iM/V0OSF/dtkqWb6xo5qITT1TJBG1MRDJM= -github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= -github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd h1:sjQovDkwrZp8u+gxLtPgKGjk5hCxuy2hrRejBTA9xFU= -github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= -github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg= -github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver/v3 v3.1.0 h1:Y2lUDsFKVRSYGojLJ1yLxSXdMmMYTYls0rCvoqmMUQk= -github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/Masterminds/sprig/v3 v3.1.0 h1:j7GpgZ7PdFqNsmncycTHsLmVPf5/3wJtlgW9TNDYD9Y= -github.com/Masterminds/sprig/v3 v3.1.0/go.mod h1:ONGMf7UfYGAbMXCZmQLy8x3lCDIPrEZE/rU8pmrbihA= -github.com/Masterminds/squirrel v1.2.0 h1:K1NhbTO21BWG47IVR0OnIZuE0LZcXAYqywrC3Ko53KI= -github.com/Masterminds/squirrel v1.2.0/go.mod h1:yaPeOnPG5ZRwL9oKdTsO/prlkPbXWZlRVMQ/gGlzIuA= -github.com/Masterminds/vcs v1.13.1/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA= -github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6trr62pF5DucadTWGdEB4mEyvzi0e2nbcmcyA= -github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= -github.com/Microsoft/hcsshim v0.8.7 h1:ptnOoufxGSzauVTsdE+wMYnCWA301PdoN4xg5oRdZpg= -github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= -github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= -github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= -github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= -github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496 h1:zV3ejI06GQ59hwDQAvmK1qxOQGB3WuVTRoY0okPTAv0= -github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= -github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= -github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y= -github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= -github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= -github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= -github.com/bshuster-repo/logrus-logstash-hook v0.4.1 h1:pgAtgj+A31JBVtEHu2uHuEx0n+2ukqUJnS2vVe5pQNA= -github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= -github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd h1:rFt+Y/IK1aEZkEHchZRSq9OQbsSzIT/OrI8YFFmRIng= -github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= -github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembjv71DPz3uX/V/6MMlSyD9JBQ6kQ= -github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= -github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o= -github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f h1:tSNMc+rJDfmYntojat8lljbt1mgKNpTxUZJsSzJ9Y1s= -github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= -github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= -github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.3.2 h1:ForxmXkA6tPIvffbrDAcPUIB32QgXkt2XFj+F0UxetA= -github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= -github.com/containerd/continuity v0.0.0-20200107194136-26c1120b8d41 h1:kIFnQBO7rQ0XkMe6xEwbybYHBEaWmh/f++laI6Emt7M= -github.com/containerd/continuity v0.0.0-20200107194136-26c1120b8d41/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY= -github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= -github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= -github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= -github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg= -github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= -github.com/deislabs/oras v0.8.1 h1:If674KraJVpujYR00rzdi0QAmW4BxzMJPVAZJKuhQ0c= -github.com/deislabs/oras v0.8.1/go.mod h1:Mx0rMSbBNaNfY9hjpccEnxkOqJL6KGjtxNHPLC4G4As= -github.com/denisenkom/go-mssqldb v0.0.0-20191001013358-cfbb681360f0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= -github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= -github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= -github.com/docker/cli v0.0.0-20200130152716-5d0cf8839492 h1:FwssHbCDJD025h+BchanCwE1Q8fyMgqDr2mOQAWOLGw= -github.com/docker/cli v0.0.0-20200130152716-5d0cf8839492/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/distribution v0.0.0-20191216044856-a8371794149d/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= -github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= -github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker v1.4.2-0.20200203170920-46ec8731fbce h1:KXS1Jg+ddGcWA8e1N7cupxaHHZhit5rB9tfDU+mfjyY= -github.com/docker/docker v1.4.2-0.20200203170920-46ec8731fbce/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ= -github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= -github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= -github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= -github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= -github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 h1:ZClxb8laGDf5arXfYcAtECDFgAgHklGI8CxgjHnXKJ4= -github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= -github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96 h1:cenwrSVm+Z7QLSV/BsnenAOcDXdX4cMv4wP0B/5QbPg= -github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= -github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc= -github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= -github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= -github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M= -github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= -github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= -github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= -github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7 h1:LofdAjjjqCSXMwLGgOgnE+rdPuvX9DxCqaHwKy7i/ko= -github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= -github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= -github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= -github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= -github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= -github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= -github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= -github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= -github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= -github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= -github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= -github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= -github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= -github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= -github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= -github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o= -github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= -github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk= -github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= -github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= -github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= -github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= -github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= -github.com/go-openapi/spec v0.19.3 h1:0XRyw8kguri6Yw4SxhsQA/atC88yqrk0+G4YhI2wabc= -github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= -github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= -github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= -github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= -github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= -github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= -github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= -github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= -github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= -github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= -github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= -github.com/gobuffalo/envy v1.7.1 h1:OQl5ys5MBea7OGCdvPbBJWRgnhC/fGona6QKfvFeau8= -github.com/gobuffalo/envy v1.7.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w= -github.com/gobuffalo/logger v1.0.1 h1:ZEgyRGgAm4ZAhAO45YXMs5Fp+bzGLESFewzAVBMKuTg= -github.com/gobuffalo/logger v1.0.1/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= -github.com/gobuffalo/packd v0.3.0 h1:eMwymTkA1uXsqxS0Tpoop3Lc0u3kTfiMBE6nKtQU4g4= -github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= -github.com/gobuffalo/packr/v2 v2.7.1 h1:n3CIW5T17T8v4GGK5sWXLVWJhCz7b5aNLSxW6gYim4o= -github.com/gobuffalo/packr/v2 v2.7.1/go.mod h1:qYEvAazPaVxy7Y7KR0W8qYEE+RymX74kETFqjFoFlOc= -github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= -github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= -github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= -github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef h1:veQD95Isof8w9/WXiA+pa3tz3fJXkt5B7QaRBrM62gk= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho= -github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995/go.mod h1:lJgMEyOkYFkPcDKwRXegd+iM6E7matEszMG5HhwytU8= -github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= -github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/googleapis/gnostic v0.1.0 h1:rVsPeBmXbYv4If/cumu1AzZPwV58q433hvONV1UEZoI= -github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33 h1:893HsJqtxp9z1SF76gg6hY70hRY1wVlTSnC/h1yUDCo= -github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= -github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= -github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY= -github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huandu/xstrings v1.3.1 h1:4jgBlKK6tLKFvO8u5pmYjG91cqytmDCDvGh7ECVFfFs= -github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ= -github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA= -github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= -github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= -github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok= -github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw= -github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= -github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk= -github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU= -github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= -github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= -github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM= -github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= -github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= -github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= -github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= -github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/mattn/go-sqlite3 v1.12.0 h1:u/x3mp++qUxvYfulZ4HKOvVO0JWhk7HtE8lWhbGz/Do= -github.com/mattn/go-sqlite3 v1.12.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= -github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= -github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f h1:2+myh5ml7lgEU/51gbeLHfKGNfgEQQIWrlbdaOsidbQ= -github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= -github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= -github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= -github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= -github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ= -github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= -github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= -github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= -github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= -github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= -github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= -github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= -github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= -github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= -github.com/otiai10/copy v1.2.0 h1:HvG945u96iNadPoG2/Ja2+AUJeW5YuFQMixq9yirC+k= -github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= -github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= -github.com/otiai10/curr v1.0.0 h1:TJIWdbX0B+kpNagQrjgq8bCMrbhiuX73M2XwgtDMoOI= -github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= -github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= -github.com/otiai10/mint v1.3.1 h1:BCmzIS3n71sGfHB5NMNDB3lHYPz8fWSkCAErHed//qc= -github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= -github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= -github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc= -github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= -github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.1.0 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8= -github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= -github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.6.0 h1:kRhiuYSXR3+uv2IbVbZhUxK5zVD/2pp3Gd2PpvPkpEo= -github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= -github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8= -github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.4.0 h1:LUa41nrWTQNGhzdsZ5lTnkwbNjj6rXTdazA1cSdjkOY= -github.com/rogpeppe/go-internal v1.4.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rubenv/sql-migrate v0.0.0-20200212082348-64f95ea68aa3 h1:xkBtI5JktwbW/vf4vopBbhYsRFTGfQWHYXzC0/qYwxI= -github.com/rubenv/sql-migrate v0.0.0-20200212082348-64f95ea68aa3/go.mod h1:rtQlpHw+eR6UrqaS3kX1VYeaCxzCVdimDS7g5Ln4pPc= -github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= -github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= -github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= -github.com/xeipuuv/gojsonschema v1.1.0 h1:ngVtJC9TY/lg0AA/1k48FYhBrhRoFlEmWzsehpNAaZg= -github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI= -github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= -github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMztlGpl/VA+Zm1AcTPHYkHJPbHqE6WJUXE= -github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= -github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1:ERexzlUfuTvpE74urLSbIQW0Z/6hF9t8U4NsJLaioAY= -github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= -github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= -github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= -go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200414173820-0848c9571904 h1:bXoxMPcSLOq08zI3/c5dEBT6lE4eh+jOh886GHrn6V8= -golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI= -golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7 h1:HmbHVPwrPEKPGLAcHSrMe6+hqSUlvZU0rab6x5EXfGU= -golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= -gopkg.in/gorp.v1 v1.7.2 h1:j3DWlAyGVv8whO7AcIWznQ2Yj7yJkn34B8s63GViAAw= -gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw= -gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= -gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= -gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= -helm.sh/helm/v3 v3.2.0 h1:V12EGAmr2DJ/fWrPo2fPdXWSIXvlXm51vGkQIXMeymE= -helm.sh/helm/v3 v3.2.0/go.mod h1:ZaXz/vzktgwjyGGFbUWtIQkscfE7WYoRGP2szqAFHR0= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -k8s.io/api v0.18.0 h1:lwYk8Vt7rsVTwjRU6pzEsa9YNhThbmbocQlKvNBB4EQ= -k8s.io/api v0.18.0/go.mod h1:q2HRQkfDzHMBZL9l/y9rH63PkQl4vae0xRT+8prbrK8= -k8s.io/apiextensions-apiserver v0.18.0 h1:HN4/P8vpGZFvB5SOMuPPH2Wt9Y/ryX+KRvIyAkchu1Q= -k8s.io/apiextensions-apiserver v0.18.0/go.mod h1:18Cwn1Xws4xnWQNC00FLq1E350b9lUF+aOdIWDOZxgo= -k8s.io/apimachinery v0.18.0 h1:fuPfYpk3cs1Okp/515pAf0dNhL66+8zk8RLbSX+EgAE= -k8s.io/apimachinery v0.18.0/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= -k8s.io/apiserver v0.18.0/go.mod h1:3S2O6FeBBd6XTo0njUrLxiqk8GNy6wWOftjhJcXYnjw= -k8s.io/cli-runtime v0.18.0 h1:jG8XpSqQ5TrV0N+EZ3PFz6+gqlCk71dkggWCCq9Mq34= -k8s.io/cli-runtime v0.18.0/go.mod h1:1eXfmBsIJosjn9LjEBUd2WVPoPAY9XGTqTFcPMIBsUQ= -k8s.io/client-go v0.18.0 h1:yqKw4cTUQraZK3fcVCMeSa+lqKwcjZ5wtcOIPnxQno4= -k8s.io/client-go v0.18.0/go.mod h1:uQSYDYs4WhVZ9i6AIoEZuwUggLVEF64HOD37boKAtF8= -k8s.io/code-generator v0.18.0/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= -k8s.io/component-base v0.18.0 h1:I+lP0fNfsEdTDpHaL61bCAqTZLoiWjEEP304Mo5ZQgE= -k8s.io/component-base v0.18.0/go.mod h1:u3BCg0z1uskkzrnAKFzulmYaEpZF7XC9Pf/uFyb1v2c= -k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= -k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c h1:/KUFqjjqAcY4Us6luF5RDNZ16KJtb49HfR3ZHB9qYXM= -k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= -k8s.io/kubectl v0.18.0 h1:hu52Ndq/d099YW+3sS3VARxFz61Wheiq8K9S7oa82Dk= -k8s.io/kubectl v0.18.0/go.mod h1:LOkWx9Z5DXMEg5KtOjHhRiC1fqJPLyCr3KtQgEolCkU= -k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= -k8s.io/metrics v0.18.0/go.mod h1:8aYTW18koXqjLVKL7Ds05RPMX9ipJZI3mywYvBOxXd4= -k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89 h1:d4vVOjXm687F1iLSP2q3lyPPuyvTUt3aVoBpi2DqRsU= -k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -rsc.io/letsencrypt v0.0.3 h1:H7xDfhkaFFSYEJlKeq38RwX2jYcnTeHuDQyT+mMNMwM= -rsc.io/letsencrypt v0.0.3/go.mod h1:buyQKZ6IXrRnB7TdkHP0RyEybLx18HHyOSoTyoOLqNY= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0= -sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0= -sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= -sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= -sigs.k8s.io/structured-merge-diff/v3 v3.0.0 h1:dOmIZBMfhcHS09XZkMyUgkq5trg3/jRyJYFZUiaOp8E= -sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= -sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= -vbom.ml/util v0.0.0-20160121211510-db5cfe13f5cc/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj6uzU2+8OWDFv/HxUSs7kI= diff --git a/kapitan/dependency_manager/helm/helm_fetch.go b/kapitan/dependency_manager/helm/helm_fetch.go deleted file mode 100644 index 1cb384557..000000000 --- a/kapitan/dependency_manager/helm/helm_fetch.go +++ /dev/null @@ -1,74 +0,0 @@ -package main - -import "C" - -import ( - "io/ioutil" - "os" - "path/filepath" - "strings" - - "github.com/otiai10/copy" - "helm.sh/helm/v3/pkg/action" - "helm.sh/helm/v3/pkg/cli" -) - -//export fetchHelmChart -func fetchHelmChart(c_repoURL, c_chartName, c_chartVersion, c_destinationDir *C.char) *C.char { - repoURL := C.GoString(c_repoURL) - chartName := C.GoString(c_chartName) - chartVersion := C.GoString(c_chartVersion) - destDir := C.GoString(c_destinationDir) - - client := action.NewPull() - - client.Settings = &cli.EnvSettings{ - Debug: false, - RepositoryCache: "/tmp", - } - - client.ChartPathOptions = action.ChartPathOptions{ - RepoURL: repoURL, - Verify: false, - Version: chartVersion, - } - - client.UntarDir = destDir - client.Untar = true - - res, err := client.Run(chartName) - if err != nil { - return C.CString(err.Error()) - } - - // remove chart tgz dir - c, err := ioutil.ReadDir(destDir) - for _, entry := range c { - if strings.Contains(entry.Name(), ".tgz") && entry.IsDir() { - tgzDir := filepath.Join(destDir, entry.Name()) - err = os.Remove(tgzDir) - if err != nil { - return C.CString(err.Error()) - } - } - - } - - // move files from helm client output dir to specified destination dir - originalDestDir := filepath.Join(destDir, chartName) - err = copy.Copy(originalDestDir, destDir) - if err != nil { - return C.CString(err.Error()) - } - - // remove old originalDestDir - err = os.RemoveAll(originalDestDir) - if err != nil { - return C.CString(err.Error()) - } - - return C.CString(res) -} - -// this is required to build this as shared object file using cgo -func main() {} diff --git a/kapitan/dependency_manager/helm/helm_fetch_binding.py b/kapitan/dependency_manager/helm/helm_fetch_binding.py deleted file mode 100644 index 7dd784572..000000000 --- a/kapitan/dependency_manager/helm/helm_fetch_binding.py +++ /dev/null @@ -1,8 +0,0 @@ -# auto-generated file -import _cffi_backend - -ffi = _cffi_backend.FFI('helm_fetch_binding', - _version = 0x2601, - _types = b'\x00\x00\x01\x0D\x00\x00\x09\x03\x00\x00\x01\x11\x00\x00\x01\x11\x00\x00\x01\x11\x00\x00\x00\x0F\x00\x00\x0A\x0D\x00\x00\x0A\x03\x00\x00\x00\x0F\x00\x00\x02\x01\x00\x00\x00\x01', - _globals = (b'\x00\x00\x00\x23fetchHelmChart',0,b'\x00\x00\x06\x23free',0), -) diff --git a/kapitan/errors.py b/kapitan/errors.py index 2093ca971..a83076f43 100644 --- a/kapitan/errors.py +++ b/kapitan/errors.py @@ -60,6 +60,10 @@ class HelmBindingUnavailableError(KapitanError): pass +class HelmFetchingError(KapitanError): + pass + + class HelmTemplateError(KapitanError): pass diff --git a/kapitan/helm_cli.py b/kapitan/helm_cli.py new file mode 100644 index 000000000..188a8e393 --- /dev/null +++ b/kapitan/helm_cli.py @@ -0,0 +1,10 @@ +import subprocess +from subprocess import PIPE + + +def helm_cli(args): + try: + res = subprocess.run(args=["helm"] + args, stderr=PIPE) + return res.stderr.decode() if res.returncode != 0 else "" + except FileNotFoundError: + return "helm binary not found. helm must be present in the PATH to use kapitan helm functionalities" diff --git a/pyproject.toml b/pyproject.toml index 9279ec4be..685de9c07 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,6 @@ exclude = ''' /( .*reclass.* | .*helm_binding.py - | .*helm_fetch_binding.py | .*version.py ) ) diff --git a/tests/test_dependency_manager.py b/tests/test_dependency_manager.py index d4d5a0e1c..38cbfa295 100644 --- a/tests/test_dependency_manager.py +++ b/tests/test_dependency_manager.py @@ -8,9 +8,11 @@ import multiprocessing import os import sys -import unittest import tempfile +import unittest from shutil import rmtree + +from kapitan.errors import HelmFetchingError from kapitan.cached import reset_cache from kapitan.cli import main from kapitan.dependency_manager.base import ( @@ -19,6 +21,7 @@ fetch_git_dependency, fetch_helm_chart, fetch_dependencies, + HelmSource, ) @@ -80,45 +83,50 @@ def test_fetch_helm_chart(self): """ Tests fetching helm chart """ + temp_dir = tempfile.mkdtemp() output_dir = tempfile.mkdtemp() output_chart_dir = os.path.join(output_dir, "charts", "prometheus") chart_name = "prometheus" version = "11.3.0" - unique_chart_name = chart_name + "-" + version + repo = "https://github.com/BurdenBear/kube-charts-mirror/raw/master/docs/" dep = [ { "output_path": output_chart_dir, "version": version, "chart_name": chart_name, - "source": "https://github.com/BurdenBear/kube-charts-mirror/raw/master/docs/", + "source": repo, } ] - fetch_helm_chart((unique_chart_name, dep)) + fetch_helm_chart((HelmSource(repo, chart_name, version), dep), temp_dir, force=False) self.assertTrue(os.path.isdir(output_chart_dir)) self.assertTrue(os.path.isfile(os.path.join(output_chart_dir, "Chart.yaml"))) self.assertTrue(os.path.isdir(os.path.join(output_chart_dir, "charts", "kube-state-metrics"))) + rmtree(temp_dir) rmtree(output_dir) def test_fetch_helm_chart_version_that_does_not_exist(self): """ Test fetching helm chart version that does not exist """ + temp_dir = tempfile.mkdtemp() output_dir = tempfile.mkdtemp() output_chart_dir = os.path.join(output_dir, "charts", "prometheus") chart_name = "prometheus" version = "10.7.0" - unique_chart_name = chart_name + "-" + version + repo = "https://github.com/BurdenBear/kube-charts-mirror/raw/master/docs/" dep = [ { "output_path": output_chart_dir, "version": version, "chart_name": chart_name, - "source": "https://github.com/BurdenBear/kube-charts-mirror/raw/master/docs/", + "source": repo, } ] - fetch_helm_chart((unique_chart_name, dep)) + with self.assertRaises(HelmFetchingError): + fetch_helm_chart((HelmSource(repo, chart_name, version), dep), temp_dir, force=False) self.assertFalse(os.path.isdir(output_chart_dir)) self.assertFalse(os.path.isfile(os.path.join(output_chart_dir, "Chart.yaml"))) + rmtree(temp_dir) rmtree(output_dir) def test_fetch_dependencies_unpack_parallel(self): From 66e4ae174eea7eca99cd98c47efa76b41ca2ca1d Mon Sep 17 00:00:00 2001 From: Jean-Daniel Dupas Date: Tue, 2 Mar 2021 23:20:52 +0100 Subject: [PATCH 02/11] [kap-9] Rewrite helm input using helm cli. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It mostly matches the cffi implementation with one difference: - release_name is required when using Helm CLI. This implementation uses —generate-name flag if neither release_name nor template_name are specified, which may cause different output. This commit also add `validate` flag support, which is required to compile some templates that rely on cluster Capabilities (cilium with ServiceMonitor for instance). --- .travis.yml | 5 - Dockerfile | 15 +- Dockerfile.ci | 24 +- MANIFEST.in | 1 - Pipfile | 1 - Pipfile.lock | 43 ---- kapitan/inputs/helm.py | 123 ++++++++++ kapitan/inputs/helm/__init__.py | 168 -------------- kapitan/inputs/helm/build.sh | 31 --- kapitan/inputs/helm/cffi_build.py | 21 -- kapitan/inputs/helm/go.mod | 19 -- kapitan/inputs/helm/go.sum | 121 ---------- kapitan/inputs/helm/helm_binding.py | 8 - kapitan/inputs/helm/template.go | 333 ---------------------------- kapitan/targets.py | 1 + pyproject.toml | 1 - requirements.txt | 1 - tests/test_helm_input.py | 13 +- 18 files changed, 135 insertions(+), 794 deletions(-) create mode 100644 kapitan/inputs/helm.py delete mode 100644 kapitan/inputs/helm/__init__.py delete mode 100755 kapitan/inputs/helm/build.sh delete mode 100644 kapitan/inputs/helm/cffi_build.py delete mode 100644 kapitan/inputs/helm/go.mod delete mode 100644 kapitan/inputs/helm/go.sum delete mode 100644 kapitan/inputs/helm/helm_binding.py delete mode 100644 kapitan/inputs/helm/template.go diff --git a/.travis.yml b/.travis.yml index 8b76c4ef2..a61a3d897 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,10 +25,6 @@ before_install: - sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 762E3157 # Loop until update succeeds (timeouts can occur) - travis_retry $(! sudo apt-get -qq update 2>&1 | grep Failed) - - sudo apt-get install -y golang-1.14 - - export PATH="/usr/lib/go-1.14/bin:$PATH" - - export GOROOT=/usr/lib/go-1.14 - - go version - sudo apt-get install -y gnupg2 git curl # Install Helm Binary - curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 @@ -40,7 +36,6 @@ install: - pip3 install coverage black script: - - make build_helm_binding - make test && make test_coverage after_success: diff --git a/Dockerfile b/Dockerfile index c7590c45e..90eb0b303 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,24 +1,14 @@ -# First build the Helm binding -FROM golang:1.14.4-stretch AS helm-builder +# Build the virtualenv for Kapitan +FROM python:3.7-slim-stretch AS python-builder RUN mkdir /kapitan WORKDIR /kapitan -COPY ./kapitan/inputs/helm ./kapitan/inputs/helm -RUN chmod +x ./kapitan/inputs/helm/build.sh \ - && ./kapitan/inputs/helm/build.sh - COPY ./kapitan ./kapitan COPY ./MANIFEST.in ./MANIFEST.in COPY ./requirements.txt ./requirements.txt COPY ./setup.py ./setup.py -# Build the virtualenv for Kapitan -FROM python:3.7-slim-stretch AS python-builder - -COPY --from=helm-builder /kapitan /kapitan -WORKDIR /kapitan - ENV PATH="/opt/venv/bin:${PATH}" RUN apt-get update \ @@ -27,7 +17,6 @@ RUN apt-get update \ && python -m venv /opt/venv \ && pip install --upgrade pip yq wheel \ && pip install -r requirements.txt \ - && ./kapitan/inputs/helm/build.sh \ && pip install . # Install Helm diff --git a/Dockerfile.ci b/Dockerfile.ci index 6c28583b9..617dae89b 100644 --- a/Dockerfile.ci +++ b/Dockerfile.ci @@ -7,21 +7,6 @@ FROM bitnami/jsonnet:0.14.0 as jsonnet-binary # /bin/promtool FROM quay.io/prometheus/prometheus:v2.15.2 AS prometheus-binary -# Build the Helm binding -FROM golang:1.14.4-stretch AS helm-builder - -RUN mkdir /kapitan -WORKDIR /kapitan - -COPY ./kapitan/inputs/helm ./kapitan/inputs/helm -RUN chmod +x ./kapitan/inputs/helm/build.sh \ - && ./kapitan/inputs/helm/build.sh - -COPY ./kapitan ./kapitan -COPY ./MANIFEST.in ./MANIFEST.in -COPY ./requirements.txt ./requirements.txt -COPY ./setup.py ./setup.py - # Build final image FROM python:3.7-buster @@ -33,7 +18,13 @@ COPY --from=terraform-binary /bin/terraform /usr/bin/terraform COPY --from=jsonnet-binary /opt/bitnami/jsonnet/bin/jsonnet /usr/bin/jsonnet COPY --from=jsonnet-binary /opt/bitnami/jsonnet/bin/jsonnetfmt /usr/bin/jsonnetfmt COPY --from=prometheus-binary /bin/promtool /usr/bin/promtool -COPY --from=helm-builder /kapitan /kapitan + +RUN mkdir /kapitan + +COPY ./kapitan /kapitan/kapitan +COPY ./MANIFEST.in /kapitan/MANIFEST.in +COPY ./requirements.txt /kapitan/requirements.txt +COPY ./setup.py /kapitan/setup.py RUN apt-get update \ && apt-get install --no-install-recommends -y \ @@ -68,7 +59,6 @@ RUN apt-get update \ && python -m venv /opt/venv \ && pip install --upgrade pip yq wheel \ && pip install -r ./kapitan/requirements.txt \ - && ./kapitan/kapitan/inputs/helm/build.sh \ && pip install ./kapitan \ && rm -rf ./kapitan \ && curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 \ diff --git a/MANIFEST.in b/MANIFEST.in index f9a9aa1cd..64d4374a7 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -2,4 +2,3 @@ recursive-include kapitan/reclass/reclass/ *.py include kapitan/lib/*.libjsonnet include requirements.txt recursive-include kapitan/inputs/templates * -recursive-include kapitan/inputs/helm * diff --git a/Pipfile b/Pipfile index 6ad0a82c2..a4bf3e0e2 100644 --- a/Pipfile +++ b/Pipfile @@ -16,7 +16,6 @@ boto3 = ">=1.14.3" requests = "==2.25.0" addict = "==2.2.1" yamllint = ">=1.23.0" -cffi = "*" rfc3987 = "==1.3.8" hvac = "==0.10.5" docker = "==4.3.1" diff --git a/Pipfile.lock b/Pipfile.lock index 4845845b2..2d6d3e7de 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -63,49 +63,6 @@ ], "version": "==2020.12.5" }, - "cffi": { - "hashes": [ - "sha256:005a36f41773e148deac64b08f233873a4d0c18b053d37da83f6af4d9087b813", - "sha256:0857f0ae312d855239a55c81ef453ee8fd24136eaba8e87a2eceba644c0d4c06", - "sha256:1071534bbbf8cbb31b498d5d9db0f274f2f7a865adca4ae429e147ba40f73dea", - "sha256:158d0d15119b4b7ff6b926536763dc0714313aa59e320ddf787502c70c4d4bee", - "sha256:1f436816fc868b098b0d63b8920de7d208c90a67212546d02f84fe78a9c26396", - "sha256:2894f2df484ff56d717bead0a5c2abb6b9d2bf26d6960c4604d5c48bbc30ee73", - "sha256:29314480e958fd8aab22e4a58b355b629c59bf5f2ac2492b61e3dc06d8c7a315", - "sha256:34eff4b97f3d982fb93e2831e6750127d1355a923ebaeeb565407b3d2f8d41a1", - "sha256:35f27e6eb43380fa080dccf676dece30bef72e4a67617ffda586641cd4508d49", - "sha256:3d3dd4c9e559eb172ecf00a2a7517e97d1e96de2a5e610bd9b68cea3925b4892", - "sha256:43e0b9d9e2c9e5d152946b9c5fe062c151614b262fda2e7b201204de0b99e482", - "sha256:48e1c69bbacfc3d932221851b39d49e81567a4d4aac3b21258d9c24578280058", - "sha256:51182f8927c5af975fece87b1b369f722c570fe169f9880764b1ee3bca8347b5", - "sha256:58e3f59d583d413809d60779492342801d6e82fefb89c86a38e040c16883be53", - "sha256:5de7970188bb46b7bf9858eb6890aad302577a5f6f75091fd7cdd3ef13ef3045", - "sha256:65fa59693c62cf06e45ddbb822165394a288edce9e276647f0046e1ec26920f3", - "sha256:69e395c24fc60aad6bb4fa7e583698ea6cc684648e1ffb7fe85e3c1ca131a7d5", - "sha256:6c97d7350133666fbb5cf4abdc1178c812cb205dc6f41d174a7b0f18fb93337e", - "sha256:6e4714cc64f474e4d6e37cfff31a814b509a35cb17de4fb1999907575684479c", - "sha256:72d8d3ef52c208ee1c7b2e341f7d71c6fd3157138abf1a95166e6165dd5d4369", - "sha256:8ae6299f6c68de06f136f1f9e69458eae58f1dacf10af5c17353eae03aa0d827", - "sha256:8b198cec6c72df5289c05b05b8b0969819783f9418e0409865dac47288d2a053", - "sha256:99cd03ae7988a93dd00bcd9d0b75e1f6c426063d6f03d2f90b89e29b25b82dfa", - "sha256:9cf8022fb8d07a97c178b02327b284521c7708d7c71a9c9c355c178ac4bbd3d4", - "sha256:9de2e279153a443c656f2defd67769e6d1e4163952b3c622dcea5b08a6405322", - "sha256:9e93e79c2551ff263400e1e4be085a1210e12073a31c2011dbbda14bda0c6132", - "sha256:9ff227395193126d82e60319a673a037d5de84633f11279e336f9c0f189ecc62", - "sha256:a465da611f6fa124963b91bf432d960a555563efe4ed1cc403ba5077b15370aa", - "sha256:ad17025d226ee5beec591b52800c11680fca3df50b8b29fe51d882576e039ee0", - "sha256:afb29c1ba2e5a3736f1c301d9d0abe3ec8b86957d04ddfa9d7a6a42b9367e396", - "sha256:b85eb46a81787c50650f2392b9b4ef23e1f126313b9e0e9013b35c15e4288e2e", - "sha256:bb89f306e5da99f4d922728ddcd6f7fcebb3241fc40edebcb7284d7514741991", - "sha256:cbde590d4faaa07c72bf979734738f328d239913ba3e043b1e98fe9a39f8b2b6", - "sha256:cd2868886d547469123fadc46eac7ea5253ea7fcb139f12e1dfc2bbd406427d1", - "sha256:d42b11d692e11b6634f7613ad8df5d6d5f8875f5d48939520d351007b3c13406", - "sha256:f2d45f97ab6bb54753eab54fffe75aaf3de4ff2341c9daee1987ee1837636f1d", - "sha256:fd78e5fee591709f32ef6edb9a015b4aa1a5022598e36227500c8f4e02328d9c" - ], - "index": "pypi", - "version": "==1.14.5" - }, "chardet": { "hashes": [ "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", diff --git a/kapitan/inputs/helm.py b/kapitan/inputs/helm.py new file mode 100644 index 000000000..dae348c8b --- /dev/null +++ b/kapitan/inputs/helm.py @@ -0,0 +1,123 @@ +import logging +import os +import tempfile + +import yaml +from kapitan.errors import HelmTemplateError +from kapitan.helm_cli import helm_cli +from kapitan.inputs.base import InputType, CompiledFile + +logger = logging.getLogger(__name__) + + +class Helm(InputType): + def __init__(self, compile_path, search_paths, ref_controller): + super().__init__("helm", compile_path, search_paths, ref_controller) + self.helm_values_file = None + self.helm_values_files = [] + self.helm_params = {} + self.kube_version = "" + + def dump_helm_values(self, helm_values): + """dump helm values into a yaml file whose path will be passed over to Go helm code""" + _, self.helm_values_file = tempfile.mkstemp(".helm_values.yml", text=True) + with open(self.helm_values_file, "w") as fp: + yaml.safe_dump(helm_values, fp) + + def set_helm_values_files(self, helm_values_files): + self.helm_values_files = helm_values_files + + def set_helm_params(self, helm_params): + self.helm_params = helm_params + + def set_kube_version(self, kube_version): + self.kube_version = kube_version + + def compile_file(self, file_path, compile_path, ext_vars, **kwargs): + """ + Render templates in file_path/templates and write to compile_path. + file_path must be a directory containing helm chart. + kwargs: + reveal: default False, set to reveal refs on compile + target_name: default None, set to current target being compiled + """ + reveal = kwargs.get("reveal", False) + target_name = kwargs.get("target_name", None) + + temp_dir = tempfile.mkdtemp() + os.makedirs(os.path.dirname(compile_path), exist_ok=True) + # save the template output to temp dir first + error_message = self.render_chart( + chart_dir=file_path, + output_path=temp_dir, + helm_values_file=self.helm_values_file, + helm_values_files=self.helm_values_files, + **self.helm_params, + ) + if error_message: + raise HelmTemplateError(error_message) + + walk_root_files = os.walk(temp_dir) + for current_dir, _, files in walk_root_files: + for file in files: # go through all the template files + rel_dir = os.path.relpath(current_dir, temp_dir) + rel_file_name = os.path.join(rel_dir, file) + full_file_name = os.path.join(current_dir, file) + with open(full_file_name, "r") as f: + item_path = os.path.join(compile_path, rel_file_name) + os.makedirs(os.path.dirname(item_path), exist_ok=True) + with CompiledFile( + item_path, + self.ref_controller, + mode="w", + reveal=reveal, + target_name=target_name, + ) as fp: + yml_obj = list(yaml.safe_load_all(f)) + fp.write_yaml(yml_obj) + logger.debug("Wrote file %s to %s", full_file_name, item_path) + + self.helm_values_file = None # reset this + self.helm_params = {} + self.helm_values_files = [] + + def default_output_type(self): + return None + + def render_chart(self, chart_dir, output_path, **kwargs): + args = ["template"] + """renders helm chart located at chart_dir, and stores the output to output_path""" + if kwargs.get("helm_values_files", []): + for file_name in kwargs["helm_values_files"]: + args.append("-f") + args.append(file_name) + + if kwargs.get("helm_values_file", None): + args.append("-f") + args.append(kwargs["helm_values_file"]) + + if kwargs.get("namespace", None): + args.append("-n") + args.append(kwargs["namespace"]) + + args.append("--output-dir") + args.append(output_path) + + if self.kube_version: + args.append("--api-versions") + args.append(self.kube_version) + + if kwargs.get("validate", False): + args.append("--validate") + + if kwargs.get("name_template", None): + args.append("--name-template") + args.append(kwargs["name_template"]) + else: + args.append(kwargs.get("release_name", "--generate-name")) + + # uses absolute path to make sure helm interpret it as a + # local dir and not a chart_name that it should download. + args.append(os.path.abspath(chart_dir)) + + return helm_cli(args) diff --git a/kapitan/inputs/helm/__init__.py b/kapitan/inputs/helm/__init__.py deleted file mode 100644 index 706aea8ed..000000000 --- a/kapitan/inputs/helm/__init__.py +++ /dev/null @@ -1,168 +0,0 @@ -import logging -import os -from kapitan.errors import HelmBindingUnavailableError, HelmTemplateError -from kapitan.inputs.base import InputType, CompiledFile - -import tempfile -import platform -import yaml - -try: - from kapitan.inputs.helm.helm_binding import ffi -except ImportError: - pass # make this feature optional - -logger = logging.getLogger(__name__) - - -class Helm(InputType): - def __init__(self, compile_path, search_paths, ref_controller): - super().__init__("helm", compile_path, search_paths, ref_controller) - self.helm_values_file = None - self.helm_values_files = [] - self.helm_params = {} - self.kube_version = "" - self.lib = self.initialise_binding() - - def initialise_binding(self): - """returns the dl_opened library (.so file) if exists, otherwise None""" - if platform.system() not in ("Linux", "Darwin"): # TODO: later add binding for Mac - return None - # binding_path is kapitan/inputs/helm/libtemplate.so - binding_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "libtemplate.so") - if not os.path.exists(binding_path): - logger.debug("The helm binding does not exist at %s", binding_path) - return None - try: - lib = ffi.dlopen(binding_path) - except (NameError, OSError) as e: - raise HelmBindingUnavailableError( - "There was an error opening helm binding. " "Refer to the exception below:\n" + str(e) - ) - return lib - - def dump_helm_values(self, helm_values): - """dump helm values into a yaml file whose path will be passed over to Go helm code""" - _, self.helm_values_file = tempfile.mkstemp(".helm_values.yml", text=True) - with open(self.helm_values_file, "w") as fp: - yaml.safe_dump(helm_values, fp) - - def set_helm_values_files(self, helm_values_files): - self.helm_values_files = helm_values_files - - def set_helm_params(self, helm_params): - self.helm_params = helm_params - - def set_kube_version(self, kube_version): - self.kube_version = kube_version - - def compile_file(self, file_path, compile_path, ext_vars, **kwargs): - """ - Render templates in file_path/templates and write to compile_path. - file_path must be a directory containing helm chart. - kwargs: - reveal: default False, set to reveal refs on compile - target_name: default None, set to current target being compiled - """ - if not self.lib: - raise HelmBindingUnavailableError( - "Helm binding is not supported for {}." - "\nOr the binding does not exist.".format(platform.system()) - ) - - reveal = kwargs.get("reveal", False) - target_name = kwargs.get("target_name", None) - - temp_dir = tempfile.mkdtemp() - os.makedirs(os.path.dirname(compile_path), exist_ok=True) - # save the template output to temp dir first - error_message = self.render_chart( - chart_dir=file_path, - output_path=temp_dir, - helm_values_file=self.helm_values_file, - helm_values_files=self.helm_values_files, - **self.helm_params, - ) - if error_message: - raise HelmTemplateError(error_message) - - walk_root_files = os.walk(temp_dir) - for current_dir, _, files in walk_root_files: - for file in files: # go through all the template files - rel_dir = os.path.relpath(current_dir, temp_dir) - rel_file_name = os.path.join(rel_dir, file) - full_file_name = os.path.join(current_dir, file) - with open(full_file_name, "r") as f: - item_path = os.path.join(compile_path, rel_file_name) - os.makedirs(os.path.dirname(item_path), exist_ok=True) - with CompiledFile( - item_path, self.ref_controller, mode="w", reveal=reveal, target_name=target_name - ) as fp: - yml_obj = list(yaml.safe_load_all(f)) - fp.write_yaml(yml_obj) - logger.debug("Wrote file %s to %s", full_file_name, item_path) - - self.helm_values_file = None # reset this - self.helm_params = {} - self.helm_values_files = [] - - def default_output_type(self): - return None - - def render_chart(self, chart_dir, output_path, **kwargs): - """renders helm chart located at chart_dir, and stores the output to output_path""" - if kwargs.get("helm_values_file", None): - helm_values_file = ffi.new("char[]", kwargs["helm_values_file"].encode("ascii")) - else: - # the value in kwargs can be None - helm_values_file = ffi.new("char[]", "".encode("ascii")) - - if kwargs.get("namespace", None): - namespace = ffi.new("char[]", kwargs["namespace"].encode("ascii")) - else: - namespace = ffi.new("char[]", "default".encode("ascii")) - - if kwargs.get("release_name", None): - release_name = ffi.new("char[]", kwargs["release_name"].encode("ascii")) - else: - release_name = ffi.new("char[]", "".encode("ascii")) - - if kwargs.get("name_template", None): - name_template = ffi.new("char[]", kwargs["name_template"].encode("ascii")) - else: - name_template = ffi.new("char[]", "".encode("ascii")) - - char_dir_buf = ffi.new("char[]", chart_dir.encode("ascii")) - output_path_buf = ffi.new("char[]", output_path.encode("ascii")) - kube_version = ffi.new("char[]", self.kube_version.encode("ascii")) - - # as noted in cffi documentation, once the reference to the pointer is out of scope, the data is freed. - # to prevent that from happening with these dynamic arrays, we create a 'keep_pointers_alive' dict - # https://cffi.readthedocs.io/en/latest/using.html#working-with-pointers-structures-and-arrays - helm_values_files = [] - keep_pointers_alive = dict() - if kwargs.get("helm_values_files", []): - for i in range(len(kwargs["helm_values_files"])): - file_name = kwargs["helm_values_files"][i] - - ptr_to_encoded_file_name = ffi.new("char[]", file_name.encode("ascii")) - keep_pointers_alive[file_name + str(i)] = ptr_to_encoded_file_name - helm_values_files.append(ptr_to_encoded_file_name) - - helm_values_files_len = ffi.cast("int", len(helm_values_files)) - helm_values_files = ffi.new("char *[]", helm_values_files) - - c_error_message = self.lib.renderChart( - char_dir_buf, - output_path_buf, - helm_values_file, - namespace, - release_name, - name_template, - helm_values_files, - helm_values_files_len, - kube_version, - ) - error_message = ffi.string(c_error_message) # this creates a copy as bytes - self.lib.free(c_error_message) # free the char* returned by go - return error_message.decode("utf-8") # empty if no error diff --git a/kapitan/inputs/helm/build.sh b/kapitan/inputs/helm/build.sh deleted file mode 100755 index e7afd9c47..000000000 --- a/kapitan/inputs/helm/build.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env bash - -cd $(dirname "$0") -pwd - -so_name="libtemplate.so" - -# Compile the binding if a Go runtime exists -if [[ -z $(which go) ]]; then - echo "[WARN] go is not available on this system -- skipping Helm binding build!" -else - go build -buildmode=c-shared -o $so_name template.go -fi - -# Validate that the compiled binding exists -if [[ -e $so_name ]]; then - echo "[INFO] $so_name built successfully or already exists" -else - echo "[ERROR] $so_name does not exist!" - exit 1 -fi - -# Compile the Python ffi binding if Python is available -if [[ -z $(which python3) ]]; then - echo "[WARN] python3 is not available on this system -- skipping cffi build!" -else - echo "[INFO] Building the Python binding using cffi" - python3 cffi_build.py -fi - -exit 0 diff --git a/kapitan/inputs/helm/cffi_build.py b/kapitan/inputs/helm/cffi_build.py deleted file mode 100644 index 22fab36c9..000000000 --- a/kapitan/inputs/helm/cffi_build.py +++ /dev/null @@ -1,21 +0,0 @@ -from cffi import FFI - - -def main(): - ffi = FFI() - - # declare functions to export - ffi.cdef( - """ - char* renderChart(char* p0, char* p1, char* p2, char* p3, char* p4, char* p5, char** p6, int p7, char* p8); - void free(void* ptr); - """ - ) - - ffi.set_source("helm_binding", None) # specify name for importing this module - - ffi.compile(verbose=True) - - -if __name__ == "__main__": - main() diff --git a/kapitan/inputs/helm/go.mod b/kapitan/inputs/helm/go.mod deleted file mode 100644 index 24d498541..000000000 --- a/kapitan/inputs/helm/go.mod +++ /dev/null @@ -1,19 +0,0 @@ -module inhelm - -go 1.14 - -require ( - github.com/BurntSushi/toml v0.3.1 // indirect - github.com/Masterminds/goutils v1.1.0 // indirect - github.com/Masterminds/semver v1.4.2 // indirect - github.com/Masterminds/sprig v2.20.0+incompatible - github.com/cyphar/filepath-securejoin v0.2.2 // indirect - github.com/ghodss/yaml v1.0.0 - github.com/gobwas/glob v0.2.3 // indirect - github.com/huandu/xstrings v1.2.0 // indirect - github.com/imdario/mergo v0.3.7 // indirect - github.com/pkg/errors v0.8.1 // indirect - golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc // indirect - k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655 - k8s.io/helm v2.14.2+incompatible -) diff --git a/kapitan/inputs/helm/go.sum b/kapitan/inputs/helm/go.sum deleted file mode 100644 index 9f962587d..000000000 --- a/kapitan/inputs/helm/go.sum +++ /dev/null @@ -1,121 +0,0 @@ -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg= -github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc= -github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/Masterminds/sprig v2.20.0+incompatible h1:dJTKKuUkYW3RMFdQFXPU/s6hg10RgctmTjRcbZ98Ap8= -github.com/Masterminds/sprig v2.20.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= -github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= -github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg= -github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= -github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= -github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= -github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= -github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= -github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= -github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= -github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= -github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= -github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huandu/xstrings v1.2.0 h1:yPeWdRnmynF7p+lLYz0H2tthW9lqhMJrQV/U7yy4wX0= -github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= -github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI= -github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc h1:c0o/qxkaO2LF5t6fQrT4b5hzyggAkLLlCUjqfRxd8Q4= -golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655 h1:CS1tBQz3HOXiseWZu6ZicKX361CZLT97UFnnPx0aqBw= -k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655/go.mod h1:nL6pwRT8NgfF8TT68DBI8uEePRt89cSvoXUVqbkWHq4= -k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/helm v2.14.2+incompatible h1:kT4JDDvxvp/AR7sWTuTnv58SzVYP0KHIGFIXThSp7gc= -k8s.io/helm v2.14.2+incompatible/go.mod h1:LZzlS4LQBHfciFOurYBFkCMTaZ0D1l+p0teMg7TSULI= -k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.4.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= -sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= -sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/kapitan/inputs/helm/helm_binding.py b/kapitan/inputs/helm/helm_binding.py deleted file mode 100644 index fbcc83f03..000000000 --- a/kapitan/inputs/helm/helm_binding.py +++ /dev/null @@ -1,8 +0,0 @@ -# auto-generated file -import _cffi_backend - -ffi = _cffi_backend.FFI('helm_binding', - _version = 0x2601, - _types = b'\x00\x00\x01\x0D\x00\x00\x0E\x03\x00\x00\x01\x11\x00\x00\x01\x11\x00\x00\x01\x11\x00\x00\x01\x11\x00\x00\x01\x11\x00\x00\x01\x03\x00\x00\x07\x01\x00\x00\x01\x11\x00\x00\x00\x0F\x00\x00\x0F\x0D\x00\x00\x0F\x03\x00\x00\x00\x0F\x00\x00\x02\x01\x00\x00\x00\x01', - _globals = (b'\x00\x00\x0B\x23free',0,b'\x00\x00\x00\x23renderChart',0), -) diff --git a/kapitan/inputs/helm/template.go b/kapitan/inputs/helm/template.go deleted file mode 100644 index 404122d28..000000000 --- a/kapitan/inputs/helm/template.go +++ /dev/null @@ -1,333 +0,0 @@ -package main - -import "C" - -import ( - "bytes" - "fmt" - "io/ioutil" - "os" - "path" - "path/filepath" - "regexp" - "strings" - "text/template" - "unsafe" - - "github.com/Masterminds/sprig" - "github.com/ghodss/yaml" - "k8s.io/apimachinery/pkg/util/validation" - "k8s.io/helm/pkg/chartutil" - "k8s.io/helm/pkg/manifest" - "k8s.io/helm/pkg/proto/hapi/chart" - "k8s.io/helm/pkg/renderutil" - "k8s.io/helm/pkg/strvals" -) - -const defaultDirectoryPermission_c = 0755 - -var ( - whitespaceRegex_c = regexp.MustCompile(`^\s*$`) - // defaultKubeVersion is the default value of --kube-version flag - defaultKubeVersion_c = fmt.Sprintf("%s.%s", chartutil.DefaultKubeVersion.Major, chartutil.DefaultKubeVersion.Minor) -) - -// copied from install.go -type valueFiles []string - -func (v *valueFiles) String() string { - return fmt.Sprint(*v) -} - -func (v *valueFiles) Type() string { - return "valueFiles" -} - -func (v *valueFiles) Set(value string) error { - for _, filePath := range strings.Split(value, ",") { - *v = append(*v, filePath) - } - return nil -} - -//readFile load a file from the local directory. remote file is disabled. -func readFile(filePath string) ([]byte, error) { - return ioutil.ReadFile(filePath) -} - -// Merges source and destination map, preferring values from the source map -func mergeValues(dest map[string]interface{}, src map[string]interface{}) map[string]interface{} { - for k, v := range src { - // If the key doesn't exist already, then just set the key to that value - if _, exists := dest[k]; !exists { - dest[k] = v - continue - } - nextMap, ok := v.(map[string]interface{}) - // If it isn't another map, overwrite the value - if !ok { - dest[k] = v - continue - } - // Edge case: If the key exists in the destination, but isn't a map - destMap, isMap := dest[k].(map[string]interface{}) - // If the source map has a map for this key, prefer it - if !isMap { - dest[k] = v - continue - } - // If we got to this point, it is a map in both, so merge them - dest[k] = mergeValues(destMap, nextMap) - } - return dest -} - -// vals merges values from files specified via -f/--values and -// directly via --set or --set-string or --set-file, marshaling them to YAML -func vals(valueFiles valueFiles, values []string, stringValues []string, fileValues []string) ([]byte, error) { - base := map[string]interface{}{} - - // User specified a values files via -f/--values - for _, filePath := range valueFiles { - currentMap := map[string]interface{}{} - - var bytes []byte - var err error - if strings.TrimSpace(filePath) == "-" { - bytes, err = ioutil.ReadAll(os.Stdin) - } else { - bytes, err = readFile(filePath) - } - - if err != nil { - return []byte{}, err - } - - if err := yaml.Unmarshal(bytes, ¤tMap); err != nil { - return []byte{}, fmt.Errorf("failed to parse %s: %s", filePath, err) - } - // Merge with the previous map - base = mergeValues(base, currentMap) - } - - // User specified a value via --set - for _, value := range values { - if err := strvals.ParseInto(value, base); err != nil { - return []byte{}, fmt.Errorf("failed parsing --set data: %s", err) - } - } - - // User specified a value via --set-string - for _, value := range stringValues { - if err := strvals.ParseIntoString(value, base); err != nil { - return []byte{}, fmt.Errorf("failed parsing --set-string data: %s", err) - } - } - - // User specified a value via --set-file - for _, value := range fileValues { - reader := func(rs []rune) (interface{}, error) { - bytes, err := readFile(string(rs)) - return string(bytes), err - } - if err := strvals.ParseIntoFile(value, base, reader); err != nil { - return []byte{}, fmt.Errorf("failed parsing --set-file data: %s", err) - } - } - - return yaml.Marshal(base) -} - -// generates name using Sprig template -func generateName(nameTemplate string) (string, error) { - t, err := template.New("name-template").Funcs(sprig.TxtFuncMap()).Parse(nameTemplate) - if err != nil { - return "", err - } - var b bytes.Buffer - err = t.Execute(&b, nil) - if err != nil { - return "", err - } - return b.String(), nil -} - -//export renderChart -func renderChart(c_chartpath, c_outputDir, c_valueFile, c_namespace, c_releaseName, c_nameTemplate *C.char, c_valuesFiles **C.char, c_valuesFilesSize C.int, c_kubeVersion *C.char) *C.char { - chartPath := C.GoString(c_chartpath) - outputDir := C.GoString(c_outputDir) - valueFile := C.GoString(c_valueFile) - // values in YAML file - var valueFiles []string - if valueFile != "" { - valueFiles = append(valueFiles, valueFile) - } - - // https://stackoverflow.com/questions/47354663/access-c-array-of-type-const-char-from-go - size := int(c_valuesFilesSize) - cStrings := (*[1 << 30]*C.char)(unsafe.Pointer(c_valuesFiles))[:size:size] - for _, cString := range cStrings { - valueFiles = append(valueFiles, C.GoString(cString)) - } - - var values []string - // to force string values - var stringValues []string - var fileValues []string - nameTemplate := C.GoString(c_nameTemplate) - releaseName := C.GoString(c_releaseName) // will be overwritten by nameTemplate if set - namespace := C.GoString(c_namespace) - kubeVersion := C.GoString(c_kubeVersion) - if kubeVersion == "" { - kubeVersion = defaultKubeVersion_c - } - - // particular template files to render - var renderFiles []string - showNotes := false - - rawVals, err := vals(valueFiles, values, stringValues, fileValues) - if err != nil { - return C.CString(err.Error()) - } - config := &chart.Config{Raw: string(rawVals), Values: map[string]*chart.Value{}} - - // If template is specified, try to run the template. - if nameTemplate != "" { - releaseName, err = generateName(nameTemplate) - if err != nil { - return C.CString(err.Error()) - } - } - - if msgs := validation.IsDNS1123Subdomain(releaseName); releaseName != "" && len(msgs) > 0 { - return C.CString(fmt.Errorf("release name %s is invalid: %s", releaseName, strings.Join(msgs, ";")).Error()) - } - - // Check chart requirements to make sure all dependencies are present in /charts - c, err := chartutil.Load(chartPath) - if err != nil { - return C.CString(err.Error()) - } - - renderOpts := renderutil.Options{ - ReleaseOptions: chartutil.ReleaseOptions{ - Name: releaseName, - IsInstall: true, - IsUpgrade: false, - Time: nil, - Namespace: namespace, - }, - KubeVersion: kubeVersion, - } - - renderedTemplates, err := renderutil.Render(c, config, renderOpts) - if err != nil { - return C.CString(err.Error()) - } - - listManifests := manifest.SplitManifests(renderedTemplates) - var manifestsToRender []manifest.Manifest - - // if we have a list of files to render, then check that each of the - // provided files exists in the chart. - if len(renderFiles) > 0 { - for _, f := range renderFiles { - missing := true - if !filepath.IsAbs(f) { - newF, err := filepath.Abs(filepath.Join(chartPath, f)) - if err != nil { - C.CString(fmt.Errorf("could not turn template path %s into absolute path: %s", f, err).Error()) - } - f = newF - } - - for _, manifest := range listManifests { - // manifest.Name is rendered using linux-style filepath separators on Windows as - // well as macOS/linux. - manifestPathSplit := strings.Split(manifest.Name, "/") - // remove the chart name from the path - manifestPathSplit = manifestPathSplit[1:] - toJoin := append([]string{chartPath}, manifestPathSplit...) - manifestPath := filepath.Join(toJoin...) - - // if the filepath provided matches a manifest path in the - // chart, render that manifest - if f == manifestPath { - manifestsToRender = append(manifestsToRender, manifest) - missing = false - } - } - if missing { - return C.CString(fmt.Errorf("could not find template %s in chart", f).Error()) - } - } - } else { - // no renderFiles provided, render all manifests in the chart - manifestsToRender = listManifests - } - - for _, m := range manifestsToRender { - data := m.Content - b := filepath.Base(m.Name) - if !showNotes && b == "NOTES.txt" { - continue - } - if strings.HasPrefix(b, "_") { - continue - } - - if outputDir != "" { - // blank template after execution - if whitespaceRegex_c.MatchString(data) { - continue - } - err = writeToFile_c(outputDir, m.Name, data) - if err != nil { - C.CString(err.Error()) - } - continue - } - fmt.Printf("---\n# Source: %s\n", m.Name) - fmt.Println(data) - } - return C.CString("") // return empty string if no error -} - -// write the to / -func writeToFile_c(outputDir string, name string, data string) error { - outfileName := strings.Join([]string{outputDir, name}, string(filepath.Separator)) - err := ensureDirectoryForFile_c(outfileName) - if err != nil { - return err - } - - f, err := os.Create(outfileName) - if err != nil { - return err - } - - defer f.Close() - - _, err = f.WriteString(fmt.Sprintf("---\n# Source: %s\n%s", name, data)) - - if err != nil { - return err - } - - return nil -} - -// check if the directory exists to create file. creates if don't exists -func ensureDirectoryForFile_c(file string) error { - baseDir := path.Dir(file) - _, err := os.Stat(baseDir) - if err != nil && !os.IsNotExist(err) { - return err - } - - return os.MkdirAll(baseDir, defaultDirectoryPermission_c) -} - -// this is required to build this as shared object file using cgo -func main() {} diff --git a/kapitan/targets.py b/kapitan/targets.py index ddde6aba6..b83526da2 100644 --- a/kapitan/targets.py +++ b/kapitan/targets.py @@ -548,6 +548,7 @@ def valid_target_obj(target_obj, require_compile=True): "namespace": {"type": "string"}, "name_template": {"type": "string"}, "release_name": {"type": "string"}, + "validate": {"type": "boolean"}, }, "additionalProperties": False, }, diff --git a/pyproject.toml b/pyproject.toml index 685de9c07..e36f04d05 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,6 @@ exclude = ''' ( /( .*reclass.* - | .*helm_binding.py | .*version.py ) ) diff --git a/requirements.txt b/requirements.txt index de68c160d..d31d1e127 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,7 +14,6 @@ urllib3==1.25.10 requests==2.23.0 addict==2.2.1 yamllint>=1.23.0 -cffi rfc3987==1.3.8 GitPython==3.1.3 hvac==0.10.4 diff --git a/tests/test_helm_input.py b/tests/test_helm_input.py index 51c2597a6..bd256f995 100644 --- a/tests/test_helm_input.py +++ b/tests/test_helm_input.py @@ -16,16 +16,7 @@ from kapitan.cli import main from kapitan.inputs.helm import Helm -helm_binding_exists = True -try: - from kapitan.inputs.helm.helm_binding import ( - ffi, - ) # this statement will raise ImportError if binding not available -except ImportError: - helm_binding_exists = False - -@unittest.skipUnless(helm_binding_exists, "helm binding is not available") class HelmInputTest(unittest.TestCase): def setUp(self): os.chdir(os.path.join("tests", "test_resources")) @@ -48,7 +39,7 @@ def test_error_invalid_char_dir(self): temp_dir = tempfile.mkdtemp() helm = Helm(None, None, None) error_message = helm.render_chart(chart_path, temp_dir) - self.assertTrue("no such file or directory" in error_message) + self.assertTrue("path" in error_message and "not found" in error_message) def test_compile_chart(self): temp = tempfile.mkdtemp() @@ -128,7 +119,7 @@ def test_compile_with_helm_values(self): with open(controller_deployment_file, "r") as fp: manifest = yaml.safe_load(fp.read()) name = manifest["metadata"]["name"] - self.assertEqual(name, "-nginx-ingress-my-controller") + self.assertEqual("RELEASE-NAME-nginx-ingress-my-controller", name) def test_compile_with_helm_values_files(self): temp = tempfile.mkdtemp() From be31e1cea49d1e1ed9cdeb6c15fad04d9803f8c7 Mon Sep 17 00:00:00 2001 From: Jean-Daniel Dupas Date: Tue, 9 Mar 2021 11:02:44 +0100 Subject: [PATCH 03/11] Ignore helm stdout. --- kapitan/helm_cli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kapitan/helm_cli.py b/kapitan/helm_cli.py index 188a8e393..18ec1982b 100644 --- a/kapitan/helm_cli.py +++ b/kapitan/helm_cli.py @@ -1,10 +1,10 @@ import subprocess -from subprocess import PIPE +from subprocess import PIPE, DEVNULL def helm_cli(args): try: - res = subprocess.run(args=["helm"] + args, stderr=PIPE) + res = subprocess.run(args=["helm"] + args, stderr=PIPE, stdout=DEVNULL) return res.stderr.decode() if res.returncode != 0 else "" except FileNotFoundError: return "helm binary not found. helm must be present in the PATH to use kapitan helm functionalities" From f77b11ee3fe4468a17dc48cacd79dc235080d30b Mon Sep 17 00:00:00 2001 From: Jean-Daniel Dupas Date: Tue, 9 Mar 2021 11:22:17 +0100 Subject: [PATCH 04/11] [helm] add include_crds and skip_tests options. --- docs/compile.md | 13 ++++++++----- kapitan/inputs/helm.py | 6 ++++++ kapitan/targets.py | 2 ++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/docs/compile.md b/docs/compile.md index d22d5b94c..2f9ef1b26 100644 --- a/docs/compile.md +++ b/docs/compile.md @@ -365,21 +365,24 @@ If the same keys exist in `helm_values` and in multiple specified `helm_values_f There is an example in the tests. The `monitoring-dev`(kapitan/tests/test_resources/inventory/targets/monitoring-dev.yml) and `monitoring-prd`(kapitan/tests/test_resources/inventory/targets/monitoring-prd.yml) targets both use the `monitoring`(tests/test_resources/inventory/classes/component/monitoring.yml) component. This component has helm chart input and takes a `common.yml` helm_values file which is "shared" by any target that uses the component and it also takes a dynamically defined file based on a kapitan variable defined in the target. -`helm_params` correspond to the options for `helm template` as follows: +`helm_params` correspond to the flags for `helm template` as follows: -- namespace: equivalent of `--namespace` option: note that due to the restriction on `helm template` command, specifying the namespace does not automatically add `metadata.namespace` property to the resources. Therefore, users are encourage to explicitly specify in all resources: +- `namespace`: equivalent of `--namespace` flag: note that due to the restriction on `helm template` command, specifying the namespace does not automatically add `metadata.namespace` property to the resources. Therefore, users are encourage to explicitly specify in all resources: ```yaml metadata: namespace: {{ .Release.Namespace }} # or any other custom values ``` -- name_template: equivalent of `--name-template` option -- release_name: equivalent of `--name` option +- `name_template`: equivalent of `--name-template` flag. +- `release_name`: equivalent of `name` parameter. Ignored if `name_template` is also specified. If neither `name_template` nor `release_name` are specified, the `--generate-name` flag is used to generate a name. +- `validate`: equivalent of `--validate` flag. +- `include_crds`: equivalent of `--include-crds` flag. Defaults to `true`. +- `skip_tests`: equivalent of `--skip-tests` flag. Defaults to `true`. See the [helm doc](https://helm.sh/docs/helm/#helm-template) for further detail. -`kube_version` optionally specifies the Kubernetes version to target when rendering the manifests from the chart, for example "1.16". As some charts generate manifests slightly differently depending on the target Kubernetes version (e.g. targeting different APIs), it may be useful to target a specific version. When not specified, the default version used is "1.12". +`kube_version` optionally specifies the Kubernetes version to target when rendering the manifests from the chart, for example "1.16". As some charts generate manifests slightly differently depending on the target Kubernetes version (e.g. targeting different APIs), it may be useful to target a specific version. #### Example diff --git a/kapitan/inputs/helm.py b/kapitan/inputs/helm.py index dae348c8b..b0cb9dcd1 100644 --- a/kapitan/inputs/helm.py +++ b/kapitan/inputs/helm.py @@ -110,6 +110,12 @@ def render_chart(self, chart_dir, output_path, **kwargs): if kwargs.get("validate", False): args.append("--validate") + if kwargs.get("include_crds", True): + args.append("--include-crds") + + if kwargs.get("skip_tests", True): + args.append("--skip-tests") + if kwargs.get("name_template", None): args.append("--name-template") args.append(kwargs["name_template"]) diff --git a/kapitan/targets.py b/kapitan/targets.py index b83526da2..c0def6daf 100644 --- a/kapitan/targets.py +++ b/kapitan/targets.py @@ -549,6 +549,8 @@ def valid_target_obj(target_obj, require_compile=True): "name_template": {"type": "string"}, "release_name": {"type": "string"}, "validate": {"type": "boolean"}, + "include_crds": {"type": "boolean"}, + "skip_tests": {"type": "boolean"}, }, "additionalProperties": False, }, From f1f13442af44479b13cb1441a4c6027ce5cfbb96 Mon Sep 17 00:00:00 2001 From: Jean-Daniel Dupas Date: Tue, 9 Mar 2021 11:22:41 +0100 Subject: [PATCH 05/11] [helm] log helm commands arguments. --- kapitan/helm_cli.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kapitan/helm_cli.py b/kapitan/helm_cli.py index 18ec1982b..e8b5ae288 100644 --- a/kapitan/helm_cli.py +++ b/kapitan/helm_cli.py @@ -1,9 +1,13 @@ +import logging import subprocess from subprocess import PIPE, DEVNULL +logger = logging.getLogger(__name__) + def helm_cli(args): try: + logger.debug("launching helm with arguments: %s", args) res = subprocess.run(args=["helm"] + args, stderr=PIPE, stdout=DEVNULL) return res.stderr.decode() if res.returncode != 0 else "" except FileNotFoundError: From af54f7f745329a8186991fb3906b50e0984c062c Mon Sep 17 00:00:00 2001 From: Jean-Daniel Dupas Date: Tue, 9 Mar 2021 19:53:27 +0100 Subject: [PATCH 06/11] [helm] Fix usage of undefined var. --- kapitan/dependency_manager/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kapitan/dependency_manager/base.py b/kapitan/dependency_manager/base.py index 4614e3feb..184a7f261 100644 --- a/kapitan/dependency_manager/base.py +++ b/kapitan/dependency_manager/base.py @@ -227,7 +227,7 @@ def fetch_helm_chart(dep_mapping, save_dir, force): if force or not exists_in_cache(cached_repo_path): fetch_helm_archive(source.repo, source.chart_name, source.version, cached_repo_path) else: - logger.debug("Using cached {} {}".format(item_type, cached_repo_path)) + logger.debug("Using cached helm chart at %s", cached_repo_path) for dep in deps: output_path = dep["output_path"] From 1f825a63ff64a31a7f837277d845d21fdd066c7b Mon Sep 17 00:00:00 2001 From: Jean-Daniel Dupas Date: Tue, 16 Mar 2021 10:39:00 +0100 Subject: [PATCH 07/11] Support arbitrary flags for helm input. --- docs/compile.md | 30 ++--- docs/external_dependencies.md | 6 +- kapitan/helm_cli.py | 8 +- kapitan/inputs/helm.py | 113 +++++++++++++----- kapitan/targets.py | 11 +- tests/test_helm_input.py | 9 +- .../targets/nginx-ingress-helm-params.yml | 2 +- 7 files changed, 113 insertions(+), 66 deletions(-) diff --git a/docs/compile.md b/docs/compile.md index 2f9ef1b26..ce3c11b06 100644 --- a/docs/compile.md +++ b/docs/compile.md @@ -298,9 +298,8 @@ parameters: helm_values_files: - helm_params: + name: namespace: - name_template: - release_name: - name: add-metadata-test-1 input_type: kadet output_path: ${test_1:output_path} @@ -352,10 +351,10 @@ parameters: helm_values_files: - helm_params: + name: namespace: - name_template: - release_name: - kube_version: + validate: true + … ``` `helm_values` is an object containing values specified that will override the default values in the input chart. This has exactly the same effect as specifying `--values custom_values.yml` for `helm template` command where `custom_values.yml` structure mirrors that of `helm_values`. @@ -365,24 +364,27 @@ If the same keys exist in `helm_values` and in multiple specified `helm_values_f There is an example in the tests. The `monitoring-dev`(kapitan/tests/test_resources/inventory/targets/monitoring-dev.yml) and `monitoring-prd`(kapitan/tests/test_resources/inventory/targets/monitoring-prd.yml) targets both use the `monitoring`(tests/test_resources/inventory/classes/component/monitoring.yml) component. This component has helm chart input and takes a `common.yml` helm_values file which is "shared" by any target that uses the component and it also takes a dynamically defined file based on a kapitan variable defined in the target. -`helm_params` correspond to the flags for `helm template` as follows: +`helm_params` correspond to the flags for `helm template`. Most flags that helm supports can be used here by replacing '-' by '_' in the flag name. -- `namespace`: equivalent of `--namespace` flag: note that due to the restriction on `helm template` command, specifying the namespace does not automatically add `metadata.namespace` property to the resources. Therefore, users are encourage to explicitly specify in all resources: +Flags without argument must have a boolean value, all other flags require a string value. + +Special flags: + +- `name`: equivalent of helm template `[NAME]` parameter. Ignored if `name_template` is also specified. If neither `name_template` nor `name` are specified, the `--generate-name` flag is used to generate a name. + +- `include_crds` and `skip_tests`: These flags are enabled by default and should be set to `false` to be removed. +- `debug`: prints the helm debug output in kapitan debug log. +- `namespace`: note that due to the restriction on `helm template` command, specifying the namespace does not automatically add `metadata.namespace` property to the resources. Therefore, users are encourage to explicitly specify in all resources: ```yaml metadata: namespace: {{ .Release.Namespace }} # or any other custom values ``` -- `name_template`: equivalent of `--name-template` flag. -- `release_name`: equivalent of `name` parameter. Ignored if `name_template` is also specified. If neither `name_template` nor `release_name` are specified, the `--generate-name` flag is used to generate a name. -- `validate`: equivalent of `--validate` flag. -- `include_crds`: equivalent of `--include-crds` flag. Defaults to `true`. -- `skip_tests`: equivalent of `--skip-tests` flag. Defaults to `true`. -See the [helm doc](https://helm.sh/docs/helm/#helm-template) for further detail. -`kube_version` optionally specifies the Kubernetes version to target when rendering the manifests from the chart, for example "1.16". As some charts generate manifests slightly differently depending on the target Kubernetes version (e.g. targeting different APIs), it may be useful to target a specific version. +See the [helm doc](https://helm.sh/docs/helm/helm_template/) for further detail. + #### Example diff --git a/docs/external_dependencies.md b/docs/external_dependencies.md index 660c5455b..a76bd0c00 100644 --- a/docs/external_dependencies.md +++ b/docs/external_dependencies.md @@ -213,8 +213,7 @@ parameters: enabled: false helm_params: namespace: monitoring - name_template: prometheus - release_name: prometheus + name: prometheus ``` Then run: @@ -266,8 +265,7 @@ parameters: enabled: false helm_params: namespace: monitoring - name_template: prometheus - release_name: prometheus + name: prometheus ``` Then run: diff --git a/kapitan/helm_cli.py b/kapitan/helm_cli.py index e8b5ae288..b6aeba598 100644 --- a/kapitan/helm_cli.py +++ b/kapitan/helm_cli.py @@ -5,10 +5,14 @@ logger = logging.getLogger(__name__) -def helm_cli(args): +def helm_cli(args, verbose=False): try: logger.debug("launching helm with arguments: %s", args) - res = subprocess.run(args=["helm"] + args, stderr=PIPE, stdout=DEVNULL) + res = subprocess.run(args=["helm"] + args, stderr=PIPE, stdout=PIPE if verbose else DEVNULL) + if verbose: + for line in res.stdout.splitlines(): + if line: + logger.debug("[helm] %s", line.decode()) return res.stderr.decode() if res.returncode != 0 else "" except FileNotFoundError: return "helm binary not found. helm must be present in the PATH to use kapitan helm functionalities" diff --git a/kapitan/inputs/helm.py b/kapitan/inputs/helm.py index b0cb9dcd1..c2e2704ad 100644 --- a/kapitan/inputs/helm.py +++ b/kapitan/inputs/helm.py @@ -3,12 +3,25 @@ import tempfile import yaml + from kapitan.errors import HelmTemplateError from kapitan.helm_cli import helm_cli from kapitan.inputs.base import InputType, CompiledFile logger = logging.getLogger(__name__) +HELM_DENIED_FLAGS = { + "atomic", + "dry-run", + "generate-name", + "help", + "output-dir", + "repo", + "show-only", + "wait", + "wait-for-jobs", +} + class Helm(InputType): def __init__(self, compile_path, search_paths, ref_controller): @@ -31,6 +44,8 @@ def set_helm_params(self, helm_params): self.helm_params = helm_params def set_kube_version(self, kube_version): + if kube_version: + logger.warning("passing kube_version is deprecated. Use api_versions helm flag instead.") self.kube_version = kube_version def compile_file(self, file_path, compile_path, ext_vars, **kwargs): @@ -50,9 +65,9 @@ def compile_file(self, file_path, compile_path, ext_vars, **kwargs): error_message = self.render_chart( chart_dir=file_path, output_path=temp_dir, + helm_params=self.helm_params, helm_values_file=self.helm_values_file, helm_values_files=self.helm_values_files, - **self.helm_params, ) if error_message: raise HelmTemplateError(error_message) @@ -84,46 +99,80 @@ def compile_file(self, file_path, compile_path, ext_vars, **kwargs): def default_output_type(self): return None - def render_chart(self, chart_dir, output_path, **kwargs): + def render_chart(self, chart_dir, output_path, helm_params, helm_values_file, helm_values_files): args = ["template"] - """renders helm chart located at chart_dir, and stores the output to output_path""" - if kwargs.get("helm_values_files", []): - for file_name in kwargs["helm_values_files"]: - args.append("-f") - args.append(file_name) - if kwargs.get("helm_values_file", None): - args.append("-f") - args.append(kwargs["helm_values_file"]) + name = helm_params.pop("name", None) - if kwargs.get("namespace", None): - args.append("-n") - args.append(kwargs["namespace"]) - - args.append("--output-dir") - args.append(output_path) + flags = {"--include-crds": True, "--skip-tests": True} if self.kube_version: - args.append("--api-versions") - args.append(self.kube_version) + flags["--api-versions"] = self.kube_version + + for param, value in helm_params.items(): + if len(param) == 1: + logger.warning("invalid helm flag: '%s'. helm_params supports only long flag names", param) + continue + + param = param.replace("_", "-") + + if param in ("set", "set-file", "set-string"): + logger.warning( + "helm '%s' flag is not supported. Use 'helm_values' to specify template values", param + ) + continue + + if param == "values": + logger.warning( + "helm '%s' flag is not supported. Use 'helm_values_files' to specify template values files", + param, + ) + continue + + if param in HELM_DENIED_FLAGS: + logger.warning("helm flag '%s' is not supported and will be ignored.", param) + continue + + flags[f"--{param}"] = value + + # 'release_name' used to be the "helm template" [NAME] parameter. + # For backward compatibility, assume it is the '--release-name' flag only if its value is a bool. + release_name = flags.get("--release-name") + if release_name is not None and not isinstance(release_name, bool): + logger.warning( + "using 'release_name' to specify the output name is deprecated. Use 'name' parameter instead" + ) + del flags["--release-name"] + # name is used in place of release_name if both are specified + name = name or release_name + + for flag, value in flags.items(): + # boolean flag should be passed when present, and omitted when not specified + if isinstance(value, bool): + if value: + args.append(flag) + else: + args.append(flag) + args.append(str(value)) - if kwargs.get("validate", False): - args.append("--validate") + """renders helm chart located at chart_dir, and stores the output to output_path""" + if helm_values_file: + args.append("--values") + args.append(helm_values_file) - if kwargs.get("include_crds", True): - args.append("--include-crds") + if helm_values_files: + for file_name in helm_values_files: + args.append("--values") + args.append(file_name) - if kwargs.get("skip_tests", True): - args.append("--skip-tests") + args.append("--output-dir") + args.append(output_path) - if kwargs.get("name_template", None): - args.append("--name-template") - args.append(kwargs["name_template"]) - else: - args.append(kwargs.get("release_name", "--generate-name")) + if "name_template" not in flags: + args.append(name or "--generate-name") - # uses absolute path to make sure helm interpret it as a + # uses absolute path to make sure helm interprets it as a # local dir and not a chart_name that it should download. - args.append(os.path.abspath(chart_dir)) + args.append(chart_dir) - return helm_cli(args) + return helm_cli(args, verbose="--debug" in flags) diff --git a/kapitan/targets.py b/kapitan/targets.py index c0def6daf..d5ec00522 100644 --- a/kapitan/targets.py +++ b/kapitan/targets.py @@ -544,15 +544,8 @@ def valid_target_obj(target_obj, require_compile=True): "helm_values_files": {"type": "array"}, "helm_params": { "type": "object", - "properties": { - "namespace": {"type": "string"}, - "name_template": {"type": "string"}, - "release_name": {"type": "string"}, - "validate": {"type": "boolean"}, - "include_crds": {"type": "boolean"}, - "skip_tests": {"type": "boolean"}, - }, - "additionalProperties": False, + "properties": {"name": {"type": "string"}}, + "additionalProperties": True, }, "input_params": {"type": "object"}, "env_vars": {"type": "object"}, diff --git a/tests/test_helm_input.py b/tests/test_helm_input.py index bd256f995..19796ff87 100644 --- a/tests/test_helm_input.py +++ b/tests/test_helm_input.py @@ -12,6 +12,7 @@ import unittest import yaml + from kapitan.cached import reset_cache from kapitan.cli import main from kapitan.inputs.helm import Helm @@ -25,7 +26,7 @@ def test_render_chart(self): temp_dir = tempfile.mkdtemp() chart_path = "charts/acs-engine-autoscaler" helm = Helm(None, None, None) - error_message = helm.render_chart(chart_path, temp_dir) + error_message = helm.render_chart(chart_path, temp_dir, {"name": "acs-engine-autoscaler"}, None, None) self.assertFalse(error_message) self.assertTrue( os.path.isfile(os.path.join(temp_dir, "acs-engine-autoscaler", "templates", "secrets.yaml")) @@ -35,10 +36,10 @@ def test_render_chart(self): ) def test_error_invalid_char_dir(self): - chart_path = "non-existent" + chart_path = "./non-existent" temp_dir = tempfile.mkdtemp() helm = Helm(None, None, None) - error_message = helm.render_chart(chart_path, temp_dir) + error_message = helm.render_chart(chart_path, temp_dir, {"name": "mychart"}, None, None) self.assertTrue("path" in error_message and "not found" in error_message) def test_compile_chart(self): @@ -150,7 +151,7 @@ def test_compile_with_helm_params(self): with open("inventory/targets/nginx-ingress-helm-params.yml", "r") as fp: manifest = yaml.safe_load(fp.read()) helm_params = manifest["parameters"]["kapitan"]["compile"][0]["helm_params"] - release_name = helm_params["release_name"] + release_name = helm_params["name"] namespace = helm_params["namespace"] main() diff --git a/tests/test_resources/inventory/targets/nginx-ingress-helm-params.yml b/tests/test_resources/inventory/targets/nginx-ingress-helm-params.yml index 8bb468aba..b4d7df228 100644 --- a/tests/test_resources/inventory/targets/nginx-ingress-helm-params.yml +++ b/tests/test_resources/inventory/targets/nginx-ingress-helm-params.yml @@ -14,5 +14,5 @@ parameters: image: repository: custom_repo helm_params: - release_name: my-first-release-name + name: my-first-release-name namespace: my-first-namespace From cf090289440e93ab24bb8ecf2faeee5e62929c33 Mon Sep 17 00:00:00 2001 From: Jean-Daniel Dupas Date: Tue, 16 Mar 2021 14:55:49 +0100 Subject: [PATCH 08/11] [helm] Abort compilation on invalid flag. - reduce denied flags list to the bare minimum. No need to raise error when using an irrelevant flag like atomic. - raise an error if flags contains a '-' instead of '_'. Allowing both may cause subtle bugs if both syntaxes are used in the same target for the same flag. --- kapitan/inputs/helm.py | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/kapitan/inputs/helm.py b/kapitan/inputs/helm.py index c2e2704ad..62d6a1ab6 100644 --- a/kapitan/inputs/helm.py +++ b/kapitan/inputs/helm.py @@ -11,15 +11,11 @@ logger = logging.getLogger(__name__) HELM_DENIED_FLAGS = { - "atomic", "dry-run", "generate-name", "help", "output-dir", - "repo", "show-only", - "wait", - "wait-for-jobs", } @@ -111,27 +107,25 @@ def render_chart(self, chart_dir, output_path, helm_params, helm_values_file, he for param, value in helm_params.items(): if len(param) == 1: - logger.warning("invalid helm flag: '%s'. helm_params supports only long flag names", param) - continue + raise ValueError(f"invalid helm flag: '{param}'. helm_params supports only long flag names") + + if "-" in param: + raise ValueError(f"helm flag names must use '_' and not '-': {param}") param = param.replace("_", "-") if param in ("set", "set-file", "set-string"): - logger.warning( - "helm '%s' flag is not supported. Use 'helm_values' to specify template values", param + raise ValueError( + f"helm '{param}' flag is not supported. Use 'helm_values' to specify template values" ) - continue if param == "values": - logger.warning( - "helm '%s' flag is not supported. Use 'helm_values_files' to specify template values files", - param, + raise ValueError( + f"helm '{param}' flag is not supported. Use 'helm_values_files' to specify template values files" ) - continue if param in HELM_DENIED_FLAGS: - logger.warning("helm flag '%s' is not supported and will be ignored.", param) - continue + raise ValueError(f"helm flag '{param}' is not supported.") flags[f"--{param}"] = value @@ -140,7 +134,7 @@ def render_chart(self, chart_dir, output_path, helm_params, helm_values_file, he release_name = flags.get("--release-name") if release_name is not None and not isinstance(release_name, bool): logger.warning( - "using 'release_name' to specify the output name is deprecated. Use 'name' parameter instead" + "using 'release_name' to specify the output name is deprecated. Use 'name' instead" ) del flags["--release-name"] # name is used in place of release_name if both are specified From f410612505e13b037143e188f02194cd79cc9636 Mon Sep 17 00:00:00 2001 From: Jean-Daniel Date: Tue, 16 Mar 2021 14:56:41 +0100 Subject: [PATCH 09/11] Typo in doc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Simon Rüegg --- docs/compile.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/compile.md b/docs/compile.md index ce3c11b06..f9a41bf6e 100644 --- a/docs/compile.md +++ b/docs/compile.md @@ -374,7 +374,7 @@ Special flags: - `include_crds` and `skip_tests`: These flags are enabled by default and should be set to `false` to be removed. - `debug`: prints the helm debug output in kapitan debug log. -- `namespace`: note that due to the restriction on `helm template` command, specifying the namespace does not automatically add `metadata.namespace` property to the resources. Therefore, users are encourage to explicitly specify in all resources: +- `namespace`: note that due to the restriction on `helm template` command, specifying the namespace does not automatically add `metadata.namespace` property to the resources. Therefore, users are encouraged to explicitly specify it in all resources: ```yaml metadata: From 37597b4fe6478d80d4c2d88969a411859b087921 Mon Sep 17 00:00:00 2001 From: Jean-Daniel Date: Fri, 2 Apr 2021 16:37:56 +0200 Subject: [PATCH 10/11] Add `output_file` helm params. When specified, run helm template without specifying --output-dir and pipe the result into a single file. --- docs/compile.md | 4 +++- kapitan/helm_cli.py | 8 +++++--- kapitan/inputs/helm.py | 13 ++++++++++--- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/docs/compile.md b/docs/compile.md index f9a41bf6e..004ec75a5 100644 --- a/docs/compile.md +++ b/docs/compile.md @@ -353,6 +353,7 @@ parameters: helm_params: name: namespace: + output_file: validate: true … ``` @@ -371,6 +372,7 @@ Flags without argument must have a boolean value, all other flags require a stri Special flags: - `name`: equivalent of helm template `[NAME]` parameter. Ignored if `name_template` is also specified. If neither `name_template` nor `name` are specified, the `--generate-name` flag is used to generate a name. +- `output_file`: name of the single file used to output all the generated resources. This is equivalent to call `helm template` without specifing output dir. If not specified, each resource is generated into a distinct file. - `include_crds` and `skip_tests`: These flags are enabled by default and should be set to `false` to be removed. - `debug`: prints the helm debug output in kapitan debug log. @@ -415,7 +417,7 @@ parameters: image: repository: custom_repo helm_params: - release_name: my-first-release-name + name: my-first-release-name namespace: my-first-namespace ``` diff --git a/kapitan/helm_cli.py b/kapitan/helm_cli.py index b6aeba598..dfdc3088d 100644 --- a/kapitan/helm_cli.py +++ b/kapitan/helm_cli.py @@ -5,11 +5,13 @@ logger = logging.getLogger(__name__) -def helm_cli(args, verbose=False): +def helm_cli(args, stdout=None, verbose=False): try: logger.debug("launching helm with arguments: %s", args) - res = subprocess.run(args=["helm"] + args, stderr=PIPE, stdout=PIPE if verbose else DEVNULL) - if verbose: + res = subprocess.run( + args=["helm"] + args, stderr=PIPE, stdout=stdout or (PIPE if verbose else DEVNULL) + ) + if verbose and not stdout: for line in res.stdout.splitlines(): if line: logger.debug("[helm] %s", line.decode()) diff --git a/kapitan/inputs/helm.py b/kapitan/inputs/helm.py index 62d6a1ab6..b5b05b78e 100644 --- a/kapitan/inputs/helm.py +++ b/kapitan/inputs/helm.py @@ -99,6 +99,7 @@ def render_chart(self, chart_dir, output_path, helm_params, helm_values_file, he args = ["template"] name = helm_params.pop("name", None) + output_file = helm_params.pop("output_file", None) flags = {"--include-crds": True, "--skip-tests": True} @@ -159,8 +160,9 @@ def render_chart(self, chart_dir, output_path, helm_params, helm_values_file, he args.append("--values") args.append(file_name) - args.append("--output-dir") - args.append(output_path) + if not output_file: + args.append("--output-dir") + args.append(output_path) if "name_template" not in flags: args.append(name or "--generate-name") @@ -169,4 +171,9 @@ def render_chart(self, chart_dir, output_path, helm_params, helm_values_file, he # local dir and not a chart_name that it should download. args.append(chart_dir) - return helm_cli(args, verbose="--debug" in flags) + if output_file: + with open(os.path.join(output_path, output_file), "wb") as f: + # can't be verbose when capturing stdout + return helm_cli(args, stdout=f) + else: + return helm_cli(args, verbose="--debug" in flags) From a675509b947dbe0ed30051c3a57ac2531cf12765 Mon Sep 17 00:00:00 2001 From: Jean-Daniel Date: Wed, 9 Jun 2021 12:06:43 +0200 Subject: [PATCH 11/11] Add 2 ways to specify custom helm binary. All helm invocation will try to use the value set in the env var KAPITAN_HELM_PATH. Fetch and compile action takes a helm_path parameter to specify per target helm binary. --- docs/compile.md | 5 +++- docs/external_dependencies.md | 6 ++++- kapitan/dependency_manager/base.py | 12 +++++---- kapitan/helm_cli.py | 8 ++++-- kapitan/inputs/helm.py | 42 ++++++++++++++---------------- kapitan/targets.py | 10 +------ tests/test_dependency_manager.py | 4 +-- tests/test_helm_input.py | 10 ++++--- 8 files changed, 51 insertions(+), 46 deletions(-) diff --git a/docs/compile.md b/docs/compile.md index 004ec75a5..c298f8e62 100644 --- a/docs/compile.md +++ b/docs/compile.md @@ -350,6 +350,7 @@ parameters: helm_values_files: - + helm_path: helm_params: name: namespace: @@ -365,6 +366,9 @@ If the same keys exist in `helm_values` and in multiple specified `helm_values_f There is an example in the tests. The `monitoring-dev`(kapitan/tests/test_resources/inventory/targets/monitoring-dev.yml) and `monitoring-prd`(kapitan/tests/test_resources/inventory/targets/monitoring-prd.yml) targets both use the `monitoring`(tests/test_resources/inventory/classes/component/monitoring.yml) component. This component has helm chart input and takes a `common.yml` helm_values file which is "shared" by any target that uses the component and it also takes a dynamically defined file based on a kapitan variable defined in the target. +`helm_path` can be use to provide the helm binary name or path. +`helm_path` defaults to the value of `KAPITAN_HELM_PATH` env var if it is set, else it defaults to `helm` + `helm_params` correspond to the flags for `helm template`. Most flags that helm supports can be used here by replacing '-' by '_' in the flag name. Flags without argument must have a boolean value, all other flags require a string value. @@ -384,7 +388,6 @@ Special flags: ``` - See the [helm doc](https://helm.sh/docs/helm/helm_template/) for further detail. diff --git a/docs/external_dependencies.md b/docs/external_dependencies.md index a76bd0c00..56f271434 100644 --- a/docs/external_dependencies.md +++ b/docs/external_dependencies.md @@ -171,7 +171,10 @@ Setting `unpack: True` will unpack zip or tar files onto the `output_path`. In s ## Helm type Fetches helm charts and any specific subcharts in the `requirements.yaml` file. -Requires that `helm` be present in the PATH. + +`helm_path` can be used to specify where the `helm` binary name or path. +It defaults to the value of the `KAPITAN_HELM_PATH` environment var or simply to `helm` if neither is set. +You should specify only if you don't want the default behavior. ### Usage @@ -184,6 +187,7 @@ parameters: source: http[s]:// version: chart_name: + helm_path: ``` diff --git a/kapitan/dependency_manager/base.py b/kapitan/dependency_manager/base.py index 184a7f261..f1ad1f2c5 100644 --- a/kapitan/dependency_manager/base.py +++ b/kapitan/dependency_manager/base.py @@ -26,7 +26,7 @@ logger = logging.getLogger(__name__) -HelmSource = namedtuple("HelmSource", ["repo", "chart_name", "version"]) +HelmSource = namedtuple("HelmSource", ["repo", "chart_name", "version", "helm_path"]) def fetch_dependencies(output_path, target_objs, save_dir, force, pool): @@ -70,7 +70,9 @@ def fetch_dependencies(output_path, target_objs, save_dir, force, pool): http_deps[source_uri].append(item) elif dependency_type == "helm": version = item.get("version", "") - helm_deps[HelmSource(source_uri, item["chart_name"], version)].append(item) + helm_deps[ + HelmSource(source_uri, item["chart_name"], version, item.get("helm_path")) + ].append(item) else: logger.warning("%s is not a valid source type", dependency_type) @@ -225,7 +227,7 @@ def fetch_helm_chart(dep_mapping, save_dir, force): save_dir, path_hash, source.chart_name + "-" + (source.version or "latest") ) if force or not exists_in_cache(cached_repo_path): - fetch_helm_archive(source.repo, source.chart_name, source.version, cached_repo_path) + fetch_helm_archive(source.helm_path, source.repo, source.chart_name, source.version, cached_repo_path) else: logger.debug("Using cached helm chart at %s", cached_repo_path) @@ -242,7 +244,7 @@ def fetch_helm_chart(dep_mapping, save_dir, force): logger.info("Dependency %s: saved to %s", source.chart_name, output_path) -def fetch_helm_archive(repo, chart_name, version, save_path): +def fetch_helm_archive(helm_path, repo, chart_name, version, save_path): logger.info("Dependency helm chart %s and version %s: fetching now", chart_name, version or "latest") # Fetch archive and untar it into parent dir save_dir = os.path.dirname(save_path) @@ -254,7 +256,7 @@ def fetch_helm_archive(repo, chart_name, version, save_path): args.append(chart_name) - response = helm_cli(args) + response = helm_cli(helm_path, args) if response != "": logger.warning("Dependency helm chart %s and version %s: %s", chart_name, version, response) raise HelmFetchingError(response) diff --git a/kapitan/helm_cli.py b/kapitan/helm_cli.py index dfdc3088d..bb43ddd5b 100644 --- a/kapitan/helm_cli.py +++ b/kapitan/helm_cli.py @@ -1,15 +1,19 @@ import logging +import os import subprocess from subprocess import PIPE, DEVNULL logger = logging.getLogger(__name__) -def helm_cli(args, stdout=None, verbose=False): +def helm_cli(helm_path, args, stdout=None, verbose=False): + # if helm is not specified, try to get it from env var, and defaults to looking up helm in the path. + if not helm_path: + helm_path = os.getenv("KAPITAN_HELM_PATH", "helm") try: logger.debug("launching helm with arguments: %s", args) res = subprocess.run( - args=["helm"] + args, stderr=PIPE, stdout=stdout or (PIPE if verbose else DEVNULL) + args=[helm_path] + args, stderr=PIPE, stdout=stdout or (PIPE if verbose else DEVNULL) ) if verbose and not stdout: for line in res.stdout.splitlines(): diff --git a/kapitan/inputs/helm.py b/kapitan/inputs/helm.py index b5b05b78e..67552d4ba 100644 --- a/kapitan/inputs/helm.py +++ b/kapitan/inputs/helm.py @@ -20,29 +20,24 @@ class Helm(InputType): - def __init__(self, compile_path, search_paths, ref_controller): + def __init__(self, compile_path, search_paths, ref_controller, args): super().__init__("helm", compile_path, search_paths, ref_controller) - self.helm_values_file = None - self.helm_values_files = [] - self.helm_params = {} - self.kube_version = "" - def dump_helm_values(self, helm_values): - """dump helm values into a yaml file whose path will be passed over to Go helm code""" - _, self.helm_values_file = tempfile.mkstemp(".helm_values.yml", text=True) - with open(self.helm_values_file, "w") as fp: - yaml.safe_dump(helm_values, fp) + self.helm_values_files = args.get("helm_values_files") + self.helm_params = args.get("helm_params") or {} + self.helm_path = args.get("helm_path") - def set_helm_values_files(self, helm_values_files): - self.helm_values_files = helm_values_files - - def set_helm_params(self, helm_params): - self.helm_params = helm_params - - def set_kube_version(self, kube_version): - if kube_version: + self.helm_values_file = None + if "helm_values" in args: + """dump helm values into a yaml file whose path will be passed over to Go helm code""" + _, self.helm_values_file = tempfile.mkstemp(".helm_values.yml", text=True) + with open(self.helm_values_file, "w") as fp: + yaml.safe_dump(args["helm_values"], fp) + + self.kube_version = None + if "kube_version" in args: logger.warning("passing kube_version is deprecated. Use api_versions helm flag instead.") - self.kube_version = kube_version + self.kube_version = args["kube_version"] def compile_file(self, file_path, compile_path, ext_vars, **kwargs): """ @@ -61,6 +56,7 @@ def compile_file(self, file_path, compile_path, ext_vars, **kwargs): error_message = self.render_chart( chart_dir=file_path, output_path=temp_dir, + helm_path=self.helm_path, helm_params=self.helm_params, helm_values_file=self.helm_values_file, helm_values_files=self.helm_values_files, @@ -95,7 +91,9 @@ def compile_file(self, file_path, compile_path, ext_vars, **kwargs): def default_output_type(self): return None - def render_chart(self, chart_dir, output_path, helm_params, helm_values_file, helm_values_files): + def render_chart( + self, chart_dir, output_path, helm_path, helm_params, helm_values_file, helm_values_files + ): args = ["template"] name = helm_params.pop("name", None) @@ -174,6 +172,6 @@ def render_chart(self, chart_dir, output_path, helm_params, helm_values_file, he if output_file: with open(os.path.join(output_path, output_file), "wb") as f: # can't be verbose when capturing stdout - return helm_cli(args, stdout=f) + return helm_cli(helm_path, args, stdout=f) else: - return helm_cli(args, verbose="--debug" in flags) + return helm_cli(helm_path, args, verbose="--debug" in flags) diff --git a/kapitan/targets.py b/kapitan/targets.py index d5ec00522..a08b3d5a1 100644 --- a/kapitan/targets.py +++ b/kapitan/targets.py @@ -438,15 +438,7 @@ def compile_target(target_obj, search_paths, compile_path, ref_controller, **kwa if "input_params" in comp_obj: input_compiler.set_input_params(comp_obj["input_params"]) elif input_type == "helm": - input_compiler = Helm(compile_path, search_paths, ref_controller) - if "helm_values" in comp_obj: - input_compiler.dump_helm_values(comp_obj["helm_values"]) - if "helm_params" in comp_obj: - input_compiler.set_helm_params(comp_obj["helm_params"]) - if "helm_values_files" in comp_obj: - input_compiler.set_helm_values_files(comp_obj["helm_values_files"]) - if "kube_version" in comp_obj: - input_compiler.set_kube_version(comp_obj["kube_version"]) + input_compiler = Helm(compile_path, search_paths, ref_controller, comp_obj) elif input_type == "copy": ignore_missing = comp_obj.get("ignore_missing", False) input_compiler = Copy(compile_path, search_paths, ref_controller, ignore_missing) diff --git a/tests/test_dependency_manager.py b/tests/test_dependency_manager.py index 38cbfa295..a66869826 100644 --- a/tests/test_dependency_manager.py +++ b/tests/test_dependency_manager.py @@ -97,7 +97,7 @@ def test_fetch_helm_chart(self): "source": repo, } ] - fetch_helm_chart((HelmSource(repo, chart_name, version), dep), temp_dir, force=False) + fetch_helm_chart((HelmSource(repo, chart_name, version, None), dep), temp_dir, force=False) self.assertTrue(os.path.isdir(output_chart_dir)) self.assertTrue(os.path.isfile(os.path.join(output_chart_dir, "Chart.yaml"))) self.assertTrue(os.path.isdir(os.path.join(output_chart_dir, "charts", "kube-state-metrics"))) @@ -123,7 +123,7 @@ def test_fetch_helm_chart_version_that_does_not_exist(self): } ] with self.assertRaises(HelmFetchingError): - fetch_helm_chart((HelmSource(repo, chart_name, version), dep), temp_dir, force=False) + fetch_helm_chart((HelmSource(repo, chart_name, version, None), dep), temp_dir, force=False) self.assertFalse(os.path.isdir(output_chart_dir)) self.assertFalse(os.path.isfile(os.path.join(output_chart_dir, "Chart.yaml"))) rmtree(temp_dir) diff --git a/tests/test_helm_input.py b/tests/test_helm_input.py index 19796ff87..607294874 100644 --- a/tests/test_helm_input.py +++ b/tests/test_helm_input.py @@ -25,8 +25,10 @@ def setUp(self): def test_render_chart(self): temp_dir = tempfile.mkdtemp() chart_path = "charts/acs-engine-autoscaler" - helm = Helm(None, None, None) - error_message = helm.render_chart(chart_path, temp_dir, {"name": "acs-engine-autoscaler"}, None, None) + helm = Helm(None, None, None, {}) + error_message = helm.render_chart( + chart_path, temp_dir, None, {"name": "acs-engine-autoscaler"}, None, None + ) self.assertFalse(error_message) self.assertTrue( os.path.isfile(os.path.join(temp_dir, "acs-engine-autoscaler", "templates", "secrets.yaml")) @@ -38,8 +40,8 @@ def test_render_chart(self): def test_error_invalid_char_dir(self): chart_path = "./non-existent" temp_dir = tempfile.mkdtemp() - helm = Helm(None, None, None) - error_message = helm.render_chart(chart_path, temp_dir, {"name": "mychart"}, None, None) + helm = Helm(None, None, None, {}) + error_message = helm.render_chart(chart_path, temp_dir, None, {"name": "mychart"}, None, None) self.assertTrue("path" in error_message and "not found" in error_message) def test_compile_chart(self):