diff --git a/.github/hooks/pre-commit b/.github/hooks/pre-commit new file mode 100755 index 000000000..febd7e3c6 --- /dev/null +++ b/.github/hooks/pre-commit @@ -0,0 +1,14 @@ +#!/bin/bash + +cd functions/go; +echo "Generating docs..." +make generate; +diff=`git diff` + +if [[ $diff != "" ]]; +then + echo "found unstaged changes. Please ensure you have run `make generate` to update the generated docs and add them before commit." + exit 1 +else + exit 0 +fi diff --git a/.github/workflows/checkSite.yml b/.github/workflows/checkSite.yml new file mode 100644 index 000000000..57cbf221b --- /dev/null +++ b/.github/workflows/checkSite.yml @@ -0,0 +1,44 @@ +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: CheckSite +on: + pull_request: + paths: + - "functions/**" + - "examples/**" + - "site/**" + - "scripts/generate_catalog/**" +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - uses: actions/checkout@v2 + with: + repository: etefera/href-checker + ref: docsify + path: href-checker + - uses: actions/setup-node@v2 + with: + node-version: '14' + - name: Install Site Checker + run: yarn install + working-directory: href-checker + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - name: Run Site Checker + run: make site-check \ No newline at end of file diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f8c3424be..0737d9db2 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -67,43 +67,29 @@ jobs: cd functions/go make check-licenses - verify-ci: - runs-on: ubuntu-latest - env: - GOPATH: /home/runner/work/kpt-functions-catalog/functions/go - GO111MODULE: on - steps: - - uses: actions/checkout@v2 - - name: Set up python 3 - uses: actions/setup-python@v2 - - name: Install libs - run: | - pip install pyyaml - - name: Set up Go 1.15 - uses: actions/setup-go@v2 - with: - go-version: 1.15 - - name: Install mdrip - run: | - go get github.com/russross/blackfriday/v2@v2.0.1 - go get github.com/monopole/mdrip@v1.0.2 - - name: Verify docs - run: | - make verify-docs - e2e-ci: - needs: [ts-unit-test-ci, go-unit-test-ci, verify-ci] + needs: [ts-unit-test-ci, go-unit-test-ci] strategy: matrix: platform: [ubuntu-latest] node-version: [12.x] runs-on: ${{ matrix.platform }} + env: + GOPATH: /home/runner/work/kpt-functions-catalog/functions/go + GO111MODULE: on steps: - uses: actions/checkout@v2 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v1 with: node-version: ${{ matrix.node-version }} + - name: Set up Go 1.15 + uses: actions/setup-go@v2 + with: + go-version: 1.15 + - name: Install kpt + run: | + go get github.com/GoogleContainerTools/kpt@next - name: Build node and Go docker images if: matrix.platform == 'ubuntu-latest' run: | @@ -111,6 +97,4 @@ jobs: - name: Run all tests if: matrix.platform == 'ubuntu-latest' run: | - sudo curl https://storage.googleapis.com/kpt-dev/latest/linux_amd64/kpt -o /usr/local/bin/kpt - sudo chmod +x /usr/local/bin/kpt make e2e-test diff --git a/.github/workflows/firebase-hosting-merge.yml b/.github/workflows/firebase-hosting-merge.yml new file mode 100644 index 000000000..2f4aebdcd --- /dev/null +++ b/.github/workflows/firebase-hosting-merge.yml @@ -0,0 +1,27 @@ +# This file was initially auto-generated by the Firebase CLI +# https://github.com/firebase/firebase-tools + +name: Deploy to Firebase Hosting on merge +on: + push: + branches: + - master + - "*/v[0-9]+.[0-9]+" +jobs: + build_and_deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Generate Site + run: make site-generate + - uses: FirebaseExtended/action-hosting-deploy@276388dd6c2cde23455b30293105cc866c22282d # v0 + with: + repoToken: '${{ secrets.GITHUB_TOKEN }}' + firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_KPT_DEV }}' + channelId: live + projectId: kpt-dev + entryPoint: site + env: + FIREBASE_CLI_PREVIEWS: hostingchannels diff --git a/.github/workflows/verify-docs.yaml b/.github/workflows/verify-docs.yaml new file mode 100644 index 000000000..8294c6510 --- /dev/null +++ b/.github/workflows/verify-docs.yaml @@ -0,0 +1,32 @@ +name: verify-docs + +on: + pull_request: + branches: + - master + - '*/v[0-9]+.[0-9]+' + +jobs: + verify-ci: + runs-on: ubuntu-latest + env: + GOPATH: /home/runner/work/kpt-functions-catalog/functions/go + GO111MODULE: on + steps: + - uses: actions/checkout@v2 + - name: Set up python 3 + uses: actions/setup-python@v2 + - name: Install libs + run: | + pip install pyyaml + - name: Set up Go 1.15 + uses: actions/setup-go@v2 + with: + go-version: 1.15 + - name: Install mdrip + run: | + go get github.com/russross/blackfriday/v2@v2.0.1 + go get github.com/monopole/mdrip@v1.0.2 + - name: Verify docs + run: | + make verify-docs diff --git a/.gitignore b/.gitignore index 1e88e75fd..a223c6eee 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .idea +.vscode dist node_modules *.iml diff --git a/Makefile b/Makefile index 4987814db..f5410e5b1 100644 --- a/Makefile +++ b/Makefile @@ -55,6 +55,14 @@ push: ## Push images to registry. WARN: This operation should only be done in CI cd functions/contrib/ts && $(MAKE) push site-generate: ## Collect function branches and generate a catalog of their examples and documentation using kpt next. - rm -rf ./examples/*/ + rm -rf ./site/*/ # GO111MODULE=on go get -v github.com/GoogleContainerTools/kpt@next - (cd scripts/generate_catalog/ && go run . ../.. ../../examples) + (cd scripts/generate_catalog/ && go run . ../.. ../../site) + +site-run: ## Run the site locally. + make site-generate + ./scripts/run-site.sh + +site-check: ## Test site for broken catalog links. + make site-run + ./scripts/check-site.sh diff --git a/README.md b/README.md index 45db340ce..a82590858 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ [Documentation] +[Open an Issue] + [Contributor Guide] [Release Process] @@ -14,3 +16,4 @@ [Contributor Guide]: CONTRIBUTING.md [Code of Conduct]: CODE_OF_CONDUCT.md [Release Process]: RELEASING.md +[Open an Issue]: https://github.com/GoogleContainerTools/kpt/issues diff --git a/examples/_template/README.md b/examples/_template/README.md index 773ab04c7..cbd480760 100644 --- a/examples/_template/README.md +++ b/examples/_template/README.md @@ -1,6 +1,6 @@ # some-image-foo: Example Title -## Overview +### Overview 1. Explain what this particular example demonstrates. 2. Include a link to the function reference (help doc) on first mention of the function. @@ -9,15 +9,15 @@ 1. Explain what this function config does. Focus on explaining this particular example, not repeating the function reference. -## Function invocation +### Function invocation 4. Show exact `kpt` commands to get the example package and run the function. -## Expected result +### Expected result 5. Describe the expected outcome of running the instructions above. This needs to be specific enough so that the user is confident the function works as expected (Don't just provide the command to `cat` a file). -## Function Reference +### Function Reference -6. Provide a link to the function help doc for reference. \ No newline at end of file +6. Provide a link to the function help doc for reference. diff --git a/examples/apply-setters/simple/.expected/diff.patch b/examples/apply-setters/simple/.expected/diff.patch index f172b99da..4fe97e225 100644 --- a/examples/apply-setters/simple/.expected/diff.patch +++ b/examples/apply-setters/simple/.expected/diff.patch @@ -1,5 +1,5 @@ diff --git a/resources.yaml b/resources.yaml -index c0c871e..cd75f56 100644 +index c79db4d..6dc582c 100644 --- a/resources.yaml +++ b/resources.yaml @@ -1,7 +1,7 @@ @@ -15,6 +15,6 @@ index c0c871e..cd75f56 100644 metadata: name: ns environments: # kpt-set: ${env} --- dev -+- prod - - stage +- - dev ++ - prod + - stage diff --git a/examples/apply-setters/simple/Kptfile b/examples/apply-setters/simple/Kptfile new file mode 100644 index 000000000..7cbabbf0f --- /dev/null +++ b/examples/apply-setters/simple/Kptfile @@ -0,0 +1,12 @@ +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile +metadata: + name: example +pipeline: + mutators: + - image: gcr.io/kpt-fn/apply-setters:unstable + configMap: + env: | + - prod + - stage + name: my-new-map diff --git a/examples/apply-setters/simple/README.md b/examples/apply-setters/simple/README.md index b0ad5582e..cee0bc966 100644 --- a/examples/apply-setters/simple/README.md +++ b/examples/apply-setters/simple/README.md @@ -1,5 +1,7 @@ # apply-setters: Simple Example +### Overview + Setters provide a solution for template-free setting of field values. The `apply-setters` KRM config function applies setter values to resource fields with setter references. @@ -23,7 +25,7 @@ environments: # kpt-set: ${env} - stage ``` -We use ConfigMap to configure the `apply-setters` function. The desired +We use `ConfigMap` to configure the `apply-setters` function. The desired setter values are provided as key-value pairs using `data` field where key is the name of the setter(as seen in the reference comments) and value is the new desired value for the tagged field. @@ -59,21 +61,20 @@ environments: # kpt-set: ${env} - stage ``` -## Function invocation +### Function invocation Get the config example and try it out by running the following commands: - -```sh -kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/apply-setters/simple . -kpt fn run simple +```shell +$ kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/apply-setters/simple . +$ kpt fn render simple ``` -## Expected result +### Expected result Check the value of setter `name` is set to `my-new-map`. Check the value of setter `env` is set to array value `[prod, stage]`. -```sh -$ kpt cfg cat simple/ -``` +#### Note: + +Refer to the `create-setters` example in `search-replace` function examples for creating setters. diff --git a/examples/apply-setters/simple/fn-config.yaml b/examples/apply-setters/simple/fn-config.yaml deleted file mode 100644 index 182448362..000000000 --- a/examples/apply-setters/simple/fn-config.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: apply-setters-fn-config - # TODO:(pmarupaka) remove annotations when e2e tests switch to kpt v1 binary - annotations: - config.k8s.io/function: | - container: - image: gcr.io/kpt-fn/apply-setters:unstable -data: - name: my-new-map - env: | - - prod - - stage diff --git a/examples/apply-setters/simple/resources.yaml b/examples/apply-setters/simple/resources.yaml index c0c871e7b..c79db4de2 100644 --- a/examples/apply-setters/simple/resources.yaml +++ b/examples/apply-setters/simple/resources.yaml @@ -10,5 +10,5 @@ kind: MyKind metadata: name: ns environments: # kpt-set: ${env} -- dev -- stage + - dev + - stage diff --git a/examples/contrib/analyze-istio/.expected/config.yaml b/examples/contrib/analyze-istio/.expected/config.yaml index 28ffd5bd9..f6237512c 100644 --- a/examples/contrib/analyze-istio/.expected/config.yaml +++ b/examples/contrib/analyze-istio/.expected/config.yaml @@ -1,2 +1 @@ exitCode: 1 -runCount: 2 diff --git a/examples/contrib/analyze-istio/.expected/results.yaml b/examples/contrib/analyze-istio/.expected/results.yaml index 67ed5d1d3..aec64cd4d 100644 --- a/examples/contrib/analyze-istio/.expected/results.yaml +++ b/examples/contrib/analyze-istio/.expected/results.yaml @@ -1,18 +1,19 @@ -- message: 'Istioctl analyze command results in error: function toString() { [native - code] }' - severity: error - file: - path: '' -- message: 'Schema validation error: gateway must have at least one server' - severity: error - tags: - documentation_url: 'https://istio.io/docs/reference/config/analysis/IST0106?ref=istioctl-analyze' - origin: Gateway httpbin-gateway.default - code: IST0106 - resourceRef: - apiVersion: networking.istio.io/v1alpha3 - kind: Gateway - namespace: '' - name: httpbin-gateway - file: - path: istio-config.yaml +apiVersion: kpt.dev/v1alpha2 +kind: FunctionResultList +metadata: + name: fnresults +exitCode: 1 +items: + - image: gcr.io/kpt-fn-contrib/analyze-istio:unstable + exitCode: 1 + results: + - message: 'Istioctl analyze command results in error: function toString() { [native code] }' + severity: error + - message: 'Schema validation error: gateway must have at least one server' + severity: error + resourceRef: + apiVersion: networking.istio.io/v1alpha3 + kind: Gateway + name: httpbin-gateway + file: + path: istio-config.yaml diff --git a/examples/contrib/analyze-istio/Kptfile b/examples/contrib/analyze-istio/Kptfile new file mode 100644 index 000000000..55be136bd --- /dev/null +++ b/examples/contrib/analyze-istio/Kptfile @@ -0,0 +1,9 @@ +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile +metadata: + name: example +pipeline: + validators: + - image: gcr.io/kpt-fn-contrib/analyze-istio:unstable + configMap: + '--use-kube': 'false' diff --git a/examples/contrib/analyze-istio/README.md b/examples/contrib/analyze-istio/README.md index d1559e899..3c62aa750 100644 --- a/examples/contrib/analyze-istio/README.md +++ b/examples/contrib/analyze-istio/README.md @@ -5,20 +5,20 @@ Istio configuration and outputs structured results detailing any errors found during analysis. This example invokes the `analyze-istio` function using declarative configuration. -## Function Invocation +### Function Invocation Get this example and try it out by running the following commands: -```sh +```shell kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/contrib/analyze-istio . kpt fn run analyze-istio ``` -## Expected Results +### Expected Results This should give the following output: -```sh +```shell [ERROR] Schema validation error: gateway must have at least one server in object 'networking.istio.io/v1alpha3/Gateway//httpbin-gateway' in file example-config.yaml error: exit status 1 ``` diff --git a/examples/contrib/analyze-istio/fn-config.yaml b/examples/contrib/analyze-istio/fn-config.yaml deleted file mode 100644 index 056b29dd4..000000000 --- a/examples/contrib/analyze-istio/fn-config.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: my-config - annotations: - config.k8s.io/function: | - container: - image: gcr.io/kpt-fn-contrib/analyze-istio:unstable - config.kubernetes.io/local-config: 'true' -data: - '--use-kube': 'false' diff --git a/examples/contrib/inflate-helm-chart/README.md b/examples/contrib/inflate-helm-chart/README.md index 92b0f3fc2..9e6686bcd 100644 --- a/examples/contrib/inflate-helm-chart/README.md +++ b/examples/contrib/inflate-helm-chart/README.md @@ -4,20 +4,20 @@ The `inflate-helm-chart` KRM config function generates a new kpt package from a local Helm chart. This example invokes the `inflate-helm-chart` function using declarative configuration. -## Function invocation +### Function invocation Get this example and try it out by running the following commands: -```sh +```shell kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/contrib/inflate-helm-chart . kpt fn run --as-current-user inflate-helm-chart/local-configs --mount type=bind,src=$(pwd)/inflate-helm-chart/helloworld-chart,dst=/source ``` -## Expected result +### Expected result Checking the contents of the `local-configs` directory with `kpt cfg tree inflate-helm-chart/local-configs/` should reveal the following new yaml files: -```sh +```shell inflate-helm-chart/local-configs ├── [deployment_chart-helloworld-chart.yaml] Deployment chart-helloworld-chart ├── [fn-config.yaml] ConfigMap my-func-config @@ -28,7 +28,7 @@ inflate-helm-chart/local-configs To view changes without writing them into a file, a dry run can be performed as follows: -```sh +```shell kpt fn run --as-current-user inflate-helm-chart/local-configs --mount type=bind,src=$(pwd)/inflate-helm-chart/helloworld-chart,dst=/source --dry-run ``` diff --git a/examples/contrib/sops/README.md b/examples/contrib/sops/README.md deleted file mode 100644 index 0828f14d8..000000000 --- a/examples/contrib/sops/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# SOPS - -The `sops` config function transforms an input kpt package according to the -function configuration: in the current version it can encrypt yaml documents or -decrypt the documents that have `sops` field with SOPS metadata. -This example invokes the `sops -d` for decryption and `sops -e` for encryption -function using declarative configuration. See -[sops readme](https://github.com/mozilla/sops/blob/master/README.rst) for more -details. - -In order to encrypt or decrypt yaml, `sops` may accept a variety of ENV vars, e.g. to work -with Hashicorp Vault it will be necessary to set: `VAULT_ADDR` and -`VAULT_TOKEN`. For PGP case this function introduces an additional `SOPS_IMPORT_PGP` ENV var -that must contain the private key or keys needed to decrypt yamls and public key or keys to -encrypt yamls. If you have a file with keys it's possible to run: - -```sh -kpt fn run --env SOPS_IMPORT_PGP="$(cat .asc)" -``` - -or if your keys are already in `gpg`, it's possibe to run: - -```sh -kpt fn run --env SOPS_IMPORT_PGP="$(gpg --armor --export-secret-keys)" -``` - -## Function invocation - -Get this example and try it out by running the following commands: - -```sh -# download sops kpt-function example -kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/contrib/sops . -# copy example key from sops project -curl -fsSL -o sops/key.asc https://raw.githubusercontent.com/mozilla/sops/master/pgp/sops_functional_tests_key.asc -# run the function -kpt fn run --env SOPS_IMPORT_PGP="$(cat sops/key.asc)" sops/local-configs -``` - -## Expected result - -Verify the updated configuration: - -```sh -kpt cfg cat sops/local-configs -``` diff --git a/examples/contrib/sops/age/README.md b/examples/contrib/sops/age/README.md new file mode 100644 index 000000000..2eb8c3871 --- /dev/null +++ b/examples/contrib/sops/age/README.md @@ -0,0 +1,34 @@ +# sops: AGE example + +### Overview + +The `sops` KRM config function encrypts and decrypts resources. Learn more on the [sops website]. + +This example demonstrates invocation of `sops` for encryption the resouce called `toEncrypt` and decryption of the resource called `toDecrypt` using the already existing AGE keys. + +## Function invocation + +Get this example and try it out by running the following commands: + +```shell +# download this example +kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/contrib/sops/age . + +# copy example AGE key from sops project +curl -fsSL -o age_keys.txt https://raw.githubusercontent.com/mozilla/sops/master/age/keys.txt + +# run the function to work with AGE +SOPS_IMPORT_AGE="$(cat age_keys.txt)" kpt fn run age +``` + +## Expected result + +Verify the updated configuration: + +```shell +kpt cfg cat age +``` + +The resource called `toDecrypt` must be decrypted and the resource called `toEncrypt` must be encrypted. + +[sops website]: https://github.com/mozilla/sops#encrypting-using-age diff --git a/examples/contrib/sops/age/function.yaml b/examples/contrib/sops/age/function.yaml new file mode 100644 index 000000000..d076d605d --- /dev/null +++ b/examples/contrib/sops/age/function.yaml @@ -0,0 +1,30 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: my-decrypt-config + annotations: + config.k8s.io/function: | + container: + image: gcr.io/kpt-fn-contrib/sops:unstable + envs: + - SOPS_IMPORT_AGE + config.kubernetes.io/local-config: "true" +data: + cmd: 'decrypt' + cmd-json-path-filter: '$[?(@.metadata.name=="toDecrypt")]' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: my-encrypt-config + annotations: + config.k8s.io/function: | + container: + image: gcr.io/kpt-fn-contrib/sops:unstable + config.kubernetes.io/local-config: "true" +data: + cmd: 'encrypt' + cmd-json-path-filter: '$[?(@.metadata.name=="toEncrypt")]' + age: 'age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw' + unencrypted-regex: '^(kind|apiVersion|group|metadata)$' + diff --git a/examples/contrib/sops/age/to-decrypt.yaml b/examples/contrib/sops/age/to-decrypt.yaml new file mode 100644 index 000000000..cf00318c0 --- /dev/null +++ b/examples/contrib/sops/age/to-decrypt.yaml @@ -0,0 +1,27 @@ +apiVersion: v1 +kind: somekind +metadata: + name: toDecrypt +nnn-password: ENC[AES256_GCM,data:G2i53KNBoAEycMHD5w==,iv:PjywQXtBGZDgn5zNgI/0BsKiov7drduyyXSt8gNtdDs=,tag:slGGtNbvT01rtgDb1pCkFw==,type:str] +user-password: ENC[AES256_GCM,data:iM5w/l6egeDlvkjc2tpk,iv:kBtgkTNuNuUL6FvYGa+NA0U0jkcmm0IIRZ8j5PicSMs=,tag:lACKq9kbf4n72xFmZb1Ymw==,type:str] +k8s-password: ENC[AES256_GCM,data:uZb3qTvx3Ucq,iv:VQTP3fimb3uitY/0LuJMhvdjd2s9bq8xguWgTOkCqG4=,tag:4JT50F72xL5Gyy5mqGjkrg==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBsR2ZvT21Bd2NuWnBXaFZa + OG9YUzg2b1g1VDQ3bHlaSGdMQW10UE9jYjEwCndSbWpDdis4S1IyOFdxL2U4eDVL + cG00RUxpcE1IRnR3cVk0dDJtK3Zwc00KLS0tIHhuNlVTakF1a3dyZFF4ZWg3TXFE + QzFjYmR1MVh3bVhydURmZ25ORmQxNGsKkcHUujLrlwycauIr1nJ9O9KG4T6NkmMv + 8szwCF4AuqHzhSKhqGzYUnRQB1Igfpw85XjdR5O1aCf0mux/+E6Ihg== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2021-04-27T04:12:50Z" + mac: ENC[AES256_GCM,data:darUiOLASNLXAMucmoQsaMvAk6KmMkb5owGfv38vsaF8JDXhxom0B6MTp2KRyiliv2KICEWv8BRofNXWQpgKGwvS8CPmZic7JgqdJhNpNVrt5NipisMcCigUVdk7WtQ73l7tTuqI5vBg9FnrnDgndnTr4CoqjxwThlbTtNy7+30=,iv:WmiLyZMMtsyL3KOTaki6EClKAyJ2KcVxanxcVJZGalo=,tag:ZJOBM+1NiyDN0a+OSndG6Q==,type:str] + pgp: [] + unencrypted_regex: ^(kind|apiVersion|group|metadata)$ + version: 3.7.1 diff --git a/examples/contrib/sops/to-encrypt.yaml b/examples/contrib/sops/age/to-encrypt.yaml similarity index 100% rename from examples/contrib/sops/to-encrypt.yaml rename to examples/contrib/sops/age/to-encrypt.yaml diff --git a/examples/contrib/sops/gpg/README.md b/examples/contrib/sops/gpg/README.md new file mode 100644 index 000000000..19920a021 --- /dev/null +++ b/examples/contrib/sops/gpg/README.md @@ -0,0 +1,34 @@ +# sops: PGP example + +### Overview + +The `sops` KRM config function encrypts and decrypts resources. Learn more on the [sops website]. + +This example demonstrates invocation of `sops` for encryption the resouce called `toEncrypt` and decryption of the resource called `toDecrypt` using the already existing PGP keys. + +## Function invocation + +Get this example and try it out by running the following commands: + +```shell +# download this example +kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/contrib/sops/gpg . + +# copy example GPG key from sops project +curl -fsSL -o gpg_keys.asc https://raw.githubusercontent.com/mozilla/sops/master/pgp/sops_functional_tests_key.asc + +# run the function to work with GPG +SOPS_IMPORT_PGP="$(cat gpg_keys.asc)" kpt fn run gpg +``` + +## Expected result + +Verify the updated configuration: + +```shell +kpt cfg cat gpg +``` + +The resource called `toDecrypt` must be decrypted and the resource called `toEncrypt` must be encrypted. + +[sops website]: https://github.com/mozilla/sops#test-with-the-dev-pgp-key diff --git a/examples/contrib/sops/function.yaml b/examples/contrib/sops/gpg/function.yaml similarity index 100% rename from examples/contrib/sops/function.yaml rename to examples/contrib/sops/gpg/function.yaml diff --git a/examples/contrib/sops/to-decrypt.yaml b/examples/contrib/sops/gpg/to-decrypt.yaml similarity index 100% rename from examples/contrib/sops/to-decrypt.yaml rename to examples/contrib/sops/gpg/to-decrypt.yaml diff --git a/examples/contrib/sops/gpg/to-encrypt.yaml b/examples/contrib/sops/gpg/to-encrypt.yaml new file mode 100644 index 000000000..3f2c18faf --- /dev/null +++ b/examples/contrib/sops/gpg/to-encrypt.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: somekind +metadata: + name: toEncrypt +nnn-password: password1 +user-password: password2 +k8s-password: password3 diff --git a/examples/enforce-gatekeeper/invalid-configmap/.expected/config.yaml b/examples/enforce-gatekeeper/invalid-configmap/.expected/config.yaml index 28ffd5bd9..f6237512c 100644 --- a/examples/enforce-gatekeeper/invalid-configmap/.expected/config.yaml +++ b/examples/enforce-gatekeeper/invalid-configmap/.expected/config.yaml @@ -1,2 +1 @@ exitCode: 1 -runCount: 2 diff --git a/examples/enforce-gatekeeper/invalid-configmap/.expected/results.yaml b/examples/enforce-gatekeeper/invalid-configmap/.expected/results.yaml index ffd5e18cf..ad9ea8450 100644 --- a/examples/enforce-gatekeeper/invalid-configmap/.expected/results.yaml +++ b/examples/enforce-gatekeeper/invalid-configmap/.expected/results.yaml @@ -1,14 +1,24 @@ +apiVersion: kpt.dev/v1alpha2 +kind: FunctionResultList +metadata: + name: fnresults +exitCode: 1 items: -- message: |- - The following banned keys are being used in the ConfigMap: {"private_key"} - violatedConstraint: no-secrets-in-configmap - severity: error - resourceRef: - apiVersion: v1 - kind: ConfigMap - metadata: - name: super-secret - namespace: default - file: - path: resources.yaml - index: 2 + - image: gcr.io/kpt-fn/enforce-gatekeeper:unstable + stderr: |- + The following banned keys are being used in the ConfigMap: {"private_key"} + violatedConstraint: no-secrets-in-configmap + exitCode: 1 + results: + - message: |- + The following banned keys are being used in the ConfigMap: {"private_key"} + violatedConstraint: no-secrets-in-configmap + severity: error + resourceRef: + apiVersion: v1 + kind: ConfigMap + name: super-secret + namespace: default + file: + path: resources.yaml + index: 2 diff --git a/examples/enforce-gatekeeper/invalid-configmap/Kptfile b/examples/enforce-gatekeeper/invalid-configmap/Kptfile new file mode 100644 index 000000000..730a14ffe --- /dev/null +++ b/examples/enforce-gatekeeper/invalid-configmap/Kptfile @@ -0,0 +1,7 @@ +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile +metadata: + name: example +pipeline: + validators: + - image: gcr.io/kpt-fn/enforce-gatekeeper:unstable diff --git a/examples/enforce-gatekeeper/invalid-configmap/README.md b/examples/enforce-gatekeeper/invalid-configmap/README.md index f0b0d245f..de2d9f907 100644 --- a/examples/enforce-gatekeeper/invalid-configmap/README.md +++ b/examples/enforce-gatekeeper/invalid-configmap/README.md @@ -1,62 +1,69 @@ -# enforce-gatekeeper: invalid configmap - -## Overview - -This example demonstrates how to validate ConfigMaps using a constraint. - -There are 3 resources: a ConstraintTemplate, a K8sBannedConfigMapKeysV1 and a -ConfigMap. -The constraint disallows using `private_key` as a key in the ConfigMap. +# enforce-gatekeeper: Invalid ConfigMap + +### Overview + +This example demonstrates how to declaratively run the [enforce-gatekeeper] +function to validate resources using gatekeeper constraints. + +There are 3 resources: a `ConstraintTemplate`, a `K8sBannedConfigMapKeysV1` and +a `ConfigMap`. +The constraint disallows using `private_key` as a key in the `ConfigMap`. + +Here's an example Kptfile to run the function: +```yaml +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile +metadata: + name: example +pipeline: + validators: + - image: gcr.io/kpt-fn/enforce-gatekeeper:unstable +``` -## Function invocation +### Function invocation Get the package: - ```shell $ kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/enforce-gatekeeper/invalid-configmap . ``` -Create a directory for storing the structured output. - -```shell -$ cd invalid-configmap -$ mkdir results -``` - Run the function: ```shell -$ kpt fn run --results-dir=results . +$ kpt fn render invalid-configmap --results-dir=/tmp ``` -## Expected result - -You should see the following output: +### Expected result -``` -The following banned keys are being used in the ConfigMap: {"private_key"} -violatedConstraint: no-secrets-in-configmaperror: exit status 1 -``` +Let's take a look at the structured results in `/tmp/results.yaml`: -Let's take a look at the structured output: - -```shell -$ cat results/results-0.yaml +```yaml +apiVersion: kpt.dev/v1alpha2 +kind: FunctionResultList +metadata: + name: fnresults +exitCode: 1 items: -- message: |- - The following banned keys are being used in the ConfigMap: {"private_key"} - violatedConstraint: no-secrets-in-configmap - severity: error - resourceRef: - apiVersion: v1 - kind: ConfigMap - metadata: - name: super-secret - namespace: default - file: - path: resources.yaml - index: 2 + - image: gcr.io/kpt-fn/enforce-gatekeeper:unstable + stderr: |- + The following banned keys are being used in the ConfigMap: {"private_key"} + violatedConstraint: no-secrets-in-configmap + exitCode: 1 + results: + - message: |- + The following banned keys are being used in the ConfigMap: {"private_key"} + violatedConstraint: no-secrets-in-configmap + severity: error + resourceRef: + apiVersion: v1 + kind: ConfigMap + metadata: + name: super-secret + namespace: default + file: + path: resources.yaml + index: 2 ``` You can find: @@ -65,11 +72,8 @@ You can find: - what constraint does it violate - where does the resource live and its index in the file -To pass validation, let's replace the key `private_key` in the ConfigMap in +To pass validation, let's replace the key `private_key` in the `ConfigMap` in `resources.yaml` with something else e.g. `public_key`. -Rerun the command. It will succeed (no output). - -## Function Reference Doc +Rerun the command. It will succeed. -TODO: replace the following with the link to the reference doc when our site is live. -https://github.com/GoogleContainerTools/kpt-functions-catalog/blob/master/functions/go/enforce-gatekeeper/README.md +[enforce-gatekeeper]: https://catalog.kpt.dev/enforce-gatekeeper/v0.1/ diff --git a/examples/enforce-gatekeeper/invalid-configmap/fn-config.yaml b/examples/enforce-gatekeeper/invalid-configmap/fn-config.yaml deleted file mode 100644 index f7e4c1ef7..000000000 --- a/examples/enforce-gatekeeper/invalid-configmap/fn-config.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: my-func-config - annotations: - config.k8s.io/function: | - container: - image: gcr.io/kpt-fn/enforce-gatekeeper:unstable - config.kubernetes.io/local-config: 'true' diff --git a/examples/enforce-gatekeeper/warning-only/.expected/results.yaml b/examples/enforce-gatekeeper/warning-only/.expected/results.yaml index 5674fe460..81ffd3d4c 100644 --- a/examples/enforce-gatekeeper/warning-only/.expected/results.yaml +++ b/examples/enforce-gatekeeper/warning-only/.expected/results.yaml @@ -1,14 +1,21 @@ +apiVersion: kpt.dev/v1alpha2 +kind: FunctionResultList +metadata: + name: fnresults +exitCode: 0 items: -- message: |- - The following banned keys are being used in the ConfigMap: {"private_key"} - violatedConstraint: no-secrets-in-configmap - severity: warning - resourceRef: - apiVersion: v1 - kind: ConfigMap - metadata: - name: super-secret - namespace: default - file: - path: resources.yaml - index: 2 + - image: gcr.io/kpt-fn/enforce-gatekeeper:unstable + exitCode: 0 + results: + - message: |- + The following banned keys are being used in the ConfigMap: {"private_key"} + violatedConstraint: no-secrets-in-configmap + severity: warning + resourceRef: + apiVersion: v1 + kind: ConfigMap + name: super-secret + namespace: default + file: + path: resources.yaml + index: 2 diff --git a/examples/enforce-gatekeeper/warning-only/Kptfile b/examples/enforce-gatekeeper/warning-only/Kptfile new file mode 100644 index 000000000..730a14ffe --- /dev/null +++ b/examples/enforce-gatekeeper/warning-only/Kptfile @@ -0,0 +1,7 @@ +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile +metadata: + name: example +pipeline: + validators: + - image: gcr.io/kpt-fn/enforce-gatekeeper:unstable diff --git a/examples/enforce-gatekeeper/warning-only/README.md b/examples/enforce-gatekeeper/warning-only/README.md index ac59a6e66..0d25e8dfb 100644 --- a/examples/enforce-gatekeeper/warning-only/README.md +++ b/examples/enforce-gatekeeper/warning-only/README.md @@ -1,56 +1,77 @@ -# enforce-gatekeeper: warning only +# enforce-gatekeeper: Warning Only -## Overview +### Overview -This example is very similar to the invalid configmap example. The major -difference is that the violations are warnings instead of errors. +This example demonstrates how to declaratively run the [enforce-gatekeeper] +function to validate resources using gatekeeper constraints. The violations are +configured to be warnings instead of errors. + +Here's an example `Kptfile` to run the function: + +```yaml +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile +metadata: + name: example +pipeline: + validators: + - image: gcr.io/kpt-fn/enforce-gatekeeper:unstable +``` In the constraint, we use `enforcementAction: warn` instead of `enforcementAction: deny`. -## Function invocation +```yaml +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sBannedConfigMapKeysV1 +metadata: + name: no-secrets-in-configmap +spec: + enforcementAction: warn + ... +``` + +### Function invocation Get the package: - ```shell $ kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/enforce-gatekeeper/warning-only . ``` -Create a directory for storing the structured output. - -```shell -$ cd warnning-only -$ mkdir results -``` - Run the function: ```shell -$ kpt fn run --results-dir=results . +$ kpt fn render warning-only --results-dir=/tmp ``` -## Expected result +### Expected result -You won't any failure. But if you look at the structured output, you can find a -warning about the constraint violation. +Let's take a look at the structured results in `/tmp/results.yaml`: ```shell -$ cat results/results-0.yaml +apiVersion: kpt.dev/v1alpha2 +kind: FunctionResultList +metadata: + name: fnresults +exitCode: 0 items: -- message: |- - The following banned keys are being used in the ConfigMap map: {"private_key"} - violatedConstraint: no-secrets-in-configmap - severity: warning - resourceRef: - apiVersion: v1 - kind: ConfigMap - metadata: - name: super-secret - namespace: default - file: - path: resources.yaml - index: 2 + - image: gcr.io/kpt-fn/enforce-gatekeeper:unstable + exitCode: 0 + results: + - message: |- + The following banned keys are being used in the ConfigMap: {"private_key"} + violatedConstraint: no-secrets-in-configmap + severity: warning + resourceRef: + apiVersion: v1 + kind: ConfigMap + metadata: + name: super-secret + namespace: default + file: + path: resources.yaml + index: 2 ``` You can find: @@ -59,11 +80,8 @@ You can find: - what constraint does it violate - where does the resource live and its index in the file -To pass validation, let's replace the key `private_key` in the ConfigMap in +To pass validation, let's replace the key `private_key` in the `ConfigMap` in `resources.yaml` with something else e.g. `public_key`. Rerun the command. It will no longer have the warning. -## Function Reference Doc - -TODO: replace the following with the link to the reference doc when our site is live. -https://github.com/GoogleContainerTools/kpt-functions-catalog/blob/master/functions/go/enforce-gatekeeper/README.md +[enforce-gatekeeper]: https://catalog.kpt.dev/enforce-gatekeeper/v0.1/ diff --git a/examples/enforce-gatekeeper/warning-only/fn-config.yaml b/examples/enforce-gatekeeper/warning-only/fn-config.yaml deleted file mode 100644 index f7e4c1ef7..000000000 --- a/examples/enforce-gatekeeper/warning-only/fn-config.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: my-func-config - annotations: - config.k8s.io/function: | - container: - image: gcr.io/kpt-fn/enforce-gatekeeper:unstable - config.kubernetes.io/local-config: 'true' diff --git a/examples/enforce-gatekeeper/warning-only/resources.yaml b/examples/enforce-gatekeeper/warning-only/resources.yaml index 28a1df7e3..d360301c2 100644 --- a/examples/enforce-gatekeeper/warning-only/resources.yaml +++ b/examples/enforce-gatekeeper/warning-only/resources.yaml @@ -15,17 +15,17 @@ spec: items: type: string targets: - - rego: |- - package ban_keys + - rego: |- + package ban_keys - violation[{"msg": sprintf("%v", [val])}] { - keys = {key | input.review.object.data[key]} - banned = {key | input.parameters.keys[_] = key} - overlap = keys & banned - count(overlap) > 0 - val := sprintf("The following banned keys are being used in the ConfigMap: %v", [overlap]) - } - target: admission.k8s.gatekeeper.sh + violation[{"msg": sprintf("%v", [val])}] { + keys = {key | input.review.object.data[key]} + banned = {key | input.parameters.keys[_] = key} + overlap = keys & banned + count(overlap) > 0 + val := sprintf("The following banned keys are being used in the ConfigMap: %v", [overlap]) + } + target: admission.k8s.gatekeeper.sh --- apiVersion: constraints.gatekeeper.sh/v1beta1 kind: K8sBannedConfigMapKeysV1 @@ -35,13 +35,13 @@ spec: enforcementAction: warn match: kinds: - - apiGroups: - - '' - kinds: - - ConfigMap + - apiGroups: + - '' + kinds: + - ConfigMap parameters: keys: - - private_key + - private_key --- apiVersion: v1 kind: ConfigMap diff --git a/examples/ensure-name-substring/advanced/.expected/config.yaml b/examples/ensure-name-substring/advanced/.expected/config.yaml deleted file mode 100644 index f7b0b32ed..000000000 --- a/examples/ensure-name-substring/advanced/.expected/config.yaml +++ /dev/null @@ -1 +0,0 @@ -runCount: 2 diff --git a/examples/ensure-name-substring/advanced/.expected/diff.patch b/examples/ensure-name-substring/advanced/.expected/diff.patch index 169fa82e9..5edaecfeb 100644 --- a/examples/ensure-name-substring/advanced/.expected/diff.patch +++ b/examples/ensure-name-substring/advanced/.expected/diff.patch @@ -1,27 +1,5 @@ -diff --git a/fn-config.yaml b/fn-config.yaml -deleted file mode 100644 -index 4638b32..0000000 ---- a/fn-config.yaml -+++ /dev/null -@@ -1,16 +0,0 @@ --apiVersion: fn.kpt.dev/v1alpha1 --kind: EnsureNameSubstring --metadata: -- name: my-config -- annotations: -- config.k8s.io/function: | -- container: -- image: gcr.io/kpt-fn/ensure-name-substring:unstable -- config.kubernetes.io/local-config: 'true' --substring: prod- --editMode: prepend --fieldSpecs: --- group: dev.example.com -- version: v1 -- kind: MyResource -- path: spec/name diff --git a/resources.yaml b/resources.yaml -index 9e83cfa..7f688d6 100644 +index eb74e1b..882834d 100644 --- a/resources.yaml +++ b/resources.yaml @@ -1,14 +1,14 @@ diff --git a/examples/ensure-name-substring/advanced/Kptfile b/examples/ensure-name-substring/advanced/Kptfile new file mode 100644 index 000000000..089cc9024 --- /dev/null +++ b/examples/ensure-name-substring/advanced/Kptfile @@ -0,0 +1,8 @@ +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile +metadata: + name: example +pipeline: + mutators: + - image: gcr.io/kpt-fn/ensure-name-substring:unstable + configPath: fn-config.yaml diff --git a/examples/ensure-name-substring/advanced/README.md b/examples/ensure-name-substring/advanced/README.md index 108782a24..fe27a8eaf 100644 --- a/examples/ensure-name-substring/advanced/README.md +++ b/examples/ensure-name-substring/advanced/README.md @@ -1,20 +1,29 @@ # ensure-name-substring: Advanced Example -Note: This is an alpha function, and we are actively seeking feedback on the -function config syntax and behavior. If you have suggestion or feedback, please -file an issue [here](https://github.com/GoogleContainerTools/kpt/issues/new/choose). +### Overview -In this example, we use the function `ensure-name-substring` to ensure every -resource name and the field declared in the field specs contain the desired name -substring. We prepend the substring if it doesn't exist. +This example demonstrates how to declaratively run the [`ensure-name-substring`] +function to prepend prefix in the resource names. -We use the following CustomResource to configure the function. +We use the following `Kptfile` and `fn-config.yaml` to run the function. ```yaml +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile +metadata: + name: example +pipeline: + mutators: + - image: gcr.io/kpt-fn/ensure-name-substring:unstable + configPath: fn-config.yaml +``` + +```yaml +# fn-config.yaml apiVersion: fn.kpt.dev/v1alpha1 kind: EnsureNameSubstring metadata: - ... + name: my-config substring: prod- editMode: prepend fieldSpecs: @@ -24,24 +33,22 @@ fieldSpecs: path: spec/name ``` +We are going to prepend prefix `prod-` to resource names. The function will not only update field `.metadata.name` but also field `.spec.name` in `MyResource`. -## Function invocation +### Function invocation Get the config example and try it out by running the following commands: - -```sh -kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/ensure-name-substring/advanced . -kpt fn run advanced +```shell +$ kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/ensure-name-substring/advanced . +$ kpt fn render advanced ``` -## Expected result +### Expected result Check all resources have `prod-` in their names and the field `.spec.name` in `MyResource` also got updated. -```sh -kpt cfg cat advanced -``` +[ensure-name-substring]: https://catalog.kpt.dev/ensure-name-substring/v0.1/ diff --git a/examples/ensure-name-substring/advanced/fn-config.yaml b/examples/ensure-name-substring/advanced/fn-config.yaml index 4638b3232..84f999fa1 100644 --- a/examples/ensure-name-substring/advanced/fn-config.yaml +++ b/examples/ensure-name-substring/advanced/fn-config.yaml @@ -2,15 +2,10 @@ apiVersion: fn.kpt.dev/v1alpha1 kind: EnsureNameSubstring metadata: name: my-config - annotations: - config.k8s.io/function: | - container: - image: gcr.io/kpt-fn/ensure-name-substring:unstable - config.kubernetes.io/local-config: 'true' -substring: prod- editMode: prepend fieldSpecs: -- group: dev.example.com - version: v1 - kind: MyResource - path: spec/name + - kind: MyResource + group: dev.example.com + path: spec/name + version: v1 +substring: prod- diff --git a/examples/ensure-name-substring/advanced/resources.yaml b/examples/ensure-name-substring/advanced/resources.yaml index 9e83cfa16..eb74e1bb1 100644 --- a/examples/ensure-name-substring/advanced/resources.yaml +++ b/examples/ensure-name-substring/advanced/resources.yaml @@ -12,18 +12,18 @@ metadata: namespace: the-namespace spec: containers: - - name: test-container - image: k8s.gcr.io/busybox - command: - - /bin/sh - - -c - - env - env: - - name: SOME_KEY - valueFrom: - configMapKeyRef: - name: the-map - key: some-key + - name: test-container + image: k8s.gcr.io/busybox + command: + - /bin/sh + - -c + - env + env: + - name: SOME_KEY + valueFrom: + configMapKeyRef: + name: the-map + key: some-key --- apiVersion: v1 kind: Service @@ -32,10 +32,10 @@ metadata: namespace: the-namespace spec: ports: - - name: etcd-server-ssl - port: 2380 - - name: etcd-client-ssl - port: 2379 + - name: etcd-server-ssl + port: 2380 + - name: etcd-client-ssl + port: 2379 clusterIP: None publishNotReadyAddresses: true --- diff --git a/examples/ensure-name-substring/prefix/.expected/config.yaml b/examples/ensure-name-substring/prefix/.expected/config.yaml deleted file mode 100644 index f7b0b32ed..000000000 --- a/examples/ensure-name-substring/prefix/.expected/config.yaml +++ /dev/null @@ -1 +0,0 @@ -runCount: 2 diff --git a/examples/ensure-name-substring/prefix/.expected/diff.patch b/examples/ensure-name-substring/prefix/.expected/diff.patch index b5942848c..491a3e02c 100644 --- a/examples/ensure-name-substring/prefix/.expected/diff.patch +++ b/examples/ensure-name-substring/prefix/.expected/diff.patch @@ -1,22 +1,5 @@ -diff --git a/fn-config.yaml b/fn-config.yaml -deleted file mode 100644 -index 22a9533..0000000 ---- a/fn-config.yaml -+++ /dev/null -@@ -1,11 +0,0 @@ --apiVersion: v1 --kind: ConfigMap --metadata: -- name: my-config -- annotations: -- config.k8s.io/function: | -- container: -- image: gcr.io/kpt-fn/ensure-name-substring:unstable -- config.kubernetes.io/local-config: 'true' --data: -- prepend: prod- diff --git a/resources.yaml b/resources.yaml -index df7fdf7..db12c67 100644 +index cff6bae..80988f6 100644 --- a/resources.yaml +++ b/resources.yaml @@ -1,7 +1,7 @@ @@ -38,11 +21,11 @@ index df7fdf7..db12c67 100644 spec: containers: @@ -23,7 +23,7 @@ spec: - - name: SOME_KEY - valueFrom: - configMapKeyRef: -- name: the-map -+ name: prod-the-map - key: some-key + - name: SOME_KEY + valueFrom: + configMapKeyRef: +- name: the-map ++ name: prod-the-map + key: some-key --- apiVersion: v1 diff --git a/examples/ensure-name-substring/prefix/Kptfile b/examples/ensure-name-substring/prefix/Kptfile new file mode 100644 index 000000000..09b3c0386 --- /dev/null +++ b/examples/ensure-name-substring/prefix/Kptfile @@ -0,0 +1,9 @@ +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile +metadata: + name: example +pipeline: + mutators: + - image: gcr.io/kpt-fn/ensure-name-substring:unstable + configMap: + prepend: prod- diff --git a/examples/ensure-name-substring/prefix/README.md b/examples/ensure-name-substring/prefix/README.md index e1ff71132..0ddc63824 100644 --- a/examples/ensure-name-substring/prefix/README.md +++ b/examples/ensure-name-substring/prefix/README.md @@ -1,41 +1,40 @@ # ensure-name-substring: Prefix Example -Note: This is an alpha function, and we are actively seeking feedback on the -function config syntax and behavior. If you have suggestion or feedback, please -file an issue [here](https://github.com/GoogleContainerTools/kpt/issues/new/choose). +### Overview -In this example, we use the function `ensure-name-substring` to ensure every -resource name contains the desired name substring. We prepend the substring if -it doesn't exist. +This example demonstrates how to declaratively run the [`ensure-name-substring`] +function to prepend prefix in the resource names. -We use the following ConfigMap to configure the function. +We use the following `Kptfile` to run the function. ```yaml -apiVersion: v1 -kind: ConfigMap +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile metadata: - ... -data: - prepend: prod- + name: example +pipeline: + mutators: + - image: gcr.io/kpt-fn/ensure-name-substring:unstable + configMap: + prepend: prod- ``` -## Function invocation +We are going to prepend prefix `prod-` to resource names. + +### Function invocation Get the config example and try it out by running the following commands: - -```sh -kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/ensure-name-substring/prefix . -kpt fn run prefix +```shell +$ kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/ensure-name-substring/prefix . +$ kpt fn render prefix ``` -## Expected result +### Expected result Check all resources have `prod-` in their names: -```sh -kpt cfg cat prefix -``` - We have a `Service` object whose name is `with-prod-service` which already -contains `prod-`. This function will skip it. +contains substring `prod-`. This resource will be skipped. + +[ensure-name-substring]: https://catalog.kpt.dev/ensure-name-substring/v0.1/ diff --git a/examples/ensure-name-substring/prefix/fn-config.yaml b/examples/ensure-name-substring/prefix/fn-config.yaml deleted file mode 100644 index 22a9533c0..000000000 --- a/examples/ensure-name-substring/prefix/fn-config.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: my-config - annotations: - config.k8s.io/function: | - container: - image: gcr.io/kpt-fn/ensure-name-substring:unstable - config.kubernetes.io/local-config: 'true' -data: - prepend: prod- diff --git a/examples/ensure-name-substring/prefix/resources.yaml b/examples/ensure-name-substring/prefix/resources.yaml index df7fdf79d..cff6bae45 100644 --- a/examples/ensure-name-substring/prefix/resources.yaml +++ b/examples/ensure-name-substring/prefix/resources.yaml @@ -13,18 +13,18 @@ metadata: namespace: the-namespace spec: containers: - - name: test-container - image: k8s.gcr.io/busybox - command: - - /bin/sh - - -c - - env - env: - - name: SOME_KEY - valueFrom: - configMapKeyRef: - name: the-map - key: some-key + - name: test-container + image: k8s.gcr.io/busybox + command: + - /bin/sh + - -c + - env + env: + - name: SOME_KEY + valueFrom: + configMapKeyRef: + name: the-map + key: some-key --- apiVersion: v1 kind: Service @@ -33,10 +33,10 @@ metadata: namespace: the-namespace spec: ports: - - name: etcd-server-ssl - port: 2380 - - name: etcd-client-ssl - port: 2379 + - name: etcd-server-ssl + port: 2380 + - name: etcd-client-ssl + port: 2379 clusterIP: None publishNotReadyAddresses: true --- diff --git a/examples/ensure-name-substring/suffix/.expected/config.yaml b/examples/ensure-name-substring/suffix/.expected/config.yaml deleted file mode 100644 index f7b0b32ed..000000000 --- a/examples/ensure-name-substring/suffix/.expected/config.yaml +++ /dev/null @@ -1 +0,0 @@ -runCount: 2 diff --git a/examples/ensure-name-substring/suffix/.expected/diff.patch b/examples/ensure-name-substring/suffix/.expected/diff.patch index 46e2d626e..b76eb86e4 100644 --- a/examples/ensure-name-substring/suffix/.expected/diff.patch +++ b/examples/ensure-name-substring/suffix/.expected/diff.patch @@ -1,22 +1,5 @@ -diff --git a/fn-config.yaml b/fn-config.yaml -deleted file mode 100644 -index a8afaf6..0000000 ---- a/fn-config.yaml -+++ /dev/null -@@ -1,11 +0,0 @@ --apiVersion: v1 --kind: ConfigMap --metadata: -- name: my-config -- annotations: -- config.k8s.io/function: | -- container: -- image: gcr.io/kpt-fn/ensure-name-substring:unstable -- config.kubernetes.io/local-config: 'true' --data: -- append: -prod diff --git a/resources.yaml b/resources.yaml -index 57e3699..23acbbb 100644 +index 675f126..3d09911 100644 --- a/resources.yaml +++ b/resources.yaml @@ -1,7 +1,7 @@ @@ -38,11 +21,11 @@ index 57e3699..23acbbb 100644 spec: containers: @@ -23,7 +23,7 @@ spec: - - name: SOME_KEY - valueFrom: - configMapKeyRef: -- name: the-map -+ name: the-map-prod - key: some-key + - name: SOME_KEY + valueFrom: + configMapKeyRef: +- name: the-map ++ name: the-map-prod + key: some-key --- apiVersion: v1 diff --git a/examples/ensure-name-substring/suffix/Kptfile b/examples/ensure-name-substring/suffix/Kptfile new file mode 100644 index 000000000..ad065ef80 --- /dev/null +++ b/examples/ensure-name-substring/suffix/Kptfile @@ -0,0 +1,9 @@ +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile +metadata: + name: example +pipeline: + mutators: + - image: gcr.io/kpt-fn/ensure-name-substring:unstable + configMap: + append: -prod diff --git a/examples/ensure-name-substring/suffix/README.md b/examples/ensure-name-substring/suffix/README.md index 1208c6f6b..4ded3d4df 100644 --- a/examples/ensure-name-substring/suffix/README.md +++ b/examples/ensure-name-substring/suffix/README.md @@ -1,41 +1,40 @@ # ensure-name-substring: Suffix Example -Note: This is an alpha function, and we are actively seeking feedback on the -function config syntax and behavior. If you have suggestion or feedback, please -file an issue [here](https://github.com/GoogleContainerTools/kpt/issues/new/choose). +### Overview -In this example, we use the function `ensure-name-substring` to ensure every -resource name contains the desired name substring. We append the substring if it -doesn't exist. +This example demonstrates how to declaratively run the [`ensure-name-substring`] +function to append suffix in the resource names. -We use the following ConfigMap to configure the function. +We use the following `Kptfile` to run the function. ```yaml -apiVersion: v1 -kind: ConfigMap +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile metadata: - ... -data: - append: -prod + name: example +pipeline: + mutators: + - image: gcr.io/kpt-fn/ensure-name-substring:unstable + configMap: + append: -prod ``` -## Function invocation +We are going to append suffix `-prod` to resource names. + +### Function invocation Get the config example and try it out by running the following commands: - -```sh -kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/ensure-name-substring/suffix . -kpt fn run suffix +```shell +$ kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/ensure-name-substring/suffix . +$ kpt fn render suffix ``` -## Expected result +### Expected result Check all resources have `-prod` in their names: -```sh -kpt cfg cat suffix -``` - We have a `Service` object whose name is `the-service-prod` which already -contains `-prod`. This function will skip it. +contains substring`-prod`. This resource will be skipped. + +[ensure-name-substring]: https://catalog.kpt.dev/ensure-name-substring/v0.1/ diff --git a/examples/ensure-name-substring/suffix/fn-config.yaml b/examples/ensure-name-substring/suffix/fn-config.yaml deleted file mode 100644 index a8afaf6a7..000000000 --- a/examples/ensure-name-substring/suffix/fn-config.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: my-config - annotations: - config.k8s.io/function: | - container: - image: gcr.io/kpt-fn/ensure-name-substring:unstable - config.kubernetes.io/local-config: 'true' -data: - append: -prod diff --git a/examples/ensure-name-substring/suffix/resources.yaml b/examples/ensure-name-substring/suffix/resources.yaml index 57e3699ca..675f12620 100644 --- a/examples/ensure-name-substring/suffix/resources.yaml +++ b/examples/ensure-name-substring/suffix/resources.yaml @@ -13,18 +13,18 @@ metadata: namespace: the-namespace spec: containers: - - name: test-container - image: k8s.gcr.io/busybox - command: - - /bin/sh - - -c - - env - env: - - name: SOME_KEY - valueFrom: - configMapKeyRef: - name: the-map - key: some-key + - name: test-container + image: k8s.gcr.io/busybox + command: + - /bin/sh + - -c + - env + env: + - name: SOME_KEY + valueFrom: + configMapKeyRef: + name: the-map + key: some-key --- apiVersion: v1 kind: Service @@ -33,10 +33,10 @@ metadata: namespace: the-namespace spec: ports: - - name: etcd-server-ssl - port: 2380 - - name: etcd-client-ssl - port: 2379 + - name: etcd-server-ssl + port: 2380 + - name: etcd-client-ssl + port: 2379 clusterIP: None publishNotReadyAddresses: true --- diff --git a/examples/fix/simple/.expected/config.yaml b/examples/fix/simple/.expected/config.yaml new file mode 100644 index 000000000..5c8560754 --- /dev/null +++ b/examples/fix/simple/.expected/config.yaml @@ -0,0 +1,4 @@ +runCount: 1 +testType: eval +image: gcr.io/kpt-fn/fix:unstable +includeMetaResources: true diff --git a/examples/fix/simple/.expected/diff.patch b/examples/fix/simple/.expected/diff.patch new file mode 100644 index 000000000..ef995614e --- /dev/null +++ b/examples/fix/simple/.expected/diff.patch @@ -0,0 +1,52 @@ +diff --git a/Kptfile b/Kptfile +index a8e7f27..24aae1f 100644 +--- a/Kptfile ++++ b/Kptfile +@@ -1,20 +1,24 @@ +-apiVersion: kpt.dev/v1alpha1 ++apiVersion: kpt.dev/v1alpha2 + kind: Kptfile + metadata: + name: nginx +-packageMetadata: +- shortDescription: describe this package + upstream: + type: git + git: +- commit: 4d2aa98b45ddee4b5fa45fbca16f2ff887de9efb + repo: https://github.com/GoogleContainerTools/kpt + directory: package-examples/nginx + ref: v0.2 +-openAPI: +- definitions: +- io.k8s.cli.setters.name: +- x-k8s-cli: +- setter: +- name: name +- value: the-map ++ updateStrategy: resource-merge ++upstreamLock: ++ type: git ++ git: ++ repo: https://github.com/GoogleContainerTools/kpt ++ directory: package-examples/nginx ++ ref: v0.2 ++info: ++ description: describe this package ++pipeline: ++ mutators: ++ - image: gcr.io/kpt-fn/apply-setters:v0.1 ++ configMap: ++ name: the-map +diff --git a/resources.yaml b/resources.yaml +index 9e30767..dae3005 100644 +--- a/resources.yaml ++++ b/resources.yaml +@@ -1,6 +1,6 @@ + apiVersion: v1 + kind: ConfigMap + metadata: +- name: the-map # {"$kpt-set":"name"} ++ name: the-map # kpt-set: ${name} + data: + some-key: some-value diff --git a/examples/fix/simple/.krmignore b/examples/fix/simple/.krmignore new file mode 100644 index 000000000..9d7a4007d --- /dev/null +++ b/examples/fix/simple/.krmignore @@ -0,0 +1 @@ +.expected diff --git a/examples/fix/simple/Kptfile b/examples/fix/simple/Kptfile new file mode 100644 index 000000000..a8e7f2758 --- /dev/null +++ b/examples/fix/simple/Kptfile @@ -0,0 +1,20 @@ +apiVersion: kpt.dev/v1alpha1 +kind: Kptfile +metadata: + name: nginx +packageMetadata: + shortDescription: describe this package +upstream: + type: git + git: + commit: 4d2aa98b45ddee4b5fa45fbca16f2ff887de9efb + repo: https://github.com/GoogleContainerTools/kpt + directory: package-examples/nginx + ref: v0.2 +openAPI: + definitions: + io.k8s.cli.setters.name: + x-k8s-cli: + setter: + name: name + value: the-map diff --git a/examples/fix/simple/README.md b/examples/fix/simple/README.md new file mode 100644 index 000000000..bdbf06113 --- /dev/null +++ b/examples/fix/simple/README.md @@ -0,0 +1,94 @@ +# fix: Simple Example + +In this example, we will fix a simple package which is compatible with v0.X version of kpt, +and make it compatible with kpt 1.0 + +Let's start with the input resources + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: the-map # {"$kpt-set":"name"} +data: + some-key: some-value +``` + +Here is an example Kptfile in the package: + +```yaml +apiVersion: kpt.dev/v1alpha1 +kind: Kptfile +metadata: + name: nginx +packageMetadata: + shortDescription: describe this package +upstream: + type: git + git: + commit: 4d2aa98b45ddee4b5fa45fbca16f2ff887de9efb + repo: https://github.com/GoogleContainerTools/kpt + directory: package-examples/nginx + ref: v0.2 +openAPI: + definitions: + io.k8s.cli.setters.name: + x-k8s-cli: + setter: + name: name + value: the-map +``` + +Invoking `fix` function on the package transforms the resources as follows: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: my-new-map # kpt-set: ${name} +data: + some-key: some-value +``` + + +```yaml +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile +metadata: + name: nginx +info: + description: describe this package +pipeline: + mutators: + - image: gcr.io/kpt-fn/apply-setters:unstable + configMap: + name: the-map +upstream: + type: git + updateStrategy: resource-merge + git: + directory: package-examples/nginx + ref: v0.2 + repo: https://github.com/GoogleContainerTools/kpt +upstreamLock: + type: git + git: + directory: package-examples/nginx + ref: v0.2 + repo: https://github.com/GoogleContainerTools/kpt +``` + +The transformed package is compatible with kpt 1.0 binary. + +### Function invocation + +Get the config example and try it out by running the following commands: + +```shell +$ kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/fix/simple . +$ kpt fn eval simple --image gcr.io/kpt-fn/fix:unstable --include-meta-resources +``` + +### Expected result + +Check the resources in the package are transformed as described above. diff --git a/examples/fix/simple/resources.yaml b/examples/fix/simple/resources.yaml new file mode 100644 index 000000000..9e307672d --- /dev/null +++ b/examples/fix/simple/resources.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: the-map # {"$kpt-set":"name"} +data: + some-key: some-value diff --git a/examples/format/imperative/.expected/config.yaml b/examples/format/imperative/.expected/config.yaml new file mode 100644 index 000000000..c6fc7696c --- /dev/null +++ b/examples/format/imperative/.expected/config.yaml @@ -0,0 +1,2 @@ +testType: eval +image: gcr.io/kpt-fn/format:unstable diff --git a/examples/format/imperative/.expected/diff.patch b/examples/format/imperative/.expected/diff.patch new file mode 100644 index 000000000..f0b031625 --- /dev/null +++ b/examples/format/imperative/.expected/diff.patch @@ -0,0 +1,37 @@ +diff --git a/resources.yaml b/resources.yaml +index 968a0f4..a33d07a 100644 +--- a/resources.yaml ++++ b/resources.yaml +@@ -1,22 +1,22 @@ + apiVersion: apps/v1 + kind: Deployment + metadata: +- labels: +- foo: bar +- env: dev + name: my-nginx + namespace: my-space ++ labels: ++ env: dev ++ foo: bar + spec: ++ replicas: 3 + selector: +- matchLabels: +- app: nginx + spec: + containers: +- - image: nginx:1.14.2 +- name: nginx +- ports: +- - containerPort: 80 +- replicas: 3 ++ - name: nginx ++ image: nginx:1.14.2 ++ ports: ++ - containerPort: 80 ++ matchLabels: ++ app: nginx + template: + metadata: + labels: diff --git a/examples/format/imperative/.krmignore b/examples/format/imperative/.krmignore new file mode 100644 index 000000000..9d7a4007d --- /dev/null +++ b/examples/format/imperative/.krmignore @@ -0,0 +1 @@ +.expected diff --git a/examples/format/imperative/README.md b/examples/format/imperative/README.md new file mode 100644 index 000000000..08d12d97c --- /dev/null +++ b/examples/format/imperative/README.md @@ -0,0 +1,23 @@ +# format: Imperative Example + +This example demonstrates how to imperatively invoke the [format] function to +format KRM resources. + +The `format` function formats the field ordering in YAML configuration files. +This example depicts the functionality of `format` function by formatting a +`Deployment` resource. + +## Function invocation + +Get the config example and try it out by running the following commands: + +```shell +$ kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/format/imperative . +$ kpt fn eval imperative --image=gcr.io/kpt-fn/format:unstable +``` + +## Expected result + +The fields should be ordered as per OpenAPI schema definition of `Deployment` +resource. For e.g. `metadata.name` field is placed before `metadata.labels` +field. The keys in `metadata.labels` field are sorted alphabetically. diff --git a/examples/format/imperative/resources.yaml b/examples/format/imperative/resources.yaml new file mode 100644 index 000000000..968a0f4b6 --- /dev/null +++ b/examples/format/imperative/resources.yaml @@ -0,0 +1,23 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + foo: bar + env: dev + name: my-nginx + namespace: my-space +spec: + selector: + matchLabels: + app: nginx + spec: + containers: + - image: nginx:1.14.2 + name: nginx + ports: + - containerPort: 80 + replicas: 3 + template: + metadata: + labels: + app: nginx diff --git a/examples/kubeval/simple/.expected/config.yaml b/examples/kubeval/simple/.expected/config.yaml index 29a1f145b..f6237512c 100644 --- a/examples/kubeval/simple/.expected/config.yaml +++ b/examples/kubeval/simple/.expected/config.yaml @@ -1,3 +1 @@ exitCode: 1 -network: true -runCount: 2 diff --git a/examples/kubeval/simple/.expected/results.yaml b/examples/kubeval/simple/.expected/results.yaml index 5117699c9..47958920b 100644 --- a/examples/kubeval/simple/.expected/results.yaml +++ b/examples/kubeval/simple/.expected/results.yaml @@ -1,22 +1,29 @@ -- message: Additional property templates is not allowed - severity: error - resourceRef: - apiVersion: v1 - kind: ReplicationController - namespace: '' - name: bob - file: - path: resources.yaml - field: - path: templates -- message: 'Invalid type. Expected: [integer,null], given: string' - severity: error - resourceRef: - apiVersion: v1 - kind: ReplicationController - namespace: '' - name: bob - file: - path: resources.yaml - field: - path: spec.replicas +apiVersion: kpt.dev/v1alpha2 +kind: FunctionResultList +metadata: + name: fnresults +exitCode: 1 +items: + - image: gcr.io/kpt-fn/kubeval:unstable + exitCode: 1 + results: + - message: Additional property templates is not allowed + severity: error + resourceRef: + apiVersion: v1 + kind: ReplicationController + name: bob + field: + path: templates + file: + path: resources.yaml + - message: 'Invalid type. Expected: [integer,null], given: string' + severity: error + resourceRef: + apiVersion: v1 + kind: ReplicationController + name: bob + field: + path: spec.replicas + file: + path: resources.yaml diff --git a/examples/kubeval/simple/Kptfile b/examples/kubeval/simple/Kptfile new file mode 100644 index 000000000..8f57fa331 --- /dev/null +++ b/examples/kubeval/simple/Kptfile @@ -0,0 +1,10 @@ +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile +metadata: + name: example +pipeline: + validators: + - image: gcr.io/kpt-fn/kubeval:v0.1 + configMap: + strict: 'true' + skip_kinds: MyCustom diff --git a/examples/kubeval/simple/README.md b/examples/kubeval/simple/README.md index e709d5b95..1e08b34f0 100644 --- a/examples/kubeval/simple/README.md +++ b/examples/kubeval/simple/README.md @@ -1,35 +1,78 @@ -# kubeval: simple example +# kubeval: Simple Example -The `kubeval` KRM config function validates Kubernetes resources using kubeval. -Learn more on the [kubeval website]. +### Overview -This example invokes the kubeval function against the builtin Kubernetes -v1.19.8 schema. +This example demonstrates how to declaratively run [`kubeval`] function to +validate KRM resources. -## Function invocation +The following is the `Kptfile` in this example: + +```yaml +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile +metadata: + name: example +pipeline: + validators: + - image: gcr.io/kpt-fn/kubeval:v0.1 + configMap: + strict: 'true' +``` + +The function configuration is provided using a `ConfigMap`. We set 2 key-value +pairs: +- `strict: 'true'`: We disallow unknown fields. +- `skip_kinds: MyCustom`: We skip resources of kind `MyCustom`. + +### Function invocation Get this example and try it out by running the following commands: - -```sh -kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/kubeval/simple . -kpt fn run simple +```shell +$ kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/kubeval/simple@kubeval/v0.1 . +$ kpt fn render simple --results-dir=/tmp ``` -## Expected Results +### Expected Results -This should give the following output: +Let's take a look at the structured results in `/tmp/results.yaml`: -```sh -[ERROR] Additional property templates is not allowed in object 'v1/ReplicationController//bob' in file resources.yaml in field templates -[ERROR] Invalid type. Expected: [integer,null], given: string in object 'v1/ReplicationController//bob' in file resources.yaml in field spec.replicas -error: exit status 1 +```yaml +apiVersion: kpt.dev/v1alpha2 +kind: FunctionResultList +metadata: + name: fnresults +exitCode: 1 +items: + - image: gcr.io/kpt-fn/kubeval:v0.1 + exitCode: 1 + results: + - message: Additional property templates is not allowed + severity: error + resourceRef: + apiVersion: v1 + kind: ReplicationController + name: bob + field: + path: templates + file: + path: resources.yaml + - message: 'Invalid type. Expected: [integer,null], given: string' + severity: error + resourceRef: + apiVersion: v1 + kind: ReplicationController + name: bob + field: + path: spec.replicas + file: + path: resources.yaml ``` There are validation error in the `resources.yaml` file, to fix them: - replace the value of `spec.replicas` with an integer - change `templates` to `template` -Rerun the command, and it will return success (no output). +Rerun the command, and it should succeed now. -[kubeval website]: https://www.kubeval.com/ +[`kubeval`]: https://catalog.kpt.dev/kubeval/v0.1/ diff --git a/examples/kubeval/simple/fn-config.yaml b/examples/kubeval/simple/fn-config.yaml deleted file mode 100644 index 30ad65fd1..000000000 --- a/examples/kubeval/simple/fn-config.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: my-func-config - annotations: - config.k8s.io/function: | - container: - image: gcr.io/kpt-fn/kubeval:unstable - config.kubernetes.io/local-config: 'true' -data: - strict: 'true' diff --git a/examples/kubeval/simple/resources.yaml b/examples/kubeval/simple/resources.yaml index ffcfa1272..beb3b6ead 100644 --- a/examples/kubeval/simple/resources.yaml +++ b/examples/kubeval/simple/resources.yaml @@ -15,7 +15,13 @@ spec: app: nginx spec: containers: - - name: nginx - image: nginx - ports: - - containerPort: 80 + - name: nginx + image: nginx + ports: + - containerPort: 80 +--- +apiVersion: example.com/v1 +kind: MyCustom +metadata: + name: alice +spec: {} diff --git a/examples/search-replace/create-setters/.expected/config.yaml b/examples/search-replace/create-setters/.expected/config.yaml new file mode 100644 index 000000000..e69de29bb diff --git a/examples/search-replace/create-setters/.expected/diff.patch b/examples/search-replace/create-setters/.expected/diff.patch new file mode 100644 index 000000000..b819347a4 --- /dev/null +++ b/examples/search-replace/create-setters/.expected/diff.patch @@ -0,0 +1,16 @@ +diff --git a/resources.yaml b/resources.yaml +index 7dde53d..7f031c6 100644 +--- a/resources.yaml ++++ b/resources.yaml +@@ -3,9 +3,9 @@ kind: Deployment + metadata: + name: my-nginx + spec: +- replicas: 3 ++ replicas: 3 # kpt-set: ${replicas} + template: + spec: + containers: + - name: nginx +- image: 'gcr.io/nginx:1.14.2' ++ image: 'gcr.io/nginx:1.14.2' # kpt-set: gcr.io/${image}:${tag} diff --git a/examples/search-replace/create-setters/.expected/exec.sh b/examples/search-replace/create-setters/.expected/exec.sh new file mode 100644 index 000000000..529a58c28 --- /dev/null +++ b/examples/search-replace/create-setters/.expected/exec.sh @@ -0,0 +1,7 @@ +#! /bin/bash + +# shellcheck disable=SC2016 +kpt fn eval --image gcr.io/kpt-fn/search-replace:unstable -- 'by-path=spec.replicas' 'put-comment=kpt-set: ${replicas}' + +# shellcheck disable=SC2016 +kpt fn eval --image gcr.io/kpt-fn/search-replace:unstable -- 'by-path=spec.**.image' 'put-comment=kpt-set: gcr.io/${image}:${tag}' diff --git a/examples/search-replace/create-setters/.krmignore b/examples/search-replace/create-setters/.krmignore new file mode 100644 index 000000000..9d7a4007d --- /dev/null +++ b/examples/search-replace/create-setters/.krmignore @@ -0,0 +1 @@ +.expected diff --git a/examples/search-replace/create-setters/README.md b/examples/search-replace/create-setters/README.md new file mode 100644 index 000000000..0801d7c89 --- /dev/null +++ b/examples/search-replace/create-setters/README.md @@ -0,0 +1,70 @@ +# search-replace: Create Setters Example + +The `search-replace` function can be used to search for fields using available matchers +and add [setter] patterns as line comments in the resources. + +This is an end to end example depicting [setter] creation process using `search-replace` function. + +Let's start with the input resource + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-nginx +spec: + replicas: 3 + template: + spec: + containers: + - name: nginx + image: "gcr.io/nginx:1.14.2" +``` + +### Function invocation + +Get the config example: + +```shell +$ kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/search-replace/create-setters . +``` + +Suppose you want to expose the values of `image` and `tag` as parameters. +You can create [setters] by invoking `search-replace` function with following arguments: + +```shell +$ kpt fn eval --image gcr.io/kpt-fn/search-replace:unstable -- 'by-path=spec.replicas' 'put-comment=kpt-set: ${replicas}' +``` + +```shell +$ kpt fn eval --image gcr.io/kpt-fn/search-replace:unstable -- 'by-path=spec.**.image' 'put-comment=kpt-set: gcr.io/${image}:${tag}' +``` + +### Expected result + +Verify that the setter comments are added as below: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-nginx +spec: + replicas: 3 # kpt-set: ${replicas} + template: + spec: + containers: + - name: nginx + image: "gcr.io/nginx:1.14.2" # kpt-set: gcr.io/${image}:${tag} +``` + +Next, you can try to run the `apply-setters` function to use the [setters] that +you just created. For example: +```shell +$ kpt fn eval --image gcr.io/kpt-fn/search-replace:unstable -- replicas=3 image=nginx tag=1.14.2 +``` + +You should be able to see the values got updated by the [setters]. + +[setter]: https://catalog.kpt.dev/apply-setters/v0.1/ +[setters]: https://catalog.kpt.dev/apply-setters/v0.1/ \ No newline at end of file diff --git a/examples/search-replace/create-setters/fn-config.yaml b/examples/search-replace/create-setters/fn-config.yaml new file mode 100644 index 000000000..db0f3ddf1 --- /dev/null +++ b/examples/search-replace/create-setters/fn-config.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: search-replace-fn-config + annotations: + config.k8s.io/function: | + container: + image: gcr.io/kpt-fn/search-replace:v0.1 +data: + by-path: spec.replicas + put-comment: "kpt-set: ${replicas}" +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: search-replace-fn-config + annotations: + config.k8s.io/function: | + container: + image: gcr.io/kpt-fn/search-replace:v0.1 +data: + by-path: spec.**.image + put-comment: "kpt-set: gcr.io/${image}:${tag}" diff --git a/examples/search-replace/create-setters/resources.yaml b/examples/search-replace/create-setters/resources.yaml new file mode 100644 index 000000000..7dde53d6b --- /dev/null +++ b/examples/search-replace/create-setters/resources.yaml @@ -0,0 +1,11 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-nginx +spec: + replicas: 3 + template: + spec: + containers: + - name: nginx + image: 'gcr.io/nginx:1.14.2' diff --git a/examples/search-replace/simple/.expected/config.yaml b/examples/search-replace/simple/.expected/config.yaml deleted file mode 100644 index f7b0b32ed..000000000 --- a/examples/search-replace/simple/.expected/config.yaml +++ /dev/null @@ -1 +0,0 @@ -runCount: 2 diff --git a/examples/search-replace/simple/Kptfile b/examples/search-replace/simple/Kptfile new file mode 100644 index 000000000..9e2aa6cb8 --- /dev/null +++ b/examples/search-replace/simple/Kptfile @@ -0,0 +1,11 @@ +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile +metadata: + name: example +pipeline: + mutators: + - image: gcr.io/kpt-fn/search-replace:unstable + configMap: + by-path: metadata.name + by-value: the-deployment + put-value: my-deployment diff --git a/examples/search-replace/simple/README.md b/examples/search-replace/simple/README.md index df9949d41..825f3be82 100644 --- a/examples/search-replace/simple/README.md +++ b/examples/search-replace/simple/README.md @@ -1,5 +1,7 @@ # search-replace: Simple Example +### Overview + The `search-replace` function performs search and optionally replace fields across all resources. @@ -18,7 +20,7 @@ metadata: Search matchers are provided with `by-` prefix. When multiple matchers are provided they are AND’ed together. `put-` matchers are mutually exclusive. -We use the following ConfigMap to provide input matchers to the function. +We use the following `ConfigMap` to provide input matchers to the function. ```yaml apiVersion: v1 @@ -41,20 +43,15 @@ metadata: namespace: my-space ``` -## Function invocation +### Function invocation Get the config example and try it out by running the following commands: - -```sh -kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/search-replace/simple . -kpt fn run simple +```shell +$ kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/search-replace/simple . +$ kpt fn render simple ``` -## Expected result +### Expected result Check the value of deployment `the-deloyment` is changed to `my-deloyment`. - -```sh -$ kpt cfg cat simple/ -``` diff --git a/examples/search-replace/simple/fn-config.yaml b/examples/search-replace/simple/fn-config.yaml deleted file mode 100644 index 634f743f6..000000000 --- a/examples/search-replace/simple/fn-config.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: search-replace-fn-config - # TODO:(pmarupaka) remove annotations when e2e tests switch to kpt v1 binary - annotations: - config.k8s.io/function: | - container: - image: gcr.io/kpt-fn/search-replace:unstable -data: - by-path: metadata.name - by-value: the-deployment - put-value: my-deployment diff --git a/examples/set-annotations/advanced/.expected/config.yaml b/examples/set-annotations/advanced/.expected/config.yaml deleted file mode 100644 index f7b0b32ed..000000000 --- a/examples/set-annotations/advanced/.expected/config.yaml +++ /dev/null @@ -1 +0,0 @@ -runCount: 2 diff --git a/examples/set-annotations/advanced/.expected/diff.patch b/examples/set-annotations/advanced/.expected/diff.patch index 515632311..277f0d75e 100644 --- a/examples/set-annotations/advanced/.expected/diff.patch +++ b/examples/set-annotations/advanced/.expected/diff.patch @@ -1,27 +1,3 @@ -diff --git a/fn-config.yaml b/fn-config.yaml -deleted file mode 100644 -index 97525b7..0000000 ---- a/fn-config.yaml -+++ /dev/null -@@ -1,18 +0,0 @@ --apiVersion: fn.kpt.dev/v1alpha1 --kind: SetAnnotationConfig --metadata: -- name: my-func-config -- annotations: -- config.k8s.io/function: | -- container: -- image: gcr.io/kpt-fn/set-annotations:unstable -- config.kubernetes.io/local-config: 'true' --annotations: -- fruit: apple -- color: orange --fieldSpecs: --- kind: MyResource -- group: dev.example.com -- version: v1 -- create: true -- path: spec/selector/annotations diff --git a/resources.yaml b/resources.yaml index bfeadb4..4821d69 100644 --- a/resources.yaml diff --git a/examples/set-annotations/advanced/Kptfile b/examples/set-annotations/advanced/Kptfile new file mode 100644 index 000000000..ac27dd550 --- /dev/null +++ b/examples/set-annotations/advanced/Kptfile @@ -0,0 +1,8 @@ +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile +metadata: + name: example +pipeline: + mutators: + - image: gcr.io/kpt-fn/set-annotations:unstable + configPath: fn-config.yaml diff --git a/examples/set-annotations/advanced/README.md b/examples/set-annotations/advanced/README.md index 5190517f8..2586e6d93 100644 --- a/examples/set-annotations/advanced/README.md +++ b/examples/set-annotations/advanced/README.md @@ -1,14 +1,29 @@ # set-annotations: Advanced Example -The `set-annotation` function adds annotations to KRM resources. +### Overview -We use the following `SetAnnotationConfig` to configure the function. +This example demonstrates how to declaratively run [`set-annotations`] function +to upsert annotations to the `.metadata.annotations` field on all resources. + +We use the following `Kptfile` and `fn-config.yaml` to configure the function. + +```yaml +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile +metadata: + name: example +pipeline: + mutators: + - image: gcr.io/kpt-fn/set-annotations:unstable + configPath: fn-config.yaml +``` ```yaml +# fn-config.yaml apiVersion: fn.kpt.dev/v1alpha1 kind: SetAnnotationConfig metadata: - ... + name: my-func-config annotations: fruit: apple color: orange @@ -25,21 +40,18 @@ CRD with group `dev.example.com`, version `v1` and kind `MyResource`. We want the annotations to be added to field `.spec.selector.annotations` as well. We specify it in field `fieldSpecs`. -## Function invocation +### Function invocation Get the example config and try it out by running the following commands: - -```sh -kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/set-annotations/advanced . -kpt fn run advanced +```shell +$ kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/set-annotations/advanced . +$ kpt fn render advanced ``` -## Expected result +### Expected result Check the 2 annotations have been added to both the k8s built-in resources and the custom resources. -```sh -kpt cfg cat advanced -``` +[`set-annotations`]: https://catalog.kpt.dev/set-annotations/v0.1/ diff --git a/examples/set-annotations/advanced/fn-config.yaml b/examples/set-annotations/advanced/fn-config.yaml index 97525b7da..d54ca10a5 100644 --- a/examples/set-annotations/advanced/fn-config.yaml +++ b/examples/set-annotations/advanced/fn-config.yaml @@ -2,17 +2,12 @@ apiVersion: fn.kpt.dev/v1alpha1 kind: SetAnnotationConfig metadata: name: my-func-config - annotations: - config.k8s.io/function: | - container: - image: gcr.io/kpt-fn/set-annotations:unstable - config.kubernetes.io/local-config: 'true' annotations: - fruit: apple color: orange + fruit: apple fieldSpecs: -- kind: MyResource - group: dev.example.com - version: v1 - create: true - path: spec/selector/annotations + - kind: MyResource + create: true + group: dev.example.com + path: spec/selector/annotations + version: v1 diff --git a/examples/set-annotations/simple/.expected/config.yaml b/examples/set-annotations/simple/.expected/config.yaml deleted file mode 100644 index f7b0b32ed..000000000 --- a/examples/set-annotations/simple/.expected/config.yaml +++ /dev/null @@ -1 +0,0 @@ -runCount: 2 diff --git a/examples/set-annotations/simple/.expected/diff.patch b/examples/set-annotations/simple/.expected/diff.patch index f7a844ce9..5ff4b5504 100644 --- a/examples/set-annotations/simple/.expected/diff.patch +++ b/examples/set-annotations/simple/.expected/diff.patch @@ -1,21 +1,3 @@ -diff --git a/fn-config.yaml b/fn-config.yaml -deleted file mode 100644 -index c4f0257..0000000 ---- a/fn-config.yaml -+++ /dev/null -@@ -1,12 +0,0 @@ --apiVersion: v1 --kind: ConfigMap --metadata: -- name: my-func-config -- annotations: -- config.k8s.io/function: | -- container: -- image: gcr.io/kpt-fn/set-annotations:unstable -- config.kubernetes.io/local-config: 'true' --data: -- color: orange -- fruit: apple diff --git a/resources.yaml b/resources.yaml index 7a5cb40..4e2c418 100644 --- a/resources.yaml diff --git a/examples/set-annotations/simple/Kptfile b/examples/set-annotations/simple/Kptfile new file mode 100644 index 000000000..566c9860d --- /dev/null +++ b/examples/set-annotations/simple/Kptfile @@ -0,0 +1,10 @@ +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile +metadata: + name: example +pipeline: + mutators: + - image: gcr.io/kpt-fn/set-annotations:unstable + configMap: + color: orange + fruit: apple diff --git a/examples/set-annotations/simple/README.md b/examples/set-annotations/simple/README.md index f3967aad8..5e2758446 100644 --- a/examples/set-annotations/simple/README.md +++ b/examples/set-annotations/simple/README.md @@ -1,35 +1,38 @@ # set-annotations: Simple Example -The `set-annotation` function adds annotations to KRM resources. +### Overview -We use the following ConfigMap to configure the function. +This example demonstrates how to declaratively run [`set-annotations`] function +to upsert annotations to the `.metadata.annotations` field on all resources. + +We use the following `Kptfile` to configure the function. ```yaml -apiVersion: v1 -kind: ConfigMap +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile metadata: - ... -data: - color: orange - fruit: apple + name: example +pipeline: + mutators: + - image: gcr.io/kpt-fn/set-annotations:unstable + configMap: + color: orange + fruit: apple ``` -The desired annotations are provided as key-value pairs using `data` field. +The desired annotations are provided as key-value pairs through `ConfigMap`. -## Function invocation +### Function invocation Get the example config and try it out by running the following commands: - -```sh -kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/set-annotations/simple . -kpt fn run simple +```shell +$ kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/set-annotations/simple . +$ kpt fn render simple ``` -## Expected result +### Expected result Check the 2 annotations have been added. -```sh -kpt cfg cat simple -``` +[`set-annotations`]: https://catalog.kpt.dev/set-annotations/v0.1/ diff --git a/examples/set-annotations/simple/fn-config.yaml b/examples/set-annotations/simple/fn-config.yaml deleted file mode 100644 index c4f025735..000000000 --- a/examples/set-annotations/simple/fn-config.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: my-func-config - annotations: - config.k8s.io/function: | - container: - image: gcr.io/kpt-fn/set-annotations:unstable - config.kubernetes.io/local-config: 'true' -data: - color: orange - fruit: apple diff --git a/examples/set-labels/advanced/.expected/config.yaml b/examples/set-labels/advanced/.expected/config.yaml deleted file mode 100644 index f7b0b32ed..000000000 --- a/examples/set-labels/advanced/.expected/config.yaml +++ /dev/null @@ -1 +0,0 @@ -runCount: 2 diff --git a/examples/set-labels/advanced/.expected/diff.patch b/examples/set-labels/advanced/.expected/diff.patch index 91a638c99..d185a4523 100644 --- a/examples/set-labels/advanced/.expected/diff.patch +++ b/examples/set-labels/advanced/.expected/diff.patch @@ -1,27 +1,3 @@ -diff --git a/fn-config.yaml b/fn-config.yaml -deleted file mode 100644 -index 943382c..0000000 ---- a/fn-config.yaml -+++ /dev/null -@@ -1,18 +0,0 @@ --apiVersion: fn.kpt.dev/v1alpha1 --kind: SetLabelConfig --metadata: -- name: my-config -- annotations: -- config.k8s.io/function: | -- container: -- image: gcr.io/kpt-fn/set-labels:unstable -- config.kubernetes.io/local-config: "true" --labels: -- color: orange -- fruit: apple --fieldSpecs: --- kind: MyResource -- group: dev.example.com -- version: v1 -- create: true -- path: spec/selector/labels diff --git a/resources.yaml b/resources.yaml index 1e641f7..a905ef4 100644 --- a/resources.yaml diff --git a/examples/set-labels/advanced/Kptfile b/examples/set-labels/advanced/Kptfile new file mode 100644 index 000000000..b8cb145e2 --- /dev/null +++ b/examples/set-labels/advanced/Kptfile @@ -0,0 +1,8 @@ +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile +metadata: + name: example +pipeline: + mutators: + - image: gcr.io/kpt-fn/set-labels:unstable + configPath: fn-config.yaml diff --git a/examples/set-labels/advanced/README.md b/examples/set-labels/advanced/README.md index e97c05b75..4ef0d7a01 100644 --- a/examples/set-labels/advanced/README.md +++ b/examples/set-labels/advanced/README.md @@ -1,16 +1,29 @@ # set-labels: Advanced Example -The `set-label` function adds or updates labels in the `.metadata.labels` field -and other fields that has the same meaning as a label on all resources. You can -find more details about these fields in the help text of the function. +### Overview -We use the following `SetLabelConfig` to configure the function. +This example demonstrates how to declaratively run [`set-labels`] function +to upsert labels to the `.metadata.labels` field on all resources. + +We use the following `Kptfile` and `fn-config.yaml` to configure the function. + +```yaml +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile +metadata: + name: example +pipeline: + mutators: + - image: gcr.io/kpt-fn/set-labels:unstable + configPath: fn-config.yaml +``` ```yaml +# fn-config.yaml apiVersion: fn.kpt.dev/v1alpha1 kind: SetLabelConfig metadata: - ... + name: my-config labels: color: orange fruit: apple @@ -27,20 +40,17 @@ The desired labels is provided using `labels` field. We have a CRD with group added to field `.spec.selector.labels` as well. We specify it in field `fieldSpecs`. -## Function invocation +### Function invocation Get the example config and try it out by running the following commands: - -```sh -kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/set-labels/advanced . -kpt fn run advanced +```shell +$ kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/set-labels/advanced . +$ kpt fn render advanced ``` -## Expected result +### Expected result Check all resources have 2 labels: `color: orange` and `fruit: apple`. -```sh -kpt cfg cat advanced -``` +[`set-labels`]: https://catalog.kpt.dev/set-labels/v0.1/ diff --git a/examples/set-labels/advanced/fn-config.yaml b/examples/set-labels/advanced/fn-config.yaml index 943382c37..268fc2f25 100644 --- a/examples/set-labels/advanced/fn-config.yaml +++ b/examples/set-labels/advanced/fn-config.yaml @@ -2,17 +2,12 @@ apiVersion: fn.kpt.dev/v1alpha1 kind: SetLabelConfig metadata: name: my-config - annotations: - config.k8s.io/function: | - container: - image: gcr.io/kpt-fn/set-labels:unstable - config.kubernetes.io/local-config: "true" labels: color: orange fruit: apple fieldSpecs: -- kind: MyResource - group: dev.example.com - version: v1 - create: true - path: spec/selector/labels + - kind: MyResource + create: true + group: dev.example.com + path: spec/selector/labels + version: v1 diff --git a/examples/set-labels/simple/.expected/config.yaml b/examples/set-labels/simple/.expected/config.yaml deleted file mode 100644 index f7b0b32ed..000000000 --- a/examples/set-labels/simple/.expected/config.yaml +++ /dev/null @@ -1 +0,0 @@ -runCount: 2 diff --git a/examples/set-labels/simple/.expected/diff.patch b/examples/set-labels/simple/.expected/diff.patch index 5d458113c..90b9f2d14 100644 --- a/examples/set-labels/simple/.expected/diff.patch +++ b/examples/set-labels/simple/.expected/diff.patch @@ -1,21 +1,3 @@ -diff --git a/fn-config.yaml b/fn-config.yaml -deleted file mode 100644 -index f2bf7f5..0000000 ---- a/fn-config.yaml -+++ /dev/null -@@ -1,12 +0,0 @@ --apiVersion: v1 --kind: ConfigMap --metadata: -- name: my-config -- annotations: -- config.k8s.io/function: | -- container: -- image: gcr.io/kpt-fn/set-labels:unstable -- config.kubernetes.io/local-config: "true" --data: -- color: orange -- fruit: apple diff --git a/resources.yaml b/resources.yaml index 1e641f7..bb4be90 100644 --- a/resources.yaml diff --git a/examples/set-labels/simple/Kptfile b/examples/set-labels/simple/Kptfile new file mode 100644 index 000000000..c738b2a54 --- /dev/null +++ b/examples/set-labels/simple/Kptfile @@ -0,0 +1,10 @@ +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile +metadata: + name: example +pipeline: + mutators: + - image: gcr.io/kpt-fn/set-labels:unstable + configMap: + color: orange + fruit: apple diff --git a/examples/set-labels/simple/README.md b/examples/set-labels/simple/README.md index 0b8cfb2b1..ed32bb005 100644 --- a/examples/set-labels/simple/README.md +++ b/examples/set-labels/simple/README.md @@ -1,37 +1,38 @@ # set-labels: Simple Example -The `set-label` function adds or updates labels in the `.metadata.labels` field -and other fields that has the same meaning as a label on all resources. You can -find more details about these fields in the help text of the function. +### Overview -We use the following ConfigMap to configure the function. +This example demonstrates how to declaratively run [`set-labels`] function +to upsert labels to the `.metadata.labels` field on all resources. + +We use the following `Kptfile` to configure the function. ```yaml -apiVersion: v1 -kind: ConfigMap +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile metadata: - ... -data: - color: orange - fruit: apple + name: example +pipeline: + mutators: + - image: gcr.io/kpt-fn/set-labels:unstable + configMap: + color: orange + fruit: apple ``` -The desired labels are provided as key-value pairs using `data` field. +The desired labels are provided as key-value pairs through `ConfigMap`. -## Function invocation +### Function invocation Get the example config and try it out by running the following commands: - -```sh -kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/set-labels/simple . -kpt fn run simple +```shell +$ kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/set-labels/simple . +$ kpt fn render simple ``` -## Expected result +### Expected result Check all resources have 2 labels `color: orange` and `fruit: apple`. -```sh -kpt cfg cat simple -``` +[`set-labels`]: https://catalog.kpt.dev/set-labels/v0.1/ diff --git a/examples/set-namespace/advanced/.expected/config.yaml b/examples/set-namespace/advanced/.expected/config.yaml deleted file mode 100644 index f7b0b32ed..000000000 --- a/examples/set-namespace/advanced/.expected/config.yaml +++ /dev/null @@ -1 +0,0 @@ -runCount: 2 diff --git a/examples/set-namespace/advanced/.expected/diff.patch b/examples/set-namespace/advanced/.expected/diff.patch index 4fce8b05f..37b424b26 100644 --- a/examples/set-namespace/advanced/.expected/diff.patch +++ b/examples/set-namespace/advanced/.expected/diff.patch @@ -1,27 +1,5 @@ -diff --git a/fn-config.yaml b/fn-config.yaml -deleted file mode 100644 -index 9bb4cbf..0000000 ---- a/fn-config.yaml -+++ /dev/null -@@ -1,16 +0,0 @@ --apiVersion: fn.kpt.dev/v1alpha1 --kind: SetNamespaceConfig --metadata: -- name: my-config -- annotations: -- config.k8s.io/function: | -- container: -- image: gcr.io/kpt-fn/set-namespace:unstable -- config.kubernetes.io/local-config: 'true' --namespace: example-ns --fieldSpecs: --- group: dev.example.com -- version: v1 -- kind: MyResource -- path: spec/selector/namespace -- create: true diff --git a/resources.yaml b/resources.yaml -index afb745f..5b81bdf 100644 +index 517a507..7dfa8c1 100644 --- a/resources.yaml +++ b/resources.yaml @@ -2,6 +2,7 @@ apiVersion: v1 @@ -40,8 +18,8 @@ index afb745f..5b81bdf 100644 + namespace: example-ns spec: ports: - - name: etcd-server-ssl -@@ -22,12 +23,13 @@ spec: + - name: etcd-server-ssl +@@ -22,13 +23,14 @@ spec: apiVersion: v1 kind: Namespace metadata: @@ -55,6 +33,6 @@ index afb745f..5b81bdf 100644 - namespace: the-namespace + namespace: example-ns spec: -- selector: {} -+ selector: + configmapRef: + name: the-map + namespace: example-ns diff --git a/examples/set-namespace/advanced/Kptfile b/examples/set-namespace/advanced/Kptfile new file mode 100644 index 000000000..13c16d605 --- /dev/null +++ b/examples/set-namespace/advanced/Kptfile @@ -0,0 +1,8 @@ +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile +metadata: + name: example +pipeline: + mutators: + - image: gcr.io/kpt-fn/set-namespace:unstable + configPath: fn-config.yaml diff --git a/examples/set-namespace/advanced/README.md b/examples/set-namespace/advanced/README.md index 48b25086c..b6812489c 100644 --- a/examples/set-namespace/advanced/README.md +++ b/examples/set-namespace/advanced/README.md @@ -1,43 +1,59 @@ # set-namespace: Advanced Example -The `set-namespace` function adds or replaces the `.metadata.namespace` field on -all resources except for those known to be cluster-scoped. +### Overview -We use the following `SetNamespaceConfig` to configure the function. +This example demonstrates how to declaratively run [`set-namespace`] function +to add or replace the `.metadata.namespace` field on all resources except for +those known to be cluster-scoped. + +We use the following `Kptfile` and `fn-config.yaml` to configure the function. ```yaml +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile +metadata: + name: example +pipeline: + mutators: + - image: gcr.io/kpt-fn/set-namespace:unstable + configPath: fn-config.yaml +``` + +```yaml +# fn-config.yaml apiVersion: fn.kpt.dev/v1alpha1 kind: SetNamespaceConfig metadata: - ... + name: my-config namespace: example-ns fieldSpecs: - group: dev.example.com version: v1 kind: MyResource - path: spec/selector/namespace + path: spec/configmapRef/namespace create: true ``` -The desired namespace is provided using `.data.namespace` field. We have a CRD -with group `dev.example.com`, version `v1` and kind `MyResource`. We want the -namespace to be set in field `.spec.selector.annotations` as well. We specify it -in field `fieldSpecs`. +`set-namespace` function not only support `ConfigMap` but also a CRD as the +function configuration. We embed the CRD in the `Kptfile` in this example. +The desired namespace is provided using `.namespace` field in the function +configuration. + +Suppose we have a CRD with group `dev.example.com`, version `v1` and kind +`MyResource`. We want the namespace to be set in field +`.spec.configmapRef.namespace` as well. We specify it in field `fieldSpecs`. -## Function invocation +### Function invocation Get the example config and try it out by running the following commands: - -```sh -kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/set-namespace/advanced . -kpt fn run advanced +```shell +$ kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/set-namespace/advanced . +$ kpt fn render advanced ``` -## Expected result +### Expected result Check all resources have `.metadata.namespace` set to `example-ns`: -```sh -kpt cfg cat advanced -``` +[`set-namespace`]: https://catalog.kpt.dev/set-namespace/v0.1/ diff --git a/examples/set-namespace/advanced/fn-config.yaml b/examples/set-namespace/advanced/fn-config.yaml index 9bb4cbf64..b2085049a 100644 --- a/examples/set-namespace/advanced/fn-config.yaml +++ b/examples/set-namespace/advanced/fn-config.yaml @@ -1,16 +1,11 @@ +namespace: example-ns apiVersion: fn.kpt.dev/v1alpha1 kind: SetNamespaceConfig metadata: name: my-config - annotations: - config.k8s.io/function: | - container: - image: gcr.io/kpt-fn/set-namespace:unstable - config.kubernetes.io/local-config: 'true' -namespace: example-ns fieldSpecs: -- group: dev.example.com - version: v1 - kind: MyResource - path: spec/selector/namespace - create: true + - kind: MyResource + create: true + group: dev.example.com + path: spec/configmapRef/namespace + version: v1 diff --git a/examples/set-namespace/advanced/resources.yaml b/examples/set-namespace/advanced/resources.yaml index afb745f42..517a507a8 100644 --- a/examples/set-namespace/advanced/resources.yaml +++ b/examples/set-namespace/advanced/resources.yaml @@ -12,10 +12,10 @@ metadata: namespace: the-namespace spec: ports: - - name: etcd-server-ssl - port: 2380 - - name: etcd-client-ssl - port: 2379 + - name: etcd-server-ssl + port: 2380 + - name: etcd-client-ssl + port: 2379 clusterIP: None publishNotReadyAddresses: true --- @@ -30,4 +30,5 @@ metadata: name: the-service namespace: the-namespace spec: - selector: {} + configmapRef: + name: the-map diff --git a/examples/set-namespace/simple/.expected/config.yaml b/examples/set-namespace/simple/.expected/config.yaml deleted file mode 100644 index f7b0b32ed..000000000 --- a/examples/set-namespace/simple/.expected/config.yaml +++ /dev/null @@ -1 +0,0 @@ -runCount: 2 diff --git a/examples/set-namespace/simple/.expected/diff.patch b/examples/set-namespace/simple/.expected/diff.patch index c10866f52..43f2d7e0c 100644 --- a/examples/set-namespace/simple/.expected/diff.patch +++ b/examples/set-namespace/simple/.expected/diff.patch @@ -1,22 +1,5 @@ -diff --git a/fn-config.yaml b/fn-config.yaml -deleted file mode 100644 -index ac4063b..0000000 ---- a/fn-config.yaml -+++ /dev/null -@@ -1,11 +0,0 @@ --apiVersion: v1 --kind: ConfigMap --metadata: -- name: my-config -- annotations: -- config.k8s.io/function: | -- container: -- image: gcr.io/kpt-fn/set-namespace:unstable -- config.kubernetes.io/local-config: 'true' --data: -- namespace: example-ns diff --git a/resources.yaml b/resources.yaml -index 8859df8..8b3c21e 100644 +index 468897a..8d5a446 100644 --- a/resources.yaml +++ b/resources.yaml @@ -2,6 +2,7 @@ apiVersion: v1 @@ -35,7 +18,7 @@ index 8859df8..8b3c21e 100644 + namespace: example-ns spec: ports: - - name: etcd-server-ssl + - name: etcd-server-ssl @@ -22,4 +23,4 @@ spec: apiVersion: v1 kind: Namespace diff --git a/examples/set-namespace/simple/Kptfile b/examples/set-namespace/simple/Kptfile new file mode 100644 index 000000000..bc1694d37 --- /dev/null +++ b/examples/set-namespace/simple/Kptfile @@ -0,0 +1,9 @@ +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile +metadata: + name: example +pipeline: + mutators: + - image: gcr.io/kpt-fn/set-namespace:unstable + configMap: + namespace: example-ns diff --git a/examples/set-namespace/simple/README.md b/examples/set-namespace/simple/README.md index 57a0e08e9..e3e3223b1 100644 --- a/examples/set-namespace/simple/README.md +++ b/examples/set-namespace/simple/README.md @@ -1,35 +1,40 @@ # set-namespace: Simple Example -The `set-namespace` function adds or replaces the `.metadata.namespace` field on -all resources except for those known to be cluster-scoped. +### Overview -We use the following ConfigMap to configure the function. +This example demonstrates how to declaratively run [`set-namespace`] function +to adds or replaces the `.metadata.namespace` field on all resources except for +those known to be cluster-scoped. + +We use the following `Kptfile` to configure the function. ```yaml -apiVersion: v1 -kind: ConfigMap +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile metadata: - ... -data: - namespace: example-ns + name: example +pipeline: + mutators: + - image: gcr.io/kpt-fn/set-namespace:unstable + configMap: + namespace: example-ns ``` -The desired namespace is provided using `.data.namespace` field. +The function configuration is provided using a `ConfigMap`. We set only one +key-value pair: +- `namespace: example-ns`: The desired namespace. -## Function invocation +### Function invocation Get the config example and try it out by running the following commands: - -```sh -kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/set-namespace/simple . -kpt fn run simple +```shell +$ kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/set-namespace/simple . +$ kpt fn render simple ``` -## Expected result +### Expected result Check all resources have `metadata.namespace` set to `example-ns`: -```sh -kpt cfg cat simple -``` +[`set-namespace`]: https://catalog.kpt.dev/set-namespace/v0.1/ diff --git a/examples/set-namespace/simple/fn-config.yaml b/examples/set-namespace/simple/fn-config.yaml deleted file mode 100644 index ac4063b58..000000000 --- a/examples/set-namespace/simple/fn-config.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: my-config - annotations: - config.k8s.io/function: | - container: - image: gcr.io/kpt-fn/set-namespace:unstable - config.kubernetes.io/local-config: 'true' -data: - namespace: example-ns diff --git a/examples/set-namespace/simple/resources.yaml b/examples/set-namespace/simple/resources.yaml index 8859df8f9..468897aa7 100644 --- a/examples/set-namespace/simple/resources.yaml +++ b/examples/set-namespace/simple/resources.yaml @@ -12,10 +12,10 @@ metadata: namespace: the-namespace spec: ports: - - name: etcd-server-ssl - port: 2380 - - name: etcd-client-ssl - port: 2379 + - name: etcd-server-ssl + port: 2380 + - name: etcd-client-ssl + port: 2379 clusterIP: None publishNotReadyAddresses: true --- diff --git a/examples/starlark/simple/.expected/config.yaml b/examples/starlark/simple/.expected/config.yaml deleted file mode 100644 index f7b0b32ed..000000000 --- a/examples/starlark/simple/.expected/config.yaml +++ /dev/null @@ -1 +0,0 @@ -runCount: 2 diff --git a/examples/starlark/simple/.expected/diff.patch b/examples/starlark/simple/.expected/diff.patch index 205c3149b..0f645fc59 100644 --- a/examples/starlark/simple/.expected/diff.patch +++ b/examples/starlark/simple/.expected/diff.patch @@ -1,24 +1,3 @@ -diff --git a/fn-config.yaml b/fn-config.yaml -deleted file mode 100644 -index cf1807a..0000000 ---- a/fn-config.yaml -+++ /dev/null -@@ -1,15 +0,0 @@ --apiVersion: fn.kpt.dev/v1alpha1 --kind: StarlarkRun --metadata: -- name: set-namespace-to-prod -- annotations: -- config.k8s.io/function: | -- container: -- image: gcr.io/kpt-fn/starlark:unstable --source: | -- # set the namespace on all resources -- def setnamespace(resources, namespace): -- for resource in resources: -- # mutate the resource -- resource["metadata"]["namespace"] = namespace -- setnamespace(ctx.resource_list["items"], "prod") diff --git a/resources.yaml b/resources.yaml index 280e700..42255a0 100644 --- a/resources.yaml diff --git a/examples/starlark/simple/Kptfile b/examples/starlark/simple/Kptfile new file mode 100644 index 000000000..00c3bc9dd --- /dev/null +++ b/examples/starlark/simple/Kptfile @@ -0,0 +1,8 @@ +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile +metadata: + name: example +pipeline: + mutators: + - image: gcr.io/kpt-fn/starlark:unstable + configPath: fn-config.yaml diff --git a/examples/starlark/simple/README.md b/examples/starlark/simple/README.md index 63c93674b..d490adc48 100644 --- a/examples/starlark/simple/README.md +++ b/examples/starlark/simple/README.md @@ -1,17 +1,31 @@ # starlark: Simple Example -## Overview +### Overview -In this example, we are going to demonstrate how to use the starlark function -with an inline starlark script as function configuration. +In this example, we are going to demonstrate how to declaratively run the +[`starlark`] function with an inline starlark script as function configuration. -We are going to use the following function configuration: +We are going to use the following `Kptfile` and `fn-config.yaml` to configure +the function: +```yaml +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile +metadata: + name: example +pipeline: + mutators: + - image: gcr.io/kpt-fn/starlark:unstable + configPath: fn-config.yaml ``` + +```yaml +# fn-config.yaml apiVersion: fn.kpt.dev/v1alpha1 kind: StarlarkRun metadata: - ... + name: set-namespace-to-prod + annotations: source: | # set the namespace on all resources def setnamespace(resources, namespace): @@ -25,20 +39,17 @@ The starlark script is embedded in the `source` field. This script read the input KRM resources from `ctx.resource_list` and sets the `.metadata.namespace` to `prod` for all resources. -## Function invocation +### Function invocation Get the config example and try it out by running the following commands: - -```sh -kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/starlark/simple . -kpt fn run simple +```shell +$ kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/starlark/simple . +$ kpt fn render simple ``` -## Expected result +### Expected result Check the `.metadata.namespace` field has been set to `prod` for every resource. -```sh -kpt cfg cat simple -``` +[`starlark`]: https://catalog.kpt.dev/starlark/v0.1/ diff --git a/examples/starlark/simple/fn-config.yaml b/examples/starlark/simple/fn-config.yaml index cf1807a36..552a63f23 100644 --- a/examples/starlark/simple/fn-config.yaml +++ b/examples/starlark/simple/fn-config.yaml @@ -2,10 +2,6 @@ apiVersion: fn.kpt.dev/v1alpha1 kind: StarlarkRun metadata: name: set-namespace-to-prod - annotations: - config.k8s.io/function: | - container: - image: gcr.io/kpt-fn/starlark:unstable source: | # set the namespace on all resources def setnamespace(resources, namespace): diff --git a/examples/apply-setters/simple/.expected/config.yaml b/examples/upsert-resource/simple/.expected/config.yaml similarity index 100% rename from examples/apply-setters/simple/.expected/config.yaml rename to examples/upsert-resource/simple/.expected/config.yaml diff --git a/examples/upsert-resource/simple/.expected/diff.patch b/examples/upsert-resource/simple/.expected/diff.patch new file mode 100644 index 000000000..f85c422cb --- /dev/null +++ b/examples/upsert-resource/simple/.expected/diff.patch @@ -0,0 +1,13 @@ +diff --git a/resources.yaml b/resources.yaml +index 50886bd..c18550c 100644 +--- a/resources.yaml ++++ b/resources.yaml +@@ -5,7 +5,7 @@ metadata: + namespace: mySpace + spec: + selector: +- app: foo ++ app: bar + --- + apiVersion: apps/v1 + kind: Deployment diff --git a/examples/upsert-resource/simple/.krmignore b/examples/upsert-resource/simple/.krmignore new file mode 100644 index 000000000..9d7a4007d --- /dev/null +++ b/examples/upsert-resource/simple/.krmignore @@ -0,0 +1 @@ +.expected diff --git a/examples/upsert-resource/simple/Kptfile b/examples/upsert-resource/simple/Kptfile new file mode 100644 index 000000000..98b4ea71c --- /dev/null +++ b/examples/upsert-resource/simple/Kptfile @@ -0,0 +1,8 @@ +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile +metadata: + name: example +pipeline: + mutators: + - image: gcr.io/kpt-fn/upsert-resource:unstable + configPath: fn-config.yaml diff --git a/examples/upsert-resource/simple/README.md b/examples/upsert-resource/simple/README.md new file mode 100644 index 000000000..d457b2bf9 --- /dev/null +++ b/examples/upsert-resource/simple/README.md @@ -0,0 +1,74 @@ +# upsert-resource: Simple Example + +In this example, we will see how `upsert-resource` function replaces the +matching resource (identified by GKNN (Group, Kind, Namespace and Name)) in the +package with the input resource. + +Let's start with the list of resources in a package: + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: myService + namespace: mySpace +spec: + selector: + app: foo +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeployment + namespace: mySpace +spec: + replicas: 3 +``` + +Resource to upsert: + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: myService + namespace: mySpace +spec: + selector: + app: bar +``` + +Invoking `upsert-resource` function replaces the resource with name `myService`: + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: myService + namespace: mySpace +spec: + selector: + app: bar +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeployment + namespace: mySpace +spec: + replicas: 3 +``` + +### Function invocation + +Get the config example and try it out by running the following commands: + +```shell +$ kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/upsert-resource/simple . +$ kpt fn render simple +``` + +### Expected result + +Check the resource with name `myService` is replaced with input resource. The +value of field `app` is updated. diff --git a/examples/upsert-resource/simple/fn-config.yaml b/examples/upsert-resource/simple/fn-config.yaml new file mode 100644 index 000000000..465997a13 --- /dev/null +++ b/examples/upsert-resource/simple/fn-config.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Service +metadata: + name: myService + namespace: mySpace +spec: + selector: + app: bar diff --git a/examples/upsert-resource/simple/resources.yaml b/examples/upsert-resource/simple/resources.yaml new file mode 100644 index 000000000..50886bdb4 --- /dev/null +++ b/examples/upsert-resource/simple/resources.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: myService + namespace: mySpace +spec: + selector: + app: foo +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeployment + namespace: mySpace +spec: + replicas: 3 diff --git a/functions/contrib/ts/analyze-istio/package-lock.json b/functions/contrib/ts/analyze-istio/package-lock.json index 297f4f18a..c40d35c59 100644 --- a/functions/contrib/ts/analyze-istio/package-lock.json +++ b/functions/contrib/ts/analyze-istio/package-lock.json @@ -822,9 +822,9 @@ } }, "hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", - "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, "http-cache-semantics": { @@ -1108,9 +1108,9 @@ } }, "lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, "long": { @@ -1973,9 +1973,9 @@ "dev": true }, "underscore": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.0.tgz", - "integrity": "sha512-21rQzss/XPMjolTiIezSu3JAjgagXKROtNrYFEOWK109qY1Uv2tVjPTZ1ci2HgvQDA16gHYSthQIJfB+XId/rQ==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz", + "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==", "dev": true }, "universalify": { diff --git a/functions/contrib/ts/inflate-helm-chart/package-lock.json b/functions/contrib/ts/inflate-helm-chart/package-lock.json index b559d8a15..4585ec37e 100644 --- a/functions/contrib/ts/inflate-helm-chart/package-lock.json +++ b/functions/contrib/ts/inflate-helm-chart/package-lock.json @@ -838,9 +838,9 @@ } }, "hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", - "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, "http-cache-semantics": { @@ -1124,9 +1124,9 @@ } }, "lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, "long": { @@ -2012,9 +2012,9 @@ "dev": true }, "underscore": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.0.tgz", - "integrity": "sha512-21rQzss/XPMjolTiIezSu3JAjgagXKROtNrYFEOWK109qY1Uv2tVjPTZ1ci2HgvQDA16gHYSthQIJfB+XId/rQ==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz", + "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==", "dev": true }, "universalify": { diff --git a/functions/contrib/ts/sops/README.md b/functions/contrib/ts/sops/README.md new file mode 100644 index 000000000..9cd87bb51 --- /dev/null +++ b/functions/contrib/ts/sops/README.md @@ -0,0 +1,63 @@ +# SOPS + +### Overview + +Use [sops] to encrypt/decrypt KRM resources. + +### Synopsis + +The function configuration must be a ConfigMap. + +The following keys can be used in the `data` field of the ConfigMap, and all of +them are optional: + +- `cmd`: The operation that sops perform: `encrypt` or `decrypt`. The default + is `decrypt`. +- `cmd-json-path-filter`: Operation will be performed only to the resources that match + to the filter, e.g. `$[?(@.metadata.name=="somename" && @.kind=="somekind")]` will + process only resources with name `somename` and kine `somekind`. The default is empty. +- `cmd-tolerate-failures`: Ignore sops error and keep KRM resource unchanged rather than + exit the function with error. The default is `false`. +- `verbose`: Sops verbose logging output is enabled. The default is `false`. +- `ignore-mac`: Sops will ignore Message Authentication Code during decryption. The default + is `false`. +- `override-preexec-cmd`: The command that will be executed prior to sops exectution. The default is + `[ "$SOPS_IMPORT_PGP" == "" ] || (echo "$SOPS_IMPORT_PGP" | gpg --import 2>/dev/null); [ "$XDG_CONFIG_HOME" == "" ] || [ "$SOPS_IMPORT_AGE" == "" ] || (mkdir -p $XDG_CONFIG_HOME/sops/age/ && echo "$SOPS_IMPORT_AGE" > $XDG_CONFIG_HOME/sops/age/keys.txt`. + This command allows to import encryption keys via ENV variables. +- `override-detached-annotations`: List of comma-separated annotations that will be removed from the KRM resource + if exist prior to sops execution and added back after execution. That helps to avoid decryption issues + in cases the composer (e.g. kpt) adds its internal annotations. The default is + `config.kubernetes.io/index,config.kubernetes.io/path,config.k8s.io/id,kustomize.config.k8s.io/id`. +- all other provided keys will be converted to the sops command arguments using pattern `-- `, e.g. + `unencrypted-regex: '^(kind|apiVersion|group|metadata)$'` will add sops parameter `--unencrypted-regex: '^(kind|apiVersion|group|metadata)$'`. + +In order to encrypt or decrypt yaml, `sops` may accept a variety of ENV variables, e.g. to work +with Hashicorp Vault it will be necessary to set: `VAULT_ADDR` and +`VAULT_TOKEN`. This option can be used to set different encryption parameters that shouldn't be stored +in version control system repository, e.g. private keys, external services credentials. +This function introduces 2 additional ENV variables: `SOPS_IMPORT_PGP` and `SOPS_IMPORT_AGE` that must contain the PGP or AGE keys and that +make possible to work with PGP and AGE encryption. + +For `pgp` if you have a file with keys it's possible to run: + +```shell +SOPS_IMPORT_PGP="$(cat .asc)" kpt fn run +``` + +or if your keys are already presented in `gpg`-storage, it's possible to run: + +```shell +SOPS_IMPORT_PGP="$(gpg --armor --export-secret-keys)" kpt fn run +``` + +To make `sops` decrypt `age` it's necessary to keep all keys in the single file `~/.config/sops/age/keys.txt`. If that file exists, it's possible to invoke sops function and provide it with that keys by the command: + +```shell +SOPS_IMPORT_AGE="$(cat ~/.config/sops/age/keys.txt)" kpt fn run +``` + +Please refer to [gpg] and [age] examples to get more details. + +[age]:/examples/contrib/sops/age/ +[gpg]:/examples/contrib/sops/gpg/ +[sops]:https://github.com/mozilla/sops diff --git a/functions/contrib/ts/sops/build/sops.Dockerfile b/functions/contrib/ts/sops/build/sops.Dockerfile index 35b2d5560..77fd862c3 100644 --- a/functions/contrib/ts/sops/build/sops.Dockerfile +++ b/functions/contrib/ts/sops/build/sops.Dockerfile @@ -2,7 +2,7 @@ FROM node:14.15-alpine3.12 as builder RUN apk add bash curl git && apk update -ARG SOPS_VERSION="v3.6.1" +ARG SOPS_VERSION="v3.7.1" RUN curl -fsSL -o /usr/local/bin/sops https://github.com/mozilla/sops/releases/download/${SOPS_VERSION}/sops-${SOPS_VERSION}.linux && \ chmod +x /usr/local/bin/sops @@ -50,5 +50,6 @@ COPY --from=builder /usr/local/bin /usr/local/bin ENV PATH /usr/local/bin:$PATH ENV GNUPGHOME /tmp +ENV XDG_CONFIG_HOME /tmp ENTRYPOINT ["node", "/home/node/app/dist/sops_run.js"] diff --git a/functions/contrib/ts/sops/package-lock.json b/functions/contrib/ts/sops/package-lock.json index 311870b05..fcab8fc54 100644 --- a/functions/contrib/ts/sops/package-lock.json +++ b/functions/contrib/ts/sops/package-lock.json @@ -115,9 +115,9 @@ "dev": true }, "@types/jasmine": { - "version": "3.6.9", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.6.9.tgz", - "integrity": "sha512-B53NIwMj/AO0O+xfSWLYmKB0Mo6TYxfv2Mk8/c1T2w/e38t55iaPR6p7pHXTTtqfTmevPK3i8T1YweYFTZlxDw==", + "version": "3.6.10", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.6.10.tgz", + "integrity": "sha512-yfCl7JGtIc5LjScFpeIGBBNhJFkJdAAcsAnAd9ZRHwzh+sR2zkt257BKkTCF5VpJ8wMPnzzZ8QatRdXM8tqpKA==", "dev": true }, "@types/js-yaml": { @@ -127,9 +127,9 @@ "dev": true }, "@types/node": { - "version": "14.14.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.21.tgz", - "integrity": "sha512-cHYfKsnwllYhjOzuC5q1VpguABBeecUp24yFluHpn/BQaVxB1CuQ1FSRZCzrPxrkIfWISXV2LbeoBthLWg0+0A==", + "version": "14.14.43", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.43.tgz", + "integrity": "sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ==", "dev": true }, "@types/request": { @@ -832,9 +832,9 @@ } }, "hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", - "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, "http-cache-semantics": { @@ -1117,9 +1117,9 @@ } }, "lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, "long": { @@ -1976,15 +1976,15 @@ "dev": true }, "typescript": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", - "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz", + "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==", "dev": true }, "underscore": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.0.tgz", - "integrity": "sha512-21rQzss/XPMjolTiIezSu3JAjgagXKROtNrYFEOWK109qY1Uv2tVjPTZ1ci2HgvQDA16gHYSthQIJfB+XId/rQ==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz", + "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==", "dev": true }, "universalify": { diff --git a/functions/contrib/ts/sops/package.json b/functions/contrib/ts/sops/package.json index 632bedb95..84aa40603 100644 --- a/functions/contrib/ts/sops/package.json +++ b/functions/contrib/ts/sops/package.json @@ -28,9 +28,9 @@ "rw": "^1.3.3" }, "devDependencies": { - "@types/jasmine": "^3.6.9", + "@types/jasmine": "^3.6.10", "@types/js-yaml": "^3.12.5", - "@types/node": "^14.14.16", + "@types/node": "^14.14.43", "@types/rw": "file:@types/rw", "create-kpt-functions": "^0.17.0", "jasmine": "^3.7.0", @@ -39,7 +39,7 @@ "tslint": "^6.1.3", "tslint-config-prettier": "1.18.0", "tslint-consistent-codestyle": "^1.16.0", - "typescript": "~4.2.3" + "typescript": "~4.2.4" }, "kpt": { "docker_repo_base": "gcr.io/kpt-fn-contrib" diff --git a/functions/contrib/ts/sops/src/sops.ts b/functions/contrib/ts/sops/src/sops.ts index 31532b8bc..333359a54 100644 --- a/functions/contrib/ts/sops/src/sops.ts +++ b/functions/contrib/ts/sops/src/sops.ts @@ -43,7 +43,9 @@ let cmdTolerateFailures = false; // pre-exec command may be overriden from config let preExecCmd = - '[ "$SOPS_IMPORT_PGP" == "" ] || (echo "$SOPS_IMPORT_PGP" | gpg --import)'; + '[ "$SOPS_IMPORT_PGP" == "" ] || (echo "$SOPS_IMPORT_PGP" | gpg --import 2>/dev/null); \ + [ "$XDG_CONFIG_HOME" == "" ] || [ "$SOPS_IMPORT_AGE" == "" ] || \ + (mkdir -p $XDG_CONFIG_HOME/sops/age/ && echo "$SOPS_IMPORT_AGE" > $XDG_CONFIG_HOME/sops/age/keys.txt);'; // list of annotations that will be detached before decryption // this is needed, because tools like kpt add some annotations diff --git a/functions/go/Makefile b/functions/go/Makefile index 3e1e7a220..b81065737 100644 --- a/functions/go/Makefile +++ b/functions/go/Makefile @@ -22,11 +22,14 @@ FUNCTIONS := \ apply-setters \ enforce-gatekeeper \ ensure-name-substring \ + fix \ + format \ search-replace \ set-annotations \ set-labels \ set-namespace \ - starlark + starlark \ + upsert-resource # Targets for running all function tests FUNCTION_TESTS := $(patsubst %,%-TEST,$(FUNCTIONS)) diff --git a/functions/go/_template/README.md b/functions/go/_template/README.md index 289a19232..5c91586d5 100644 --- a/functions/go/_template/README.md +++ b/functions/go/_template/README.md @@ -17,6 +17,9 @@ Explain what this function does in one or two sentences. Explain the function config and behavior for this function in detail. +For each field in the function config, specify: + - An example value + - Whether it is optional, and if so, the default value To decouple the function orchestrator (i.e. kpt) from the function, it's recommended to not show the kpt CLI or custom resources like the Kptfile. diff --git a/functions/go/apply-setters/README.md b/functions/go/apply-setters/README.md index 4370ff655..5bf73894f 100644 --- a/functions/go/apply-setters/README.md +++ b/functions/go/apply-setters/README.md @@ -64,13 +64,13 @@ data: Render the declared values by invoking: -```sh +```shell $ kpt fn run --image gcr.io/kpt-fn/apply-setters:unstable --fn-config ./apply-setters-fn-config ``` Alternatively, setter values can be passed as key-value pairs in the CLI -```sh +```shell $ kpt fn run --image gcr.io/kpt-fn/apply-setters:unstable -- 'image=ubuntu' 'replicas=3' ``` @@ -135,3 +135,7 @@ environments: # kpt-set: ${env} ``` + +#### Note: + +Refer to the `create-setters` example in `search-replace` function examples for creating setters. diff --git a/functions/go/apply-setters/apply_setters.go b/functions/go/apply-setters/applysetters/apply_setters.go similarity index 61% rename from functions/go/apply-setters/apply_setters.go rename to functions/go/apply-setters/applysetters/apply_setters.go index 188628895..33957e3f2 100644 --- a/functions/go/apply-setters/apply_setters.go +++ b/functions/go/apply-setters/applysetters/apply_setters.go @@ -1,4 +1,4 @@ -package main +package applysetters import ( "fmt" @@ -7,32 +7,59 @@ import ( "sigs.k8s.io/kustomize/kyaml/errors" "sigs.k8s.io/kustomize/kyaml/kio" + "sigs.k8s.io/kustomize/kyaml/kio/kioutil" "sigs.k8s.io/kustomize/kyaml/yaml" ) -var _ kio.Filter = ApplySetters{} +const SetterCommentIdentifier = "# kpt-set: " + +var _ kio.Filter = &ApplySetters{} // ApplySetters applies the setter values to the resource fields which are tagged // by the setter reference comments type ApplySetters struct { // Setters holds the user provided values for all the setters - Setters []Setter `json:"setters,omitempty" yaml:"setters,omitempty"` + Setters []Setter + + // Results are the results of applying setter values + Results []*Result + + // filePath file path of resource + filePath string } type Setter struct { // Name is the name of the setter - Name string `json:"name,omitempty" yaml:"name,omitempty"` + Name string // Value is the input value for setter - Value string `json:"value,omitempty" yaml:"value,omitempty"` + Value string } -const SetterCommentIdentifier = "# kpt-set: " +// Result holds result of search and replace operation +type Result struct { + // FilePath is the file path of the matching field + FilePath string + + // FieldPath is field path of the matching field + FieldPath string + + // Value of the matching field + Value string +} // Filter implements Set as a yaml.Filter -func (as ApplySetters) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) { +func (as *ApplySetters) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) { + if len(as.Setters) == 0 { + return nodes, fmt.Errorf("input setters list cannot be empty") + } for i := range nodes { - err := accept(&as, nodes[i]) + filePath, _, err := kioutil.GetFileAnnotations(nodes[i]) + if err != nil { + return nodes, err + } + as.filePath = filePath + err = accept(as, nodes[i]) if err != nil { return nil, errors.Wrap(err) } @@ -60,18 +87,27 @@ environments: # kpt-set: ${env} - prod */ -func (as *ApplySetters) visitMapping(object *yaml.RNode) error { +func (as *ApplySetters) visitMapping(object *yaml.RNode, path string) error { return object.VisitFields(func(node *yaml.MapNode) error { - if node.IsNilOrEmpty() { + if node == nil || node.Key.IsNil() || node.Value.IsNil() { + // don't do IsNilOrEmpty check as empty sequences are allowed return nil } + // the aim of this method is to apply-setter for sequence nodes if node.Value.YNode().Kind != yaml.SequenceNode { // return if it is not a sequence node return nil } - setterPattern := extractSetterPattern(node.Key) + lineComment := node.Key.YNode().LineComment + if node.Value.YNode().Style == yaml.FlowStyle { + // if node is FlowStyle e.g. env: [foo, bar] # kpt-set: ${env} + // the setter comment will be on value node + lineComment = node.Value.YNode().LineComment + } + + setterPattern := extractSetterPattern(lineComment) if setterPattern == "" { // the node is not tagged with setter pattern return nil @@ -91,10 +127,28 @@ func (as *ApplySetters) visitMapping(object *yaml.RNode) error { // get the setter value for the setter name in the comment sv := setterValue(as.Setters, setterPattern) + // add the key to the field path + fieldPath := strings.TrimPrefix(fmt.Sprintf("%s.%s", path, node.Key.YNode().Value), ".") + + if sv == "" { + node.Value.YNode().Content = []*yaml.Node{} + // empty sequence must be FlowStyle e.g. env: [] # kpt-set: ${env} + node.Value.YNode().Style = yaml.FlowStyle + // setter pattern comment must be on value node + node.Value.YNode().LineComment = lineComment + node.Key.YNode().LineComment = "" + as.Results = append(as.Results, &Result{ + FilePath: as.filePath, + FieldPath: fieldPath, + Value: sv, + }) + return nil + } + // parse the setter value as yaml node rn, err := yaml.Parse(sv) if err != nil { - return err + return errors.Errorf("input to array setter must be an array of values, but found %q", sv) } // the setter value must parse as sequence node @@ -103,7 +157,18 @@ func (as *ApplySetters) visitMapping(object *yaml.RNode) error { } node.Value.YNode().Content = rn.YNode().Content + node.Key.YNode().LineComment = lineComment + // non-empty sequences should be standardized to FoldedStyle + // env: # kpt-set: ${env} + // - foo + // - bar node.Value.YNode().Style = yaml.FoldedStyle + + as.Results = append(as.Results, &Result{ + FilePath: as.filePath, + FieldPath: fieldPath, + Value: sv, + }) return nil }) } @@ -128,8 +193,8 @@ apiVersion: v1 image: ubuntu:1.8.0 # kpt-set: ${image}:${tag} */ -func (as *ApplySetters) visitScalar(object *yaml.RNode) error { - if object.IsNilOrEmpty() { +func (as *ApplySetters) visitScalar(object *yaml.RNode, path string) error { + if object.IsNil() { return nil } @@ -139,7 +204,7 @@ func (as *ApplySetters) visitScalar(object *yaml.RNode) error { } // perform a direct set of the field if it matches - setterPattern := extractSetterPattern(object) + setterPattern := extractSetterPattern(object.YNode().LineComment) if setterPattern == "" { // the node is not tagged with setter pattern return nil @@ -178,7 +243,15 @@ func (as *ApplySetters) visitScalar(object *yaml.RNode) error { } object.YNode().Value = setterPattern + if setterPattern == "" { + object.YNode().Style = yaml.DoubleQuotedStyle + } object.YNode().Tag = yaml.NodeTagEmpty + as.Results = append(as.Results, &Result{ + FilePath: as.filePath, + FieldPath: strings.TrimPrefix(path, "."), + Value: object.YNode().Value, + }) return nil } @@ -196,37 +269,52 @@ func shouldSet(pattern string, setters []Setter) bool { // currentSetterValues takes pattern and value and returns setter names to values // derived using pattern matching -// e.g. pattern = foo-${image}:${tag}-bar, value = foo-nginx:1.7.1-bar -// returns {"image":"nginx", "tag":"1.7.1"} +// e.g. pattern = my-app-layer.${stage}.${domain}.${tld}, value = my-app-layer.dev.example.com +// returns {"stage":"dev", "domain":"example", "tld":"com"} func currentSetterValues(pattern, value string) map[string]string { res := make(map[string]string) // get all setter names enclosed in ${} + // e.g. value: my-app-layer.dev.example.com + // pattern: my-app-layer.${stage}.${domain}.${tld} + // urs: [${stage}, ${domain}, ${tld}] urs := unresolvedSetters(pattern) - // transform pattern replace pattern with named matching groups - // e.g. foo-${image}:${tag}-bar => foo-(?P.*):(?P.*)-bar + // and escape pattern + pattern = regexp.QuoteMeta(pattern) + // escaped pattern: my-app-layer\.\$\{stage\}\.\$\{domain\}\.\$\{tld\} + for _, setterName := range urs { + // escape setter name + // we need to escape the setterName as well to replace it in the escaped pattern string later + setterName = regexp.QuoteMeta(setterName) pattern = strings.ReplaceAll( pattern, setterName, - fmt.Sprintf(`(?P<%s>.*)`, clean(setterName))) + `(?P.*)`) // x is just a place holder, it could be any alphanumeric string } + // pattern: my-app-layer\.(?P.*)\.(?P.*)\.(?P.*) r, err := regexp.Compile(pattern) if err != nil { // just return empty map if values can't be derived from pattern return res } setterValues := r.FindStringSubmatch(value) - setterNames := r.SubexpNames() - if len(setterNames) != len(setterValues) { + if len(setterValues) == 0 { + return res + } + // setterValues: [ "my-app-layer.dev.example.com", "dev", "example", "com"] + setterValues = setterValues[1:] + // setterValues: [ "dev", "example", "com"] + if len(urs) != len(setterValues) { // just return empty map if values can't be derived return res } - for i := range setterNames { - if i == 0 { - // first value is just entire value, so skip it - continue + for i := range setterValues { + if setterValues[i] == "" { + // if any of the value is unresolved return empty map + // and expect users to provide all values + return make(map[string]string) } - res[setterNames[i]] = setterValues[i] + res[clean(urs[i])] = setterValues[i] } return res } @@ -242,13 +330,9 @@ func setterValue(setters []Setter, setterName string) string { } // extractSetterPattern extracts the setter pattern from the line comment of the -// input yaml RNode. If the the line comment doesn't contain SetterCommentIdentifier +// yaml RNode. If the the line comment doesn't contain SetterCommentIdentifier // prefix, then it returns empty string -func extractSetterPattern(node *yaml.RNode) string { - if node == nil { - return "" - } - lineComment := node.YNode().LineComment +func extractSetterPattern(lineComment string) string { if !strings.HasPrefix(lineComment, SetterCommentIdentifier) { return "" } @@ -275,3 +359,10 @@ func clean(input string) string { input = strings.TrimSpace(input) return strings.TrimSuffix(strings.TrimPrefix(input, "${"), "}") } + +// Decode decodes the input yaml node into Set struct +func Decode(rn *yaml.RNode, fcd *ApplySetters) { + for k, v := range rn.GetDataMap() { + fcd.Setters = append(fcd.Setters, Setter{Name: k, Value: v}) + } +} diff --git a/functions/go/apply-setters/apply_setters_test.go b/functions/go/apply-setters/applysetters/apply_setters_test.go similarity index 65% rename from functions/go/apply-setters/apply_setters_test.go rename to functions/go/apply-setters/applysetters/apply_setters_test.go index 5b3d52ae5..01115d4b2 100644 --- a/functions/go/apply-setters/apply_setters_test.go +++ b/functions/go/apply-setters/applysetters/apply_setters_test.go @@ -1,4 +1,4 @@ -package main +package applysetters import ( "io/ioutil" @@ -140,6 +140,36 @@ spec: containers: - name: nginx image: ubuntu:1.7.9 # kpt-set: ${image}:${tag} +`, + }, + { + name: "derive missing values from pattern - special characters in name and value", + config: ` +data: + image-~!@#$%^&*()<>?"|: ubuntu-~!@#$%^&*()<>?"| +`, + input: `apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment +spec: + replicas: 3 + template: + spec: + containers: + - name: nginx + image: nginx:1.7.9 # kpt-set: ${image-~!@#$%^&*()<>?"|}:${tag}`, + expectedResources: `apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment +spec: + replicas: 3 + template: + spec: + containers: + - name: nginx + image: ubuntu-~!@#$%^&*()<>?"|:1.7.9 # kpt-set: ${image-~!@#$%^&*()<>?"|}:${tag} `, }, { @@ -285,6 +315,126 @@ spec: `, errMsg: `invalid setter pattern for array node: "${images}:${tag}"`, }, + { + name: "scalar partial setter using dots", + config: ` +data: + domain: demo + tld: io +`, + input: `apiVersion: v1 +kind: ConfigMap +metadata: + name: my-app-layer +spec: + host: my-app-layer.dev.example.com # kpt-set: my-app-layer.${stage}.${domain}.${tld} +`, + expectedResources: `apiVersion: v1 +kind: ConfigMap +metadata: + name: my-app-layer +spec: + host: my-app-layer.dev.demo.io # kpt-set: my-app-layer.${stage}.${domain}.${tld} +`, + }, + { + name: "error: no input", + config: ` +data: {} +`, + input: `apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment +spec: + replicas: 3 + template: + spec: + containers: + - name: nginx + image: nginx:1.7.9 # kpt-set: ${image}:${tag} +`, + expectedResources: `apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment +spec: + replicas: 3 + template: + spec: + containers: + - name: nginx + image: nginx:1.7.9 # kpt-set: ${image}:${tag} +`, + errMsg: `input setters list cannot be empty`, + }, + { + name: "set empty values", + input: `apiVersion: v1 +kind: Service +metadata: + name: myService # kpt-set: ${app} + namespace: "foo" # kpt-set: ${ns} +image: nginx:1.7.1 # kpt-set: ${image}:${tag} +env: # kpt-set: ${env} + - foo + - bar +roles: [dev, prod] # kpt-set: ${roles} +`, + config: ` +data: + app: "" + ns: ~ + image: '' + env: "" + roles: '' +`, + expectedResources: `apiVersion: v1 +kind: Service +metadata: + name: "" # kpt-set: ${app} + namespace: "" # kpt-set: ${ns} +image: :1.7.1 # kpt-set: ${image}:${tag} +env: [] # kpt-set: ${env} +roles: [] # kpt-set: ${roles} +`, + }, + { + name: "set non-empty values from empty values", + input: `apiVersion: v1 +kind: Service +metadata: + name: "" # kpt-set: ${app} + namespace: "" # kpt-set: ${ns} +image: :1.7.1 # kpt-set: ${image}:${tag} +env: [] # kpt-set: ${env} +roles: [] # kpt-set: ${roles} +`, + config: ` +data: + app: myService + ns: foo + image: nginx + tag: 1.7.1 + env: "[foo, bar]" + roles: | + - dev + - prod +`, + expectedResources: `apiVersion: v1 +kind: Service +metadata: + name: "myService" # kpt-set: ${app} + namespace: "foo" # kpt-set: ${ns} +image: nginx:1.7.1 # kpt-set: ${image}:${tag} +env: # kpt-set: ${env} + - foo + - bar +roles: # kpt-set: ${roles} + - dev + - prod +`, + }, } for i := range tests { test := tests[i] @@ -310,10 +460,7 @@ spec: if !assert.NoError(t, err) { t.FailNow() } - err = decode(node, s) - if !assert.NoError(t, err) { - t.FailNow() - } + Decode(node, s) if !assert.NoError(t, err) { t.FailNow() } @@ -371,12 +518,23 @@ var resolvePatternCases = []patternTest{ }, }, { - name: "setter values from pattern 1", - value: "nginx:1.7.1", - pattern: `${image}:${tag}`, + name: "setter values from pattern 2", + value: "foo-dev-bar-us-east-1-baz", + pattern: `foo-${environment}-bar-${region}-baz`, + expected: map[string]string{ + "environment": "dev", + "region": "us-east-1", + }, + }, + { + name: "setter values from pattern 3", + value: "gcr.io/my-app/my-app-backend:1.0.0", + pattern: `${registry}/${app~!@#$%^&*()<>?:"|}/${app-image-name}:${app-image-tag}`, expected: map[string]string{ - "image": "nginx", - "tag": "1.7.1", + "registry": "gcr.io", + `app~!@#$%^&*()<>?:"|`: "my-app", + "app-image-name": "my-app-backend", + "app-image-tag": "1.0.0", }, }, { @@ -385,6 +543,18 @@ var resolvePatternCases = []patternTest{ pattern: `${image}:${tag}`, expected: map[string]string{}, }, + { + name: "setter values from pattern unresolved 2", + value: "nginx:1.2", + pattern: `${image}${tag}`, + expected: map[string]string{}, + }, + { + name: "setter values from pattern unresolved 3", + value: "my-project/nginx:1.2", + pattern: `${project-id}/${image}${tag}`, + expected: map[string]string{}, + }, } func TestCurrentSetterValues(t *testing.T) { diff --git a/functions/go/search-replace/walk.go b/functions/go/apply-setters/applysetters/walk.go similarity index 98% rename from functions/go/search-replace/walk.go rename to functions/go/apply-setters/applysetters/walk.go index 48cee66b6..abe68fb32 100644 --- a/functions/go/search-replace/walk.go +++ b/functions/go/apply-setters/applysetters/walk.go @@ -1,4 +1,4 @@ -package main +package applysetters import ( "fmt" diff --git a/functions/go/apply-setters/generated/docs.go b/functions/go/apply-setters/generated/docs.go index a71d8a952..aac251f51 100644 --- a/functions/go/apply-setters/generated/docs.go +++ b/functions/go/apply-setters/generated/docs.go @@ -1,3 +1,5 @@ + + // Code generated by "mdtogo"; DO NOT EDIT. package generated diff --git a/functions/go/apply-setters/go.mod b/functions/go/apply-setters/go.mod index b7a8f3895..23178d157 100644 --- a/functions/go/apply-setters/go.mod +++ b/functions/go/apply-setters/go.mod @@ -5,5 +5,5 @@ go 1.15 require ( github.com/stretchr/testify v1.6.1 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect - sigs.k8s.io/kustomize/kyaml v0.10.10 + sigs.k8s.io/kustomize/kyaml v0.10.20 ) diff --git a/functions/go/apply-setters/go.sum b/functions/go/apply-setters/go.sum index dc7b5c2ae..ef4fd0f2b 100644 --- a/functions/go/apply-setters/go.sum +++ b/functions/go/apply-setters/go.sum @@ -1,20 +1,14 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/360EntSecGroup-Skylar/excelize v1.4.1/go.mod h1:vnax29X2usfl7HHkBrX5EvSCJcmH3dT9luvxzu8iGAE= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +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/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg= -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-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/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/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -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/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= @@ -34,66 +28,23 @@ 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/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/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/dustmop/soup v1.1.2-0.20190516214245-38228baa104e/go.mod h1:CgNC6SGbT+Xb8wGGvzilttZL1mc5sQ/5KkcxsZttMIk= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 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-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= 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-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.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-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= 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.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.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/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= -github.com/go-openapi/spec v0.19.5 h1:Xm0Ao53uqnk9QE/LlYV5DEU09UAgpliA85QoT9LzqPw= -github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= -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/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= -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.8/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gobuffalo/here v0.6.0 h1:hYrd0a6gDmWxBM4TnrGw8mQg24iSVoIkHEk7FodQcBI= -github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM= 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/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -101,12 +52,21 @@ github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4er github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 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.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 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 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/go-cmp v0.3.1/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/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= @@ -115,38 +75,38 @@ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 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/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= 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/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/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 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/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -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/markbates/pkger v0.17.1 h1:/MKEtWqtc0mZvu9OinB9UzVN9iYCwLWuyUv4Bw+PCno= -github.com/markbates/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/paulmach/orb v0.1.3/go.mod h1:VFlX/8C+IQ1p6FTRRKzKoOPJnvEtA5G0Veuqwbu//Vk= -github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +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/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -158,10 +118,8 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 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/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/qri-io/starlib v0.4.2-0.20200213133954-ff2e8cd5ef8d/go.mod h1:7DPO4domFU579Ga6E61sB9VFNaniPVwJP5C4bBCu3wA= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= @@ -173,71 +131,56 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU 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.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.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= 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 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= 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.2.3-0.20181224173747-660f15d67dbb/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/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= 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/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI= github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -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.starlark.net v0.0.0-20190528202925-30ae18b8564f/go.mod h1:c1/X6cHgvdXj6pUlmWKMkuqRnW4K8x2vwt6JAaaircg= go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= 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-20180904163835-0709b304e793/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-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/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-20180218175443-cbe0f9307d01/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-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-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-20190522155817-f3200d17e092/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-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/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 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-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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-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-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-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/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= @@ -245,14 +188,19 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb 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-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-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -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/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/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 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-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -263,12 +211,19 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl 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.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -sigs.k8s.io/kustomize/kyaml v0.10.10 h1:caAxDDkaXZp+0kDsZVik4leFJV8LCy09PdVqpaoNeF4= -sigs.k8s.io/kustomize/kyaml v0.10.10/go.mod h1:K9yg1k/HB/6xNOf5VH3LhTo1DK9/5ykSZO5uIv+Y/1k= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM= +k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= +sigs.k8s.io/kustomize/kyaml v0.10.20 h1:L9JNKvJfCBpmYFr4tP0igpfj/pXP7nW2aXOWNtF5k1g= +sigs.k8s.io/kustomize/kyaml v0.10.20/go.mod h1:TYWhGwW9vjoRh3rWqBwB/ZOXyEGRVWe7Ggc3+KZIO+c= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/functions/go/apply-setters/main.go b/functions/go/apply-setters/main.go index 87f5ae94c..d7d399bc5 100644 --- a/functions/go/apply-setters/main.go +++ b/functions/go/apply-setters/main.go @@ -4,57 +4,91 @@ import ( "fmt" "os" + "github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/apply-setters/applysetters" "github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/apply-setters/generated" "sigs.k8s.io/kustomize/kyaml/fn/framework" + "sigs.k8s.io/kustomize/kyaml/fn/framework/command" kyaml "sigs.k8s.io/kustomize/kyaml/yaml" ) //nolint func main() { resourceList := &framework.ResourceList{} - resourceList.FunctionConfig = map[string]interface{}{} - - cmd := framework.Command(resourceList, func() error { - s, err := getSetters(resourceList.FunctionConfig) - if err != nil { - return fmt.Errorf("failed to parse function config: %w", err) - } - _, err = s.Filter(resourceList.Items) - if err != nil { - return fmt.Errorf("failed to apply setters: %w", err) - } - return nil - }) + resourceList.FunctionConfig = &kyaml.RNode{} + asp := ApplySettersProcessor{} + cmd := command.Build(&asp, command.StandaloneEnabled, false) cmd.Short = generated.ApplySettersShort cmd.Long = generated.ApplySettersLong cmd.Example = generated.ApplySettersExamples if err := cmd.Execute(); err != nil { - fmt.Println(err) + fmt.Fprintln(os.Stderr, err) os.Exit(1) } } -// getSetters retrieve the setters from input config -func getSetters(fc interface{}) (ApplySetters, error) { - var fcd ApplySetters - f, ok := fc.(map[string]interface{}) - if !ok { - return fcd, fmt.Errorf("function config %#v is not valid", fc) +type ApplySettersProcessor struct{} + +func (asp *ApplySettersProcessor) Process(resourceList *framework.ResourceList) error { + resourceList.Result = &framework.Result{ + Name: "apply-setters", + } + items, err := run(resourceList) + if err != nil { + resourceList.Result.Items = getErrorItem(err.Error()) + return err + } + resourceList.Result.Items = items + return nil +} + +func run(resourceList *framework.ResourceList) ([]framework.ResultItem, error) { + s, err := getSetters(resourceList.FunctionConfig) + if err != nil { + return nil, err } - rn, err := kyaml.FromMap(f) + _, err = s.Filter(resourceList.Items) if err != nil { - return fcd, fmt.Errorf("failed to parse input from function config: %w", err) + return nil, err } + resultItems, err := resultsToItems(s) + if err != nil { + return nil, err + } + return resultItems, nil +} - return fcd, decode(rn, &fcd) +// getSetters retrieve the setters from input config +func getSetters(fc *kyaml.RNode) (applysetters.ApplySetters, error) { + var fcd applysetters.ApplySetters + applysetters.Decode(fc, &fcd) + return fcd, nil } -// decode decodes the input yaml node into Set struct -func decode(rn *kyaml.RNode, fcd *ApplySetters) error { - for k, v := range rn.GetDataMap() { - fcd.Setters = append(fcd.Setters, Setter{Name: k, Value: v}) +// resultsToItems converts the Search and Replace results to +// equivalent items([]framework.Item) +func resultsToItems(sr applysetters.ApplySetters) ([]framework.ResultItem, error) { + var items []framework.ResultItem + if len(sr.Results) == 0 { + return nil, fmt.Errorf("no matches for the input list of setters") + } + for _, res := range sr.Results { + items = append(items, framework.ResultItem{ + Message: fmt.Sprintf("set field value to %q", res.Value), + Field: framework.Field{Path: res.FieldPath}, + File: framework.File{Path: res.FilePath}, + }) + } + return items, nil +} + +// getErrorItem returns the item for input error message +func getErrorItem(errMsg string) []framework.ResultItem { + return []framework.ResultItem{ + { + Message: fmt.Sprintf("failed to apply setters: %s", errMsg), + Severity: framework.Error, + }, } - return nil } diff --git a/functions/go/apply-setters/walk.go b/functions/go/apply-setters/walk.go deleted file mode 100644 index fcc6db621..000000000 --- a/functions/go/apply-setters/walk.go +++ /dev/null @@ -1,48 +0,0 @@ -package main - -import ( - "sigs.k8s.io/kustomize/kyaml/yaml" -) - -// visitor is implemented by structs which need to walk the configuration. -// visitor is provided to accept to walk configuration -type visitor interface { - // visitScalar is called for each scalar field value on a resource - // node is the scalar field value - visitScalar(node *yaml.RNode) error - - // visitMapping is called for each Mapping field value on a resource - // node is the mapping field value - visitMapping(node *yaml.RNode) error -} - -// accept invokes the appropriate function on v for each field in object -func accept(v visitor, object *yaml.RNode) error { - return acceptImpl(v, object) -} - -// acceptImpl implements accept using recursion -func acceptImpl(v visitor, object *yaml.RNode) error { - switch object.YNode().Kind { - case yaml.DocumentNode: - // Traverse the child of the document - return accept(v, object) - case yaml.MappingNode: - if err := v.visitMapping(object); err != nil { - return err - } - return object.VisitFields(func(node *yaml.MapNode) error { - // Traverse each field value - return acceptImpl(v, node.Value) - }) - case yaml.SequenceNode: - return object.VisitElements(func(node *yaml.RNode) error { - // Traverse each list element - return acceptImpl(v, node) - }) - case yaml.ScalarNode: - // Visit the scalar field - return v.visitScalar(object) - } - return nil -} diff --git a/functions/go/enforce-gatekeeper/generated/docs.go b/functions/go/enforce-gatekeeper/generated/docs.go index 0162e2dd0..68b7b5773 100644 --- a/functions/go/enforce-gatekeeper/generated/docs.go +++ b/functions/go/enforce-gatekeeper/generated/docs.go @@ -1,8 +1,10 @@ + + // Code generated by "mdtogo"; DO NOT EDIT. package generated -var GatekeeperValidateShort = `Validate the KRM resources using [Gatekeeper] constraints.` -var GatekeeperValidateLong = ` +var EnforceGatekeeperShort = `Validate the KRM resources using [Gatekeeper] constraints.` +var EnforceGatekeeperLong = ` You can use Gatekeeper to validate KRM resources. To learn more about how to use the Gatekeeper project, see: https://open-policy-agent.github.io/gatekeeper/website/docs/howto. @@ -21,6 +23,6 @@ https://cloud.google.com/anthos-config-management/docs/how-to/write-a-constraint and https://cloud.google.com/anthos-config-management/docs/how-to/creating-constraints. ` -var GatekeeperValidateExamples = ` +var EnforceGatekeeperExamples = ` https://github.com/GoogleContainerTools/kpt-functions-catalog/tree/master/examples/enforce-gatekeeper/ ` diff --git a/functions/go/enforce-gatekeeper/main.go b/functions/go/enforce-gatekeeper/main.go index b51517de0..5e142036e 100644 --- a/functions/go/enforce-gatekeeper/main.go +++ b/functions/go/enforce-gatekeeper/main.go @@ -72,9 +72,9 @@ func main() { } return nil }) - cmd.Short = generated.GatekeeperValidateShort - cmd.Long = generated.GatekeeperValidateLong - cmd.Example = generated.GatekeeperValidateExamples + cmd.Short = generated.EnforceGatekeeperShort + cmd.Long = generated.EnforceGatekeeperLong + cmd.Example = generated.EnforceGatekeeperExamples if err := cmd.Execute(); err != nil { os.Exit(1) } diff --git a/functions/go/ensure-name-substring/generated/docs.go b/functions/go/ensure-name-substring/generated/docs.go index 7dd041a0a..4e2c1f233 100644 --- a/functions/go/ensure-name-substring/generated/docs.go +++ b/functions/go/ensure-name-substring/generated/docs.go @@ -1,3 +1,5 @@ + + // Code generated by "mdtogo"; DO NOT EDIT. package generated diff --git a/functions/go/fix/Dockerfile b/functions/go/fix/Dockerfile new file mode 100644 index 000000000..4296cbdcd --- /dev/null +++ b/functions/go/fix/Dockerfile @@ -0,0 +1,15 @@ +FROM golang:1.15-alpine3.12 +ENV CGO_ENABLED=0 +WORKDIR /go/src/ + +COPY go.mod go.sum ./ +RUN go mod download + +COPY . . +RUN go build -o /usr/local/bin/function ./ + +############################################# + +FROM alpine:3.12 +COPY --from=0 /usr/local/bin/function /usr/local/bin/function +ENTRYPOINT ["function"] diff --git a/functions/go/fix/README.md b/functions/go/fix/README.md new file mode 100644 index 000000000..eed629021 --- /dev/null +++ b/functions/go/fix/README.md @@ -0,0 +1,128 @@ +# fix + +### Overview + + + +Fix resources and make them compatible with kpt 1.0. + + + +### Synopsis + + + +`fix` helps you migrate the resources from `v1alpha1` format to `v1alpha2` format. +This is an automated step to migrate kpt packages which are compatible with kpt v0.X.Y +versions of kpt, and make them compatible with kpt 1.0 + +Here are the automated changes performed by `fix` function on `v1alpha1` kpt package: + +1. The `packageMetaData` section will be transformed to `info` section. +2. `upstream` section(if present), in the `v1alpha1` Kptfile is converted to `upstream` + and `upstreamLock` sections in `v1alpha2` version of Kptfile. +3. `dependencies` section will be removed from the Kptfile. +4. Setters no longer follow the OpenAPI format. The setters and substitutions will be converted + to simple setter patterns. `apply-setters` function is declared in the `pipeline` section. + Setters are configured using [ConfigMap] option. +5. Function annotation from function configs will be removed and corresponding + function definitions will be [declared in pipeline] section of Kptfile. Reference + to function config is added via [configPath] option. + +Limitations of `fix` function: + +1. All the functions are treated as mutators by the `fix` function while migrating and are added to + the mutators section in the pipeline. Users must manually go through the functions + and move the validator functions to the [validators] section in the pipeline section + of `v1alpha2` Kptfile. +2. [Openapi validations] and [required setters] feature offered by v0.X.Y setters is + no longer offered in v1.0 version of kpt. `fix` function will remove them. + Users must write their own validation functions to achieve the functionality. + Tip: Adding a [starlark function] would be an easier alternative to achieve the + equivalent validation functionality. +3. If you have used [Starlark runtime] in v0.X, please checkout the new and improved + [starlark function] and declare it in the pipeline as `fix` funtion will remove them. +4. [Auto-setters] feature is deprecated in v1.0 version of kpt. Since the setters are + migrated to a new and simple declarative version, package consumers can easily + declare all the setter values and render them all at once. +5. The `fix` function does not alter resources in live cluster. + If you are using the [inventory object] to manage live cluster, please + refer to [live migrate] docs to perform live migration separately. + + + +### Examples + + + +Let's start with a simple input resource which is compatible with kpt v0.X.Y + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-nginx +spec: + replicas: 3 # {"$kpt-set":"replicas"} +``` + +Here is the corresponding v1alpha1 Kptfile in the package + +```yaml +apiVersion: kpt.dev/v1alpha1 +kind: Kptfile +metadata: + name: nginx +openAPI: + definitions: + io.k8s.cli.setters.replicas: + x-k8s-cli: + setter: + name: replicas + value: "3" +``` + +Invoke `fix` function on the package: + +```shell +$ kpt fn eval --image gcr.io/kpt-fn/fix:unstable --include-meta-resources +``` + +Here is the transformed resource + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-nginx +spec: + replicas: 3 # kpt-set: ${replicas} +``` + +Here is the transformed `v1alpha2` Kptfile: + +```yaml +apiVersion: kpt.dev/v1alpha2 +kind: Kptfile +metadata: + name: nginx +pipeline: + mutators: + - image: gcr.io/kpt-fn/apply-setters:v0.1 + configMap: + replicas: "3" +``` + + + +[validators]: https://kpt.dev/book/04-using-functions/02-declaring-and-running-functions-in-a-package +[openapi validations]: https://googlecontainertools.github.io/kpt/guides/producer/setters/#openapi-validations +[required setters]: https://googlecontainertools.github.io/kpt/guides/producer/setters/#required-setters +[starlark function]: https://catalog.kpt.dev/starlark/v0.1/ +[starlark runtime]: https://googlecontainertools.github.io/kpt/guides/producer/functions/starlark/ +[auto-setters]: https://googlecontainertools.github.io/kpt/concepts/setters/#auto-setters +[inventory object]: https://googlecontainertools.github.io/kpt/reference/live/alpha/#what-is-an-inventory-object +[live migrate]: https://googlecontainertools.github.io/kpt/reference/live/alpha/ +[configpath]: https://kpt.dev/book/04-using-functions/01-declarative-function-execution?id=configpath +[declared in pipeline]: https://kpt.dev/book/04-using-functions/01-declarative-function-execution?id=_41-declarative-function-execution +[Configmap]: https://kpt.dev/book/04-using-functions/01-declarative-function-execution?id=configmap diff --git a/functions/go/fix/fixpkg/fix.go b/functions/go/fix/fixpkg/fix.go new file mode 100644 index 000000000..9eea7ca47 --- /dev/null +++ b/functions/go/fix/fixpkg/fix.go @@ -0,0 +1,630 @@ +package fixpkg + +import ( + "encoding/json" + "fmt" + "path/filepath" + "strings" + + "github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/fix/v1alpha1" + "github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/fix/v1alpha2" + "k8s.io/kube-openapi/pkg/validation/spec" + "sigs.k8s.io/kustomize/kyaml/errors" + "sigs.k8s.io/kustomize/kyaml/fieldmeta" + "sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil" + "sigs.k8s.io/kustomize/kyaml/kio" + "sigs.k8s.io/kustomize/kyaml/kio/kioutil" + "sigs.k8s.io/kustomize/kyaml/openapi" + "sigs.k8s.io/kustomize/kyaml/sets" + "sigs.k8s.io/kustomize/kyaml/setters2" + "sigs.k8s.io/kustomize/kyaml/yaml" +) + +var _ kio.Filter = &Fix{} + +// Fix migrates the resources in v1alpha1 format to v1alpha2 format +type Fix struct { + // pkgPathToPkgFilePaths key: package path relative to root package path + // value: list of file paths in the package, relative to root package + // the list doesn't include the file paths of subpackages + pkgPathToPkgFilePaths map[string]sets.String + + // pkgFileToPkgPath key: file path(relative to root package) + // value: path to package(relative to root package) to which the file belongs to + pkgFileToPkgPath map[string]string + + // settersSchema is the schema equivalent of openAPI section in Kptfile + // this must be updated while processing each resources so that the visitor + // interface methods have access to it + settersSchema *spec.Schema + + // Results are the results of fixing packages + Results []*Result +} + +// Result holds result of fixing packages +type Result struct { + // FilePath is the file path of the resource + FilePath string + + // Message is the result message + Message string +} + +// Filter implements Fix as a yaml.Filter +func (s *Fix) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) { + // group the resources based on the packages they belong to + // and populate Fix struct maps + if err := s.groupPathsInPkgs(nodes); err != nil { + return nodes, fmt.Errorf("unable to group resources by packages, %q", err.Error()) + } + + // each kpt package has a Kptfile with OpenAPI section(could be empty) + // get the map of pkgPath to OpenAPI schema as a pre-processing step + pkgPathToSettersSchema, err := getPkgPathToSettersSchema(nodes) + if err != nil { + return nodes, err + } + + kfFound := false + for i := range nodes { + meta, err := nodes[i].GetMeta() + if err != nil { + return nodes, err + } + + // check if there is Kptfile in root package + if meta.Kind == v1alpha2.KptFileName { + kfFound = true + } + + if meta.Kind == v1alpha2.KptFileName { + // this node is Kptfile node + // migrate Kptfile from v1alpha1 to v1alpha2 + pkgPath := filepath.Dir(meta.Annotations[kioutil.PathAnnotation]) + functions := s.FunctionsInPkg(nodes, pkgPath) + kNode, err := s.FixKptfile(nodes[i], functions) + if err != nil { + return nodes, err + } + nodes[i] = kNode + continue + } + + if meta.Labels["cli-utils.sigs.k8s.io/inventory-id"] != "" { + s.Results = append(s.Results, &Result{ + FilePath: meta.Annotations[kioutil.PathAnnotation], + Message: `Please refer to https://googlecontainertools.github.io/kpt/reference/live/alpha/, this package is using "inventory-object"`, + }) + continue + } + + // this is not a Kptfile node + // get the setters schema of the package to which the resource belongs + pkgPathOfResource := s.pkgFileToPkgPath[meta.Annotations[kioutil.PathAnnotation]] + + // update s.settersSchema so that visitor interface has setters schema for resource + s.settersSchema = pkgPathToSettersSchema[pkgPathOfResource] + + // fix setter comments in each resource + err = accept(s, nodes[i], s.settersSchema) + if err != nil { + return nil, errors.Wrap(err) + } + } + + if !kfFound { + return nodes, fmt.Errorf("Kptfile not found in directory tree, make sure you specify '--include-meta-resources' flag") + } + return nodes, nil +} + +// groupPathsInPkgs takes the input nodes list and populates +// pkgPathToPkgFilePaths and pkgFileToPkgPath in Fix struct +// this is a one-time pre-processing step to group package paths +func (s *Fix) groupPathsInPkgs(nodes []*yaml.RNode) error { + s.pkgPathToPkgFilePaths = make(map[string]sets.String) + s.pkgFileToPkgPath = make(map[string]string) + nonKfPaths, err := getNonKptFilesPaths(nodes) + if err != nil { + return err + } + kfPaths, err := getKptFilesPaths(nodes) + if err != nil { + return err + } + for _, kfPath := range kfPaths.List() { + filesInPkg := filesInPackage(filepath.Dir(kfPath), nonKfPaths, kfPaths) + s.pkgPathToPkgFilePaths[filepath.Dir(kfPath)] = filesInPkg + for _, filePath := range filesInPkg.List() { + s.pkgFileToPkgPath[filePath] = filepath.Dir(kfPath) + } + } + return nil +} + +// getNonKptFilesPaths returns the file paths of all resources which are NOT Kptfiles +func getNonKptFilesPaths(nodes []*yaml.RNode) (sets.String, error) { + paths := sets.String{} + for _, node := range nodes { + meta, err := node.GetMeta() + if err != nil { + return nil, err + } + path := meta.Annotations[kioutil.PathAnnotation] + if filepath.Base(path) != v1alpha2.KptFileName { + paths.Insert(meta.Annotations[kioutil.PathAnnotation]) + } + } + return paths, nil +} + +// getKptFilesPaths returns all the paths to Kptfiles relative to the root package +func getKptFilesPaths(nodes []*yaml.RNode) (sets.String, error) { + paths := sets.String{} + for _, node := range nodes { + meta, err := node.GetMeta() + if err != nil { + return nil, err + } + path := meta.Annotations[kioutil.PathAnnotation] + if filepath.Base(path) == v1alpha2.KptFileName { + paths.Insert(meta.Annotations[kioutil.PathAnnotation]) + } + } + return paths, nil +} + +// filesInPackage returns all the file paths which belong to the input pkgPath +// this doesn't include files in subpackages +func filesInPackage(pkgPath string, resourcesPaths, kptFilePaths sets.String) sets.String { + res := sets.String{} + for _, resourcePath := range resourcesPaths.List() { + dirPath := filepath.Dir(resourcePath) + for { + // check if the input pkgPath is the immediate parent package for the resource + kfPath := filepath.Join(dirPath, v1alpha2.KptFileName) + if kptFilePaths.Has(kfPath) { + if dirPath == pkgPath { + // this means the dirPath has a Kptfile and is a package + // and dirPath is the target package for which we are searching the resource paths + res.Insert(resourcePath) + } + break + } + if dirPath == "" || dirPath == "." { + break + } + // keep searching the parent directory for Kptfile + dirPath = filepath.Dir(dirPath) + } + } + return res +} + +// FunctionsInPkg gets the v1alpha2 functions list for functions in package +// nodes is list of input nodes which are sorted according to the package depth +// i is the index of the Kptfile of the package, all the files till i hits next Kptfile +// are the files of the package +// pkgPath is the package path relative to the root package directory +func (s *Fix) FunctionsInPkg(nodes []*yaml.RNode, pkgPath string) []v1alpha2.Function { + var res []v1alpha2.Function + for _, node := range nodes { + meta, err := node.GetMeta() + if err != nil { + return res + } + nonKfPkgPaths := s.pkgPathToPkgFilePaths[pkgPath] + if !nonKfPkgPaths.Has(meta.Annotations[kioutil.PathAnnotation]) { + continue + } + fnSpec := runtimeutil.GetFunctionSpec(node) + if fnSpec != nil { + // in v1alpha2, fn-config must be present in the package directory + // so configPath must be just the file name + fnFileName := filepath.Base(meta.Annotations[kioutil.PathAnnotation]) + res = append(res, v1alpha2.Function{ + Image: fnSpec.Container.Image, + ConfigPath: fnFileName, + }) + // move the fn-config to the top level directory of the package + meta.Annotations[kioutil.PathAnnotation] = filepath.Join(pkgPath, fnFileName) + delete(meta.Annotations, runtimeutil.FunctionAnnotationKey) + delete(meta.Annotations, "config.k8s.io/function") + err = node.SetAnnotations(meta.Annotations) + if err != nil { + return res + } + } + } + return res +} + +// FixKptfile migrates the input Kptfile node from v1alpha1 to v1alpha2 +func (s *Fix) FixKptfile(node *yaml.RNode, functions []v1alpha2.Function) (*yaml.RNode, error) { + var err error + meta, err := node.GetMeta() + if err != nil { + return node, err + } + kfOld, err := v1alpha1.ReadFile(node) + if err != nil { + return node, err + } + + kfNew := v1alpha2.KptFile{ResourceMeta: meta} + kfNew.APIVersion = v1alpha2.KptFileAPIVersion + + // convert packageMetadata in v1alpha1 Kptfile to v1alpha2 info + if kfOld.PackageMeta != nil { + emails := []string{kfOld.PackageMeta.Email} + if kfOld.PackageMeta.Email == "" { + emails = nil + } + kfNew.Info = &v1alpha2.PackageInfo{ + Site: kfOld.PackageMeta.URL, + Emails: emails, + License: kfOld.PackageMeta.License, + Description: kfOld.PackageMeta.ShortDescription, + Keywords: kfOld.PackageMeta.Tags, + Man: kfOld.PackageMeta.Man, + } + s.Results = append(s.Results, &Result{ + FilePath: meta.Annotations[kioutil.PathAnnotation], + Message: `Transformed "packageMetadata" to "info"`, + }) + } + + // convert upstream section + if kfOld.Upstream != nil { + kfNew.Upstream = &v1alpha2.Upstream{ + Type: v1alpha2.OriginType(kfOld.Upstream.Type), + Git: &v1alpha2.Git{ + Repo: kfOld.Upstream.Git.Repo, + Directory: kfOld.Upstream.Git.Directory, + Ref: kfOld.Upstream.Git.Ref, + }, + UpdateStrategy: v1alpha2.ResourceMerge, + } + + kfNew.UpstreamLock = &v1alpha2.UpstreamLock{ + Type: v1alpha2.OriginType(kfOld.Upstream.Type), + Git: &v1alpha2.GitLock{ + Repo: kfOld.Upstream.Git.Repo, + Directory: kfOld.Upstream.Git.Directory, + Ref: kfOld.Upstream.Git.Ref, + }, + } + + s.Results = append(s.Results, &Result{ + FilePath: meta.Annotations[kioutil.PathAnnotation], + Message: `Transformed "upstream" to "upstream" and "upstreamLock"`, + }) + } + + if err != nil { + return node, err + } + setters, err := listSetters(node) + if err != nil { + return node, err + } + + pl := &v1alpha2.Pipeline{} + kfNew.Pipeline = pl + for _, fn := range functions { + s.Results = append(s.Results, &Result{ + FilePath: meta.Annotations[kioutil.PathAnnotation], + Message: fmt.Sprintf(`Added %q to mutators list, please move it to validators section if it is a validator function`, fn.Image), + }) + } + + if len(setters) > 0 { + fn := v1alpha2.Function{ + Image: "gcr.io/kpt-fn/apply-setters:v0.1", + ConfigMap: setters, + } + pl.Mutators = append(pl.Mutators, fn) + s.Results = append(s.Results, &Result{ + FilePath: meta.Annotations[kioutil.PathAnnotation], + Message: `Transformed "openAPI" definitions to "apply-setters" function`, + }) + } + pl.Mutators = append(pl.Mutators, functions...) + + // convert inventory section + if kfOld.Inventory != nil { + kfNew.Inventory = &v1alpha2.Inventory{ + Namespace: kfOld.Inventory.Namespace, + Name: kfOld.Inventory.Name, + InventoryID: kfOld.Inventory.InventoryID, + Labels: kfOld.Inventory.Labels, + Annotations: kfOld.Inventory.Annotations, + } + } + + // convert kfNew to yaml node + b, err := yaml.Marshal(kfNew) + if err != nil { + return node, err + } + kNode, err := yaml.Parse(string(b)) + if err != nil { + return node, err + } + err = kNode.SetAnnotations(meta.Annotations) + return kNode, err +} + +// getPkgPathToSettersSchema returns the, map of pkgPath to the setters schema in Kptfile +// of the package +func getPkgPathToSettersSchema(nodes []*yaml.RNode) (map[string]*spec.Schema, error) { + res := make(map[string]*spec.Schema) + for _, node := range nodes { + meta, err := node.GetMeta() + if err != nil { + return nil, err + } + if meta.Kind == v1alpha2.KptFileName { + // convert OpenAPI section in v1alpha1 Kptfile to apply-setters + schema, err := schemaUsingField(node, openapi.SupplementaryOpenAPIFieldName) + if err != nil { + return nil, err + } + res[filepath.Dir(meta.Annotations[kioutil.PathAnnotation])] = schema + } + } + return res, nil +} + +// visitMapping visits mapping node to convert the comments for array setters +func (s *Fix) visitMapping(object *yaml.RNode) error { + return object.VisitFields(func(node *yaml.MapNode) error { + if node.IsNilOrEmpty() { + return nil + } + if node.Value.YNode().Kind != yaml.SequenceNode { + // return if it is not a sequence node + return nil + } + + comment := node.Key.YNode().LineComment + // # {"$kpt-set":"foo"} must be converted to # kpt-set: ${foo} + if strings.Contains(comment, "$kpt-set") { + comment := strings.TrimPrefix(comment, `# {"$kpt-set":"`) + comment = strings.TrimSuffix(comment, `"}`) + node.Key.YNode().LineComment = fmt.Sprintf("kpt-set: ${%s}", comment) + } + return nil + }) +} + +// visitScalar visits scalar nodes and converts the comments to v1alpha2 format +func (s *Fix) visitScalar(object *yaml.RNode, setterSchema *openapi.ResourceSchema) error { + ext, err := getExtFromComment(setterSchema) + if err != nil { + return err + } + if ext == nil { + return nil + } + + ok, err := s.fixSetter(object, ext) + if err != nil { + return err + } + if ok { + return nil + } + + _, err = s.fixSubst(object, ext) + if err != nil { + return err + } + return nil +} + +// fixSetter converts the setter comment to v1alpha2 format +func (s *Fix) fixSetter(field *yaml.RNode, ext *setters2.CliExtension) (bool, error) { + // check full setter + if ext == nil || ext.Setter == nil { + return false, nil + } + + field.YNode().LineComment = fmt.Sprintf("kpt-set: ${%s}", ext.Setter.Name) + return true, nil +} + +// fixSubst converts the substitution comment to expanded setter comment pattern +func (s *Fix) fixSubst(field *yaml.RNode, ext *setters2.CliExtension) (bool, error) { + if ext.Substitution == nil { + return false, nil + } + + // track the visited nodes to detect cycles in nested substitutions + visited := sets.String{} + + res, err := s.substituteUtil(ext, visited) + if err != nil { + return false, err + } + + field.YNode().LineComment = fmt.Sprintf("kpt-set: %s", res) + + return true, nil +} + +// substituteUtil recursively parses nested substitutions in ext and sets the setter value +// returns error if cyclic substitution is detected or any other unexpected errors +func (s *Fix) substituteUtil(ext *setters2.CliExtension, visited sets.String) (string, error) { + // check if the substitution has already been visited and throw error as cycles + // are not allowed in nested substitutions + if visited.Has(ext.Substitution.Name) { + return "", errors.Errorf( + "cyclic substitution detected with name " + ext.Substitution.Name) + } + + visited.Insert(ext.Substitution.Name) + pattern := ext.Substitution.Pattern + + // substitute each setter into the pattern to get the new value + // if substitution references to another substitution, recursively + // process the nested substitutions to replace the pattern with setter values + for _, v := range ext.Substitution.Values { + if v.Ref == "" { + return "", errors.Errorf( + "missing reference on substitution " + ext.Substitution.Name) + } + ref, err := spec.NewRef(v.Ref) + if err != nil { + return "", errors.Wrap(err) + } + def, err := openapi.Resolve(&ref, s.settersSchema) // resolve the def to its openAPI def + if err != nil { + return "", errors.Wrap(err) + } + defExt, err := setters2.GetExtFromSchema(def) // parse the extension out of the openAPI + if err != nil { + return "", errors.Wrap(err) + } + + if defExt.Substitution != nil { + // parse recursively if it reference is substitution + substVal, err := s.substituteUtil(defExt, visited) + if err != nil { + return "", err + } + pattern = strings.ReplaceAll(pattern, v.Marker, substVal) + continue + } + + if val, found := defExt.Setter.EnumValues[defExt.Setter.Value]; found { + // the setter has an enum-map. we should replace the marker with the + // enum value looked up from the map rather than the enum key + pattern = strings.ReplaceAll(pattern, v.Marker, val) + } else { + pattern = strings.ReplaceAll(pattern, v.Marker, fmt.Sprintf("${%s}", defExt.Setter.Name)) + } + } + return pattern, nil +} + +// listSetters extracts the setters information from the input Kptfile node +func listSetters(object *yaml.RNode) (map[string]string, error) { + setters := make(map[string]string) + // read the OpenAPI definitions in Kptfile + def, err := object.Pipe(yaml.LookupCreate(yaml.MappingNode, "openAPI", "definitions")) + if err != nil { + return nil, err + } + if yaml.IsMissingOrNull(def) { + return nil, nil + } + + // iterate over definitions -- find those that are setters + err = def.VisitFields(func(node *yaml.MapNode) error { + setter := setters2.SetterDefinition{} + + // the definition key -- contains the setter name + key := node.Key.YNode().Value + + if !strings.HasPrefix(key, fieldmeta.SetterDefinitionPrefix) { + // not a setter -- doesn't have the right prefix + return nil + } + + setterNode, err := node.Value.Pipe(yaml.Lookup(setters2.K8sCliExtensionKey, "setter")) + if err != nil { + return err + } + if yaml.IsMissingOrNull(setterNode) { + // has the setter prefix, but missing the setter extension + return errors.Errorf("missing x-k8s-cli.setter for %s", key) + } + + // unmarshal the yaml for the setter extension into the definition struct + b, err := setterNode.String() + if err != nil { + return err + } + if err := yaml.Unmarshal([]byte(b), &setter); err != nil { + return err + } + + // the description is not part of the extension, and should be pulled out + // separately from the extension values. + description := node.Value.Field("description") + if description != nil { + setter.Description = description.Value.YNode().Value + } + if len(setter.ListValues) > 0 { + var vals string + for _, val := range setter.ListValues { + vals = vals + ", " + val + } + vals = strings.TrimPrefix(vals, ", ") + setters[setter.Name] = fmt.Sprintf("[%s]", vals) + } else { + setters[setter.Name] = setter.Value + } + return nil + }) + if err != nil { + return nil, err + } + + return setters, nil +} + +// getExtFromComment returns the cliExtension openAPI extension if it is present as +// a comment on the field. +func getExtFromComment(schema *openapi.ResourceSchema) (*setters2.CliExtension, error) { + if schema == nil { + return nil, nil + } + + // get the cli extension from the openapi (contains setter information) + ext, err := setters2.GetExtFromSchema(schema.Schema) + if err != nil { + return nil, errors.Wrap(err) + } + return ext, nil +} + +// schemaUsingField returns the schema object for the openAPI section in input Kptfile object node +func schemaUsingField(object *yaml.RNode, field string) (*spec.Schema, error) { + if field != "" { + // get the field containing the openAPI + m := object.Field(field) + if m.IsNilOrEmpty() { + // doesn't contain openAPI definitions + return nil, nil + } + object = m.Value + } + + oAPI, err := object.String() + if err != nil { + return nil, err + } + + // convert the yaml openAPI to a JSON string by unmarshalling it to an + // interface{} and the marshalling it to a string + var o interface{} + err = yaml.Unmarshal([]byte(oAPI), &o) + if err != nil { + return nil, err + } + j, err := json.Marshal(o) + if err != nil { + return nil, err + } + + var sc spec.Schema + err = sc.UnmarshalJSON(j) + if err != nil { + return nil, err + } + + return &sc, nil +} diff --git a/functions/go/fix/fixpkg/fix_test.go b/functions/go/fix/fixpkg/fix_test.go new file mode 100644 index 000000000..bab05d329 --- /dev/null +++ b/functions/go/fix/fixpkg/fix_test.go @@ -0,0 +1,33 @@ +package fixpkg + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/stretchr/testify/assert" + "sigs.k8s.io/kustomize/kyaml/copyutil" + "sigs.k8s.io/kustomize/kyaml/kio" +) + +func TestFix(t *testing.T) { + dir, err := ioutil.TempDir("", "") + assert.NoError(t, err) + defer os.RemoveAll(dir) + err = copyutil.CopyDir("../../../../testdata/fix/nginx-v1alpha1", dir) + assert.NoError(t, err) + inout := &kio.LocalPackageReadWriter{ + PackagePath: dir, + MatchFilesGlob: append(kio.DefaultMatch, "Kptfile"), + } + f := &Fix{} + err = kio.Pipeline{ + Inputs: []kio.Reader{inout}, + Filters: []kio.Filter{f}, + Outputs: []kio.Writer{inout}, + }.Execute() + assert.NoError(t, err) + diff, err := copyutil.Diff(dir, "../../../../testdata/fix/nginx-v1alpha2") + assert.NoError(t, err) + assert.Equal(t, 0, len(diff.List())) +} diff --git a/functions/go/fix/fixpkg/walk.go b/functions/go/fix/fixpkg/walk.go new file mode 100644 index 000000000..e231f2692 --- /dev/null +++ b/functions/go/fix/fixpkg/walk.go @@ -0,0 +1,192 @@ +package fixpkg + +import ( + "encoding/json" + "strings" + + "k8s.io/kube-openapi/pkg/validation/spec" + "sigs.k8s.io/kustomize/kyaml/fieldmeta" + "sigs.k8s.io/kustomize/kyaml/openapi" + "sigs.k8s.io/kustomize/kyaml/yaml" +) + +// visitor is implemented by structs which need to walk the configuration. +// visitor is provided to accept to walk configuration +type visitor interface { + // visitScalar is called for each scalar field value on a resource + // node is the scalar field value + // path is the path to the field; path elements are separated by '.' + // setterSchema is the OpenAPI schema of the setter from Kptfile + visitScalar(node *yaml.RNode, setterSchema *openapi.ResourceSchema) error + + // visitMapping is called for each Mapping field value on a resource + // node is the mapping field value + visitMapping(node *yaml.RNode) error +} + +// accept invokes the appropriate function on v for each field in object +// settersSchema is the schema equivalent of openAPI section in Kptfile +func accept(v visitor, object *yaml.RNode, settersSchema *spec.Schema) error { + oa := getSchema(object, nil, "", settersSchema) + return acceptImpl(v, object, "", oa, settersSchema) +} + +// acceptImpl implements accept using recursion +func acceptImpl(v visitor, object *yaml.RNode, p string, oa *openapi.ResourceSchema, settersSchema *spec.Schema) error { + switch object.YNode().Kind { + case yaml.DocumentNode: + // Traverse the child of the document + return accept(v, yaml.NewRNode(object.YNode()), settersSchema) + case yaml.MappingNode: + if err := v.visitMapping(object); err != nil { + return err + } + return object.VisitFields(func(node *yaml.MapNode) error { + // get the schema for the field and propagate it + fieldSchema := getSchema(node.Key, oa, node.Key.YNode().Value, settersSchema) + // Traverse each field value + return acceptImpl(v, node.Value, p+"."+node.Key.YNode().Value, fieldSchema, settersSchema) + }) + case yaml.SequenceNode: + // get the schema for the elements + schema := getSchema(object, oa, "", settersSchema) + return object.VisitElements(func(node *yaml.RNode) error { + // Traverse each list element + return acceptImpl(v, node, p, schema, settersSchema) + }) + case yaml.ScalarNode: + // Visit the scalar field + setterSchema := getSchema(object, oa, "", settersSchema) + return v.visitScalar(object, setterSchema) + } + return nil +} + +// getSchema returns setter OpenAPI schema from Kptfile for a field. +// r is the Node to get the Schema for +// s is the provided schema for the field if known +// field is the name of the field +// settersSchema is the schema equivalent of openAPI section in Kptfile +func getSchema(r *yaml.RNode, s *openapi.ResourceSchema, field string, settersSchema *spec.Schema) *openapi.ResourceSchema { + // get the override schema if it exists on the field + fm := &fieldmeta.FieldMeta{SettersSchema: settersSchema} + if err := Read(r, fm); err == nil && !fm.IsEmpty() { + if fm.Schema.Ref.String() != "" { + // resolve the reference + s, err := openapi.Resolve(&fm.Schema.Ref, settersSchema) + if err == nil && s != nil { + fm.Schema = *s + } + } + return &openapi.ResourceSchema{Schema: &fm.Schema} + } + + // get the schema for a field of the node if the field is provided + if s != nil && field != "" { + return s.Field(field) + } + + // get the schema for the elements if this is a list + if s != nil && r.YNode().Kind == yaml.SequenceNode { + return s.Elements() + } + + // use the provided schema if present + if s != nil { + return s + } + + if yaml.IsMissingOrNull(r) { + return nil + } + + // lookup the schema for the type + m, _ := r.GetMeta() + if m.Kind == "" || m.APIVersion == "" { + return nil + } + return openapi.SchemaForResourceType(yaml.TypeMeta{Kind: m.Kind, APIVersion: m.APIVersion}) +} + +// Read reads the FieldMeta from a node +func Read(n *yaml.RNode, fm *fieldmeta.FieldMeta) error { + // check for metadata on head and line comments + comments := []string{n.YNode().LineComment, n.YNode().HeadComment} + for _, c := range comments { + if c == "" { + continue + } + c := strings.TrimLeft(c, "#") + + // check for new short hand notation or fall back to openAPI ref format + if !processShortHand(c, fm) { + // if it doesn't Unmarshal that is fine, it means there is no metadata + // other comments are valid, they just don't parse + // TODO: consider more sophisticated parsing techniques similar to what is used + // for go struct tags. + if err := fm.Schema.UnmarshalJSON([]byte(c)); err != nil { + // note: don't return an error if the comment isn't a fieldmeta struct + return nil + } + } + fe := fm.Schema.VendorExtensible.Extensions["x-kustomize"] + if fe == nil { + return nil + } + b, err := json.Marshal(fe) + if err != nil { + return err + } + return json.Unmarshal(b, &fm.Extensions) + } + return nil +} + +// processShortHand parses the comment for short hand ref, loads schema to fm +// and returns true if successful, returns false for any other cases and not throw +// error, as the comment might not be a setter ref +func processShortHand(comment string, fm *fieldmeta.FieldMeta) bool { + input := map[string]string{} + err := json.Unmarshal([]byte(comment), &input) + if err != nil { + return false + } + name := input["$kpt-set"] + if name == "" { + return false + } + + // check if setter with the name exists, else check for a substitution + // setter and substitution can't have same name in shorthand + + setterRef, err := spec.NewRef(fieldmeta.DefinitionsPrefix + fieldmeta.SetterDefinitionPrefix + name) + if err != nil { + return false + } + + setterRefBytes, err := setterRef.MarshalJSON() + if err != nil { + return false + } + + if _, err := openapi.Resolve(&setterRef, fm.SettersSchema); err == nil { + setterErr := fm.Schema.UnmarshalJSON(setterRefBytes) + return setterErr == nil + } + + substRef, err := spec.NewRef(fieldmeta.DefinitionsPrefix + fieldmeta.SubstitutionDefinitionPrefix + name) + if err != nil { + return false + } + + substRefBytes, err := substRef.MarshalJSON() + if err != nil { + return false + } + + if _, err := openapi.Resolve(&substRef, fm.SettersSchema); err == nil { + substErr := fm.Schema.UnmarshalJSON(substRefBytes) + return substErr == nil + } + return false +} diff --git a/functions/go/fix/generated/docs.go b/functions/go/fix/generated/docs.go new file mode 100644 index 000000000..3cbabb560 --- /dev/null +++ b/functions/go/fix/generated/docs.go @@ -0,0 +1,93 @@ + + +// Code generated by "mdtogo"; DO NOT EDIT. +package generated + +var FixShort = `Fix resources and make them compatible with kpt 1.0.` +var FixLong = ` +` + "`" + `fix` + "`" + ` helps you migrate the resources from ` + "`" + `v1alpha1` + "`" + ` format to ` + "`" + `v1alpha2` + "`" + ` format. +This is an automated step to migrate kpt packages which are compatible with kpt v0.X.Y +versions of kpt, and make them compatible with kpt 1.0 + +Here are the automated changes performed by ` + "`" + `fix` + "`" + ` function on ` + "`" + `v1alpha1` + "`" + ` kpt package: + +1. The ` + "`" + `packageMetaData` + "`" + ` section will be transformed to ` + "`" + `info` + "`" + ` section. +2. ` + "`" + `upstream` + "`" + ` section(if present), in the ` + "`" + `v1alpha1` + "`" + ` Kptfile is converted to ` + "`" + `upstream` + "`" + ` + and ` + "`" + `upstreamLock` + "`" + ` sections in ` + "`" + `v1alpha2` + "`" + ` version of Kptfile. +3. ` + "`" + `dependencies` + "`" + ` section will be removed from the Kptfile. +4. Setters no longer follow the OpenAPI format. The setters and substitutions will be converted + to simple setter patterns. ` + "`" + `apply-setters` + "`" + ` function is declared in the ` + "`" + `pipeline` + "`" + ` section. + Setters are configured using [configMap] option. +5. Function annotation from function configs will be removed and corresponding + function definitions will be [declared in pipeline] section of Kptfile. Reference + to function config is added via [configPath] option. + +Limitations of ` + "`" + `fix` + "`" + ` function: + +1. All the functions are treated as mutators by the ` + "`" + `fix` + "`" + ` function while migrating and are added to + the mutators section in the pipeline. Users must manually go through the functions + and move the validator functions to the [validators] section in the pipeline section + of ` + "`" + `v1alpha2` + "`" + ` Kptfile. +2. [Openapi validations] and [required setters] feature offered by v0.X.Y setters is + no longer offered in v1.0 version of kpt. ` + "`" + `fix` + "`" + ` function will remove them. + Users must write their own validation functions to achieve the functionality. + Tip: Adding a [starlark function] would be an easier alternative to achieve the + equivalent validation functionality. +3. If you have used [Starlark runtime] in v0.X, please checkout the new and improved + [starlark function] and declare it in the pipeline as ` + "`" + `fix` + "`" + ` funtion will remove them. +4. [Auto-setters] feature is deprecated in v1.0 version of kpt. Since the setters are + migrated to a new and simple declarative version, package consumers can easily + declare all the setter values and render them all at once. +5. The ` + "`" + `fix` + "`" + ` function does not alter resources in live cluster. + If you are using the [inventory object] to manage live cluster, please + refer to [live migrate] docs to perform live migration separately. +` +var FixExamples = ` +Let's start with a simple input resource which is compatible with kpt v0.X.Y + + apiVersion: apps/v1 + kind: Deployment + metadata: + name: my-nginx + spec: + replicas: 3 # {"$kpt-set":"replicas"} + +Here is the corresponding v1alpha1 Kptfile in the package + + apiVersion: kpt.dev/v1alpha1 + kind: Kptfile + metadata: + name: nginx + openAPI: + definitions: + io.k8s.cli.setters.replicas: + x-k8s-cli: + setter: + name: replicas + value: "3" + +Invoke ` + "`" + `fix` + "`" + ` function on the package: + + $ kpt fn eval --image gcr.io/kpt-fn/fix:unstable --include-meta-resources + +Here is the transformed resource + + apiVersion: apps/v1 + kind: Deployment + metadata: + name: my-nginx + spec: + replicas: 3 # kpt-set: ${replicas} + +Here is the transformed ` + "`" + `v1alpha2` + "`" + ` Kptfile: + + apiVersion: kpt.dev/v1alpha2 + kind: Kptfile + metadata: + name: nginx + pipeline: + mutators: + - image: gcr.io/kpt-fn/apply-setters:v0.1 + configMap: + replicas: "3" +` diff --git a/functions/go/fix/go.mod b/functions/go/fix/go.mod new file mode 100644 index 000000000..dcfd745c2 --- /dev/null +++ b/functions/go/fix/go.mod @@ -0,0 +1,12 @@ +module github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/fix + +go 1.15 + +require ( + github.com/go-openapi/spec v0.19.5 // indirect + github.com/qri-io/starlib v0.4.2-0.20200213133954-ff2e8cd5ef8d // indirect + github.com/stretchr/testify v1.7.0 + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e + sigs.k8s.io/kustomize/kyaml v0.10.20 +) diff --git a/functions/go/fix/go.sum b/functions/go/fix/go.sum new file mode 100644 index 000000000..e334968d0 --- /dev/null +++ b/functions/go/fix/go.sum @@ -0,0 +1,845 @@ +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= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/360EntSecGroup-Skylar/excelize v1.4.1/go.mod h1:vnax29X2usfl7HHkBrX5EvSCJcmH3dT9luvxzu8iGAE= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v14.2.0+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 v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +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/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/GoogleContainerTools/kpt v1.0.0-alpha.1.0.20210430222406-d40e7deb3dd1 h1:jmXMMd7hse+eOdaE60LiI8vCDD/fT/QT4ud/YelcZ9g= +github.com/GoogleContainerTools/kpt v1.0.0-alpha.1.0.20210430222406-d40e7deb3dd1/go.mod h1:bHJiUeVcstLgaVyMJQq8QBlNCj3tsuOaZOAqV/l9F04= +github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= +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/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg= +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/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/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +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 h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +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/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +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/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +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/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/etcd v3.3.13+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/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +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/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/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/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +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/dustmop/soup v1.1.2-0.20190516214245-38228baa104e/go.mod h1:CgNC6SGbT+Xb8wGGvzilttZL1mc5sQ/5KkcxsZttMIk= +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/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/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +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/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +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-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.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-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v0.3.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= +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 h1:8b2ZgKfKIUTVQpTb77MoRDIMEIwvDVw40o3aOXdfYzI= +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 h1:a2kIyV3w+OS3S97zxUndRVD46+FhGOUBDFY7nmu4CsY= +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 h1:5I4CCSqoWzT+82bBkNIvmLc0UOsoKKQ4Fz+3VxOB7SY= +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 h1:csnOgcgAiuGoM/Po7PEpKDoNulCcF3FGbSnbHfxgjMI= +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/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/spec v0.19.5 h1:Xm0Ao53uqnk9QE/LlYV5DEU09UAgpliA85QoT9LzqPw= +github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= +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/strfmt v0.19.5 h1:0utjKrw+BAh8s57XE9Xz8DUBsVvPmRUB6styvl9wWIM= +github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= +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-openapi/validate v0.19.8 h1:YFzsdWIDfVuLvIOF+ZmKjVg1MbPJ1QgY9PihMwei1ys= +github.com/go-openapi/validate v0.19.8/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gobuffalo/here v0.6.0 h1:hYrd0a6gDmWxBM4TnrGw8mQg24iSVoIkHEk7FodQcBI= +github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM= +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/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +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/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/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/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +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/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +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/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 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/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/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/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/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/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= +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/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +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/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +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/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/igorsobreira/titlecase v0.0.0-20140109233139-4156b5b858ac/go.mod h1:KOzUkqpWM2xArNm82cehGc5PBFYV1Qadzzt81aJi7F0= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.6/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/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/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +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.3/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/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +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/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +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/magiconair/properties v1.8.1/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/markbates/pkger v0.17.1 h1:/MKEtWqtc0mZvu9OinB9UzVN9iYCwLWuyUv4Bw+PCno= +github.com/markbates/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI= +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/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= +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-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= +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/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +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/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.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/paulmach/orb v0.1.3/go.mod h1:VFlX/8C+IQ1p6FTRRKzKoOPJnvEtA5G0Veuqwbu//Vk= +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/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/philopon/go-toposort v0.0.0-20170620085441-9be86dbd762f/go.mod h1:/iRjX3DdSK956SzsUdV55J+wIsQ+2IBWmBrB4RvZfk4= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +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/posener/complete/v2 v2.0.1-alpha.12/go.mod h1://JlL91cS2JV7rOl6LVHrRqBXoBUecJu3ILQPgbJiMQ= +github.com/posener/script v1.0.4/go.mod h1:Rg3ijooqulo05aGLyGsHoLmIOUzHUVK19WVgrYBPU/E= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +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.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +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/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +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.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +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.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/qri-io/starlib v0.4.2-0.20200213133954-ff2e8cd5ef8d/go.mod h1:7DPO4domFU579Ga6E61sB9VFNaniPVwJP5C4bBCu3wA= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +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/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/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/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/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= +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/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/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= +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 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= +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.2.3-0.20181224173747-660f15d67dbb/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/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +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 v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI= +github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= +github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +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 h1:jxcFYjlkl8xaERsgLo+RNquI0epW6zuy/ZRQs6jnrFA= +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/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.starlark.net v0.0.0-20190528202925-30ae18b8564f/go.mod h1:c1/X6cHgvdXj6pUlmWKMkuqRnW4K8x2vwt6JAaaircg= +go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= +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-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/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-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +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/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/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-20181023162649-9b4f9f5ad519/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-20181201002055-351d144fa1fc/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-20190503192946-f4e77d36d62c/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-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/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/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +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/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/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/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-20181026203630-95b1ffbd15a5/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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +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-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/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/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +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/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/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-20190312151545-0bb0c0a6e846/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-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +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-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +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.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +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-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +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.21.1/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/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +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-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/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/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +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/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.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +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-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78= +k8s.io/api v0.18.10/go.mod h1:xWtwPX1v47j5RTncmlMFGCx8b0avh+nP8OgZZ9hjo3M= +k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= +k8s.io/apiextensions-apiserver v0.18.2/go.mod h1:q3faSnRGmYimiocj6cHQ1I3WpLqmDgJFlKL37fC4ZvY= +k8s.io/apiextensions-apiserver v0.18.10/go.mod h1:XOE93YaGrb8Pa+ro00Jx3fhzRJ7UB0bU37jRTQXpTOM= +k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= +k8s.io/apimachinery v0.18.10/go.mod h1:PF5taHbXgTEJLU+xMypMmYTXTWPJ5LaW8bfsisxnEXk= +k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apiserver v0.18.2/go.mod h1:Xbh066NqrZO8cbsoenCwyDJ1OSi8Ag8I2lezeHxzwzw= +k8s.io/apiserver v0.18.10/go.mod h1:N4FaJo9BeSgmtvVByXi4fPSQPRqhvvLMGqswwkddob8= +k8s.io/cli-runtime v0.20.4/go.mod h1:dz38e1CM4uuIhy8PMFUZv7qsvIdoE3ByZYlmbHNCkt4= +k8s.io/client-go v0.18.2/go.mod h1:Xcm5wVGXX9HAA2JJ2sSBUn3tCJ+4SVlCbl2MNNv+CIU= +k8s.io/client-go v0.18.10/go.mod h1:XBkFAqPrzqfwmGkV5ac+mlgBpWcz5TkhLw2808q8C3c= +k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k= +k8s.io/code-generator v0.18.2/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= +k8s.io/code-generator v0.18.10/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= +k8s.io/code-generator v0.20.4/go.mod h1:UsqdF+VX4PU2g46NC2JRs4gc+IfrctnwHb76RNbWHJg= +k8s.io/component-base v0.18.2/go.mod h1:kqLlMuhJNHQ9lz8Z7V5bxUUtjFZnrypArGl58gmDfUM= +k8s.io/component-base v0.18.10/go.mod h1:ZzFXjzUBHKOcF0mnWkxBI1wDu5t+CV3GxXKKvHZBLf0= +k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI= +k8s.io/component-helpers v0.20.4/go.mod h1:S7jGg8zQp3kwvSzfuGtNaQAMVmvzomXDioTm5vABn9g= +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/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20201113003025-83324d819ded/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +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/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= +k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= +k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= +k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM= +k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= +k8s.io/kubectl v0.20.4/go.mod h1:yCC5lUQyXRmmtwyxfaakryh9ezzp/bT0O14LeoFLbGo= +k8s.io/metrics v0.20.4/go.mod h1:DDXS+Ls+2NAxRcVhXKghRPa3csljyJRjDRjPe6EOg/g= +k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0= +sigs.k8s.io/cli-utils v0.25.0/go.mod h1:dllg30GE57wkWbvaA9lI1cpDwTKxb9NAENStrQ3fQxg= +sigs.k8s.io/controller-runtime v0.6.0/go.mod h1:CpYf5pdNY/B352A1TFLAS2JVSlnGQ5O2cftPHndTroo= +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/kustomize/kyaml v0.10.10 h1:caAxDDkaXZp+0kDsZVik4leFJV8LCy09PdVqpaoNeF4= +sigs.k8s.io/kustomize/kyaml v0.10.10/go.mod h1:K9yg1k/HB/6xNOf5VH3LhTo1DK9/5ykSZO5uIv+Y/1k= +sigs.k8s.io/kustomize/kyaml v0.10.16/go.mod h1:mlQFagmkm1P+W4lZJbJ/yaxMd8PqMRSC4cPcfUVt5Hg= +sigs.k8s.io/kustomize/kyaml v0.10.17 h1:4zrV0ym5AYa0e512q7K3Wp1u7mzoWW0xR3UHJcGWGIg= +sigs.k8s.io/kustomize/kyaml v0.10.17/go.mod h1:mlQFagmkm1P+W4lZJbJ/yaxMd8PqMRSC4cPcfUVt5Hg= +sigs.k8s.io/kustomize/kyaml v0.10.19 h1:us4+KUSKRpSox16AmjHkYORIlkWuQSLUaU5iGL7kkK4= +sigs.k8s.io/kustomize/kyaml v0.10.19/go.mod h1:h94DSoDbmnN4BTc6VTX7tGNGXZy29rbPo+R4jGMvA8U= +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/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/functions/go/fix/main.go b/functions/go/fix/main.go new file mode 100644 index 000000000..db0ef142c --- /dev/null +++ b/functions/go/fix/main.go @@ -0,0 +1,69 @@ +package main + +import ( + "fmt" + "os" + + "github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/fix/fixpkg" + "github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/fix/generated" + "sigs.k8s.io/kustomize/kyaml/fn/framework" + "sigs.k8s.io/kustomize/kyaml/fn/framework/command" + kyaml "sigs.k8s.io/kustomize/kyaml/yaml" +) + +//nolint +func main() { + resourceList := &framework.ResourceList{} + resourceList.FunctionConfig = &kyaml.RNode{} + fp := FixProcessor{} + cmd := command.Build(&fp, command.StandaloneEnabled, false) + + cmd.Short = generated.FixShort + cmd.Long = generated.FixLong + cmd.Example = generated.FixExamples + + if err := cmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(1) + } +} + +type FixProcessor struct{} + +func (fp *FixProcessor) Process(resourceList *framework.ResourceList) error { + s := &fixpkg.Fix{} + var err error + resourceList.Result = &framework.Result{ + Name: "fix", + } + resourceList.Items, err = s.Filter(resourceList.Items) + if err != nil { + resourceList.Result.Items = getErrorItem(err.Error()) + return nil + } + resourceList.Result.Items = resultsToItems(s) + return nil +} + +// resultsToItems converts the Search and Replace results to +// equivalent items([]framework.Item) +func resultsToItems(sr *fixpkg.Fix) []framework.ResultItem { + var items []framework.ResultItem + for _, res := range sr.Results { + items = append(items, framework.ResultItem{ + Message: res.Message, + File: framework.File{Path: res.FilePath}, + }) + } + return items +} + +// getErrorItem returns the item for input error message +func getErrorItem(errMsg string) []framework.ResultItem { + return []framework.ResultItem{ + { + Message: fmt.Sprintf("failed to fix package: %s", errMsg), + Severity: framework.Error, + }, + } +} diff --git a/functions/go/fix/metadata.yaml b/functions/go/fix/metadata.yaml new file mode 100644 index 000000000..8bc310e3f --- /dev/null +++ b/functions/go/fix/metadata.yaml @@ -0,0 +1,10 @@ +image: gcr.io/kpt-fn/fix +description: Fix resources and make them compatible with kpt 1.0. +tags: + - mutator +sourceURL: https://github.com/GoogleContainerTools/kpt-functions-catalog/tree/master/functions/go/fix +examplePackageURLs: + - https://github.com/GoogleContainerTools/kpt-functions-catalog/tree/master/examples/fix/simple +emails: + - kpt-team@google.com +license: Apache-2.0 diff --git a/functions/go/fix/v1alpha1/types.go b/functions/go/fix/v1alpha1/types.go new file mode 100644 index 000000000..9af061ba4 --- /dev/null +++ b/functions/go/fix/v1alpha1/types.go @@ -0,0 +1,169 @@ +package v1alpha1 + +import ( + "fmt" + "strings" + + "sigs.k8s.io/kustomize/kyaml/yaml" +) + +// KptFileName is the name of the KptFile +const ( + KptFileName = "Kptfile" + KptFileGroup = "kpt.dev" + KptFileVersion = "v1alpha1" + KptFileAPIVersion = KptFileGroup + "/" + KptFileVersion +) + +// TypeMeta is the TypeMeta for KptFile instances. +var TypeMeta = yaml.ResourceMeta{ + TypeMeta: yaml.TypeMeta{ + APIVersion: KptFileAPIVersion, + Kind: KptFileName, + }, +} + +// KptFile contains information about a package managed with kpt +type KptFile struct { + yaml.ResourceMeta `yaml:",inline"` + + // CloneFrom records where the package was originally cloned from + Upstream *Upstream `yaml:"upstream,omitempty"` + + // PackageMeta contains information about the package + PackageMeta *PackageMeta `yaml:"packageMetadata,omitempty"` + + Dependencies []Dependency `yaml:"dependencies,omitempty"` + + // OpenAPI contains additional schema for the resources in this package + // Uses interface{} instead of Node to work around yaml serialization issues + // See https://github.com/go-yaml/yaml/issues/518 and + // https://github.com/go-yaml/yaml/issues/575 + OpenAPI interface{} `yaml:"openAPI,omitempty"` + + // Functions contains configuration for running functions + Functions Functions `yaml:"functions,omitempty"` + + // Parameters for inventory object. + Inventory *Inventory `yaml:"inventory,omitempty"` +} + +// Inventory encapsulates the parameters for the inventory object. All of the +// the parameters are required if any are set. +type Inventory struct { + Namespace string `yaml:"namespace,omitempty"` + Name string `yaml:"name,omitempty"` + // Unique label to identify inventory object in cluster. + InventoryID string `yaml:"inventoryID,omitempty"` + Labels map[string]string `yaml:"labels,omitempty"` + Annotations map[string]string `yaml:"annotations,omitempty"` +} + +type Functions struct { + // AutoRunStarlark will cause starlark functions to automatically be run. + AutoRunStarlark bool `yaml:"autoRunStarlark,omitempty"` + + // StarlarkFunctions is a list of starlark functions to run + StarlarkFunctions []StarlarkFunction `yaml:"starlarkFunctions,omitempty"` +} + +type StarlarkFunction struct { + // Name is the name that will be given to the program + Name string `yaml:"name,omitempty"` + // Path is the path to the *.star script to run + Path string `yaml:"path,omitempty"` +} + +type Dependency struct { + Name string `yaml:"name,omitempty"` + Upstream `yaml:",inline,omitempty"` + EnsureNotExists bool `yaml:"ensureNotExists,omitempty"` + Strategy string `yaml:"updateStrategy,omitempty"` + Functions []Function `yaml:"functions,omitempty"` + AutoSet bool `yaml:"autoSet,omitempty"` +} + +type PackageMeta struct { + // URL is the location of the package. e.g. https://github.com/example/com + URL string `yaml:"url,omitempty"` + + // Email is the email of the package maintainer + Email string `yaml:"email,omitempty"` + + // License is the package license + License string `yaml:"license,omitempty"` + + // Version is the package version + Version string `yaml:"version,omitempty"` + + // Tags can be indexed and are metadata about the package + Tags []string `yaml:"tags,omitempty"` + + // Man is the path to documentation about the package + Man string `yaml:"man,omitempty"` + + // ShortDescription contains a short description of the package. + ShortDescription string `yaml:"shortDescription,omitempty"` +} + +// OriginType defines the type of origin for a package +type OriginType string + +const ( + // GitOrigin specifies a package as having been cloned from a git repository + GitOrigin OriginType = "git" + StdinOrigin OriginType = "stdin" +) + +// Upstream defines where a package was cloned from +type Upstream struct { + // Type is the type of origin. + Type OriginType `yaml:"type,omitempty"` + + // Git contains information on the origin of packages cloned from a git repository. + Git Git `yaml:"git,omitempty"` + + Stdin Stdin `yaml:"stdin,omitempty"` +} + +type Stdin struct { + FilenamePattern string `yaml:"filenamePattern,omitempty"` + + Original string `yaml:"original,omitempty"` +} + +// Git contains information on the origin of packages cloned from a git repository. +type Git struct { + // Commit is the git commit that the package was fetched at + Commit string `yaml:"commit,omitempty"` + + // Repo is the git repository the package was cloned from. e.g. https:// + Repo string `yaml:"repo,omitempty"` + + // RepoDirectory is the sub directory of the git repository that the package was cloned from + Directory string `yaml:"directory,omitempty"` + + // Ref is the git ref the package was cloned from + Ref string `yaml:"ref,omitempty"` +} + +type Function struct { + Config yaml.Node `yaml:"config,omitempty"` + Image string `yaml:"image,omitempty"` +} + +// ReadFile reads the KptFile node +func ReadFile(node *yaml.RNode) (*KptFile, error) { + kpgfile := &KptFile{ResourceMeta: TypeMeta} + s, err := node.String() + if err != nil { + return &KptFile{}, err + } + f := strings.NewReader(s) + d := yaml.NewDecoder(f) + d.KnownFields(true) + if err = d.Decode(&kpgfile); err != nil { + return &KptFile{}, fmt.Errorf("please make sure the package has a valid 'v1alpha1' Kptfile: %s", err) + } + return kpgfile, nil +} diff --git a/functions/go/fix/v1alpha2/types.go b/functions/go/fix/v1alpha2/types.go new file mode 100644 index 000000000..11bab2f6d --- /dev/null +++ b/functions/go/fix/v1alpha2/types.go @@ -0,0 +1,281 @@ +package v1alpha2 + +import ( + "fmt" + "sigs.k8s.io/kustomize/kyaml/yaml" +) + +const ( + KptFileName = "Kptfile" + KptFileGroup = "kpt.dev" + KptFileVersion = "v1alpha2" + KptFileAPIVersion = KptFileGroup + "/" + KptFileVersion +) + +// TypeMeta is the TypeMeta for KptFile instances. +var TypeMeta = yaml.ResourceMeta{ + TypeMeta: yaml.TypeMeta{ + APIVersion: KptFileAPIVersion, + Kind: KptFileName, + }, +} + +// KptFile contains information about a package managed with kpt. +type KptFile struct { + yaml.ResourceMeta `yaml:",inline"` + + Upstream *Upstream `yaml:"upstream,omitempty"` + + // UpstreamLock is a resolved locator for the last fetch of the package. + UpstreamLock *UpstreamLock `yaml:"upstreamLock,omitempty"` + + // Info contains metadata such as license, documentation, etc. + Info *PackageInfo `yaml:"info,omitempty"` + + // Pipeline declares the pipeline of functions. + Pipeline *Pipeline `yaml:"pipeline,omitempty"` + + // Inventory contains parameters for the inventory object used in apply. + Inventory *Inventory `yaml:"inventory,omitempty"` +} + +// OriginType defines the type of origin for a package. +type OriginType string + +const ( + // GitOrigin specifies a package as having been cloned from a git repository. + GitOrigin OriginType = "git" +) + +// UpdateStrategyType defines the strategy for updating a package from upstream. +type UpdateStrategyType string + +// ToUpdateStrategy takes a string representing an update strategy and will +// return the strategy as an UpdateStrategyType. If the provided string does +// not match any known update strategies, an error will be returned. +func ToUpdateStrategy(strategy string) (UpdateStrategyType, error) { + switch strategy { + case string(ResourceMerge): + return ResourceMerge, nil + case string(FastForward): + return FastForward, nil + case string(ForceDeleteReplace): + return ForceDeleteReplace, nil + default: + return "", fmt.Errorf("unknown update strategy %q", strategy) + } +} + +const ( + // ResourceMerge performs a structural schema-aware comparison and + // merges the changes into the local package. + ResourceMerge UpdateStrategyType = "resource-merge" + // FastForward fails without updating if the local package was modified + // since it was fetched. + FastForward UpdateStrategyType = "fast-forward" + // ForceDeleteReplace wipes all local changes to the package. + ForceDeleteReplace UpdateStrategyType = "force-delete-replace" +) + +// UpdateStrategies is a slice with all the supported update strategies. +var UpdateStrategies = []UpdateStrategyType{ + ResourceMerge, + FastForward, + ForceDeleteReplace, +} + +// UpdateStrategiesAsStrings returns a list of update strategies as strings. +func UpdateStrategiesAsStrings() []string { + var strs []string + for _, s := range UpdateStrategies { + strs = append(strs, string(s)) + } + return strs +} + +// Upstream is a user-specified upstream locator for a package. +type Upstream struct { + // Type is the type of origin. + Type OriginType `yaml:"type,omitempty"` + + // Git is the locator for a package stored on Git. + Git *Git `yaml:"git,omitempty"` + + // UpdateStrategy declares how a package will be updated from upstream. + UpdateStrategy UpdateStrategyType `yaml:"updateStrategy,omitempty"` +} + +// Git is the user-specified locator for a package on Git. +type Git struct { + // Repo is the git repository the package. + // e.g. 'https://github.com/kubernetes/examples.git' + Repo string `yaml:"repo,omitempty"` + + // Directory is the sub directory of the git repository. + // e.g. 'staging/cockroachdb' + Directory string `yaml:"directory,omitempty"` + + // Ref can be a Git branch, tag, or a commit SHA-1. + Ref string `yaml:"ref,omitempty"` +} + +// UpstreamLock is a resolved locator for the last fetch of the package. +type UpstreamLock struct { + // Type is the type of origin. + Type OriginType `yaml:"type,omitempty"` + + // Git is the resolved locator for a package on Git. + Git *GitLock `yaml:"git,omitempty"` +} + +// GitLock is the resolved locator for a package on Git. +type GitLock struct { + // Repo is the git repository that was fetched. + // e.g. 'https://github.com/kubernetes/examples.git' + Repo string `yaml:"repo,omitempty"` + + // Directory is the sub directory of the git repository that was fetched. + // e.g. 'staging/cockroachdb' + Directory string `yaml:"directory,omitempty"` + + // Ref can be a Git branch, tag, or a commit SHA-1 that was fetched. + // e.g. 'master' + Ref string `yaml:"ref,omitempty"` + + // Commit is the SHA-1 for the last fetch of the package. + // This is set by kpt for bookkeeping purposes. + Commit string `yaml:"commit,omitempty"` +} + +// PackageInfo contains optional information about the package such as license, documentation, etc. +// These fields are not consumed by any functionality in kpt and are simply passed through. +// Note that like any other KRM resource, humans and automation can also use `metadata.labels` and +// `metadata.annotations` as the extrension mechanism. +type PackageInfo struct { + // Site is the URL for package web page. + Site string `yaml:"site,omitempty"` + + // Email is the list of emails for the package authors. + Emails []string `yaml:"emails,omitempty"` + + // SPDX license identifier (e.g. "Apache-2.0"). See: https://spdx.org/licenses/ + License string `yaml:"license,omitempty"` + + // Relative slash-delimited path to the license file (e.g. LICENSE.txt) + LicenseFile string `yaml:"licenseFile,omitempty"` + + // Doc is the path to documentation about the package. + Doc string `yaml:"doc,omitempty"` + + // Description contains a short description of the package. + Description string `yaml:"description,omitempty"` + + // Keywords is a list of keywords for this package. + Keywords []string `yaml:"keywords,omitempty"` + + // Man is the path to documentation about the package + Man string `yaml:"man,omitempty"` +} + +// Subpackages declares a local or remote subpackage. +type Subpackage struct { + // Name of the immediate subdirectory relative to this Kptfile where the suppackage + // either exists (local subpackages) or will be fetched to (remote subpckages). + // This must be unique across all subpckages of a package. + LocalDir string `yaml:"localDir,omitempty"` + + // Upstream is a reference to where the subpackage should be fetched from. + // Whether a subpackage is local or remote is determined by whether Upstream is specified. + Upstream *Upstream `yaml:"upstream,omitempty"` +} + +// Pipeline declares a pipeline of functions used to mutate or validate resources. +type Pipeline struct { + // Sources defines the source packages to resolve as input to the pipeline. Possible values: + // a) A slash-separated, OS-agnostic relative package path which may include '.' and '..' e.g. './base', '../foo' + // The source package is resolved recursively. + // b) Resources in this package using '.'. Meta resources such as the Kptfile, Pipeline, and function configs + // are excluded. + // c) Resources in this package AND all resolved subpackages using './*' + // + // Resultant list of resources are ordered: + // - According to the order of sources specified in this array. + // - When using './*': Subpackages are resolved in alphanumerical order before package resources. + // + // When omitted, defaults to './*'. + // Sources []string `yaml:"sources,omitempty"` + + // Following fields define the sequence of functions in the pipeline. + // Input of the first function is the resolved sources. + // Input of the second function is the output of the first function, and so on. + // Order of operation: mutators, validators + + // Mutators defines a list of of KRM functions that mutate resources. + Mutators []Function `yaml:"mutators,omitempty"` + + // Validators defines a list of KRM functions that validate resources. + // Validators are not permitted to mutate resources. + Validators []Function `yaml:"validators,omitempty"` +} + +// String returns the string representation of Pipeline struct +// The string returned is the struct content in Go default format. +func (p *Pipeline) String() string { + return fmt.Sprintf("%+v", *p) +} + +// IsEmpty returns true if the pipeline doesn't contain any functions in any of +// the function chains (mutators, validators). +func (p *Pipeline) IsEmpty() bool { + if p == nil { + return true + } + if len(p.Mutators) == 0 && len(p.Validators) == 0 { + return true + } + return false +} + +// Function specifies a KRM function. +type Function struct { + // `Image` specifies the function container image. + // It can either be fully qualified, e.g.: + // + // image: gcr.io/kpt-fn/set-label + // + // Optionally, kpt can be configured to use a image + // registry host-path that will be used to resolve the image path in case + // the image path is missing (Defaults to gcr.io/kpt-fn). + // e.g. The following resolves to gcr.io/kpt-fn/set-label: + // + // image: set-label + Image string `yaml:"image,omitempty"` + + // `Config` specifies an inline KRM resource used as the function config. + // Config, ConfigPath, and ConfigMap fields are mutually exclusive. + // We cannot use a pointer to yaml.Node because it will cause errors when + // we try to unmarshal the YAML. + Config yaml.Node `yaml:"config,omitempty"` + + // `ConfigPath` specifies a slash-delimited relative path to a file in the current directory + // containing a KRM resource used as the function config. This resource is + // excluded when resolving 'sources', and as a result cannot be operated on + // by the pipeline. + ConfigPath string `yaml:"configPath,omitempty"` + + // `ConfigMap` is a convenient way to specify a function config of kind ConfigMap. + ConfigMap map[string]string `yaml:"configMap,omitempty"` +} + +// Inventory encapsulates the parameters for the inventory resource applied to a cluster. +// All of the the parameters are required if any are set. +type Inventory struct { + // Namespace for the inventory resource. + Namespace string `yaml:"namespace,omitempty"` + // Name of the inventory resource. + Name string `yaml:"name,omitempty"` + // Unique label to identify inventory resource in cluster. + InventoryID string `yaml:"inventoryID,omitempty"` + Labels map[string]string `yaml:"labels,omitempty"` + Annotations map[string]string `yaml:"annotations,omitempty"` +} diff --git a/functions/go/format/Dockerfile b/functions/go/format/Dockerfile new file mode 100644 index 000000000..4296cbdcd --- /dev/null +++ b/functions/go/format/Dockerfile @@ -0,0 +1,15 @@ +FROM golang:1.15-alpine3.12 +ENV CGO_ENABLED=0 +WORKDIR /go/src/ + +COPY go.mod go.sum ./ +RUN go mod download + +COPY . . +RUN go build -o /usr/local/bin/function ./ + +############################################# + +FROM alpine:3.12 +COPY --from=0 /usr/local/bin/function /usr/local/bin/function +ENTRYPOINT ["function"] diff --git a/functions/go/format/README.md b/functions/go/format/README.md new file mode 100644 index 000000000..25d422b36 --- /dev/null +++ b/functions/go/format/README.md @@ -0,0 +1,72 @@ +# format + +### Overview + + + +Format the field ordering in resources. + + + +### Synopsis + + + +The `format` function formats the field ordering in YAML configuration files. Field +ordering follows the ordering defined in the OpenAPI document for Kubernetes resources, +falling back on lexicographical sorting for unrecognized fields. This function also performs +other changes like fixing indentation, adding quotes to ambiguous string values. + + + +### Examples + + + +#### Format a package + +Let's start with the input resource in a package. + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + bar: 100 + name: nginx-deployment +spec: + template: + spec: + containers: + - name: nginx + image: nginx:1.0.0 + ports: + - containerPort: 80 + name: http +``` + +Invoke the `format` function on the package, formatted resource looks like the following: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + annotations: + bar: "100" +spec: + template: + spec: + containers: + - name: nginx + image: nginx:1.0.0 + ports: + - name: http + containerPort: 80 +``` + +The fields are ordered as per the OpenAPI schema definition of `Deployment` resource. For e.g. `metadata.name` field +is moved up. Since the type of annotation value is `string`, quotes are added to value `100` as it will be interpreted +as `int` by yaml in its current form. + + diff --git a/functions/go/format/generated/docs.go b/functions/go/format/generated/docs.go new file mode 100644 index 000000000..93073ff26 --- /dev/null +++ b/functions/go/format/generated/docs.go @@ -0,0 +1,55 @@ + + +// Code generated by "mdtogo"; DO NOT EDIT. +package generated + +var FormatShort = `Format the field ordering in resources.` +var FormatLong = ` +The ` + "`" + `format` + "`" + ` function formats the field ordering in YAML configuration files. Field +ordering follows the ordering defined in the OpenAPI document for Kubernetes resources, +falling back on lexicographical sorting for unrecognized fields. This function also performs +other changes like fixing indentation, adding quotes to ambiguous string values. +` +var FormatExamples = ` +Format a package: + +Let's start with the input resource in a package. + + apiVersion: apps/v1 + kind: Deployment + metadata: + annotations: + bar: 100 + name: nginx-deployment + spec: + template: + spec: + containers: + - name: nginx + image: nginx:1.0.0 + ports: + - containerPort: 80 + name: http + +Invoke the ` + "`" + `format` + "`" + ` function on the package, formatted resource looks like the following: + + apiVersion: apps/v1 + kind: Deployment + metadata: + name: nginx-deployment + annotations: + bar: "100" + spec: + template: + spec: + containers: + - name: nginx + image: nginx:1.0.0 + ports: + - name: http + containerPort: 80 + +The fields are ordered as per the OpenAPI schema definition of ` + "`" + `Deployment` + "`" + ` resource. For e.g. ` + "`" + `metadata.name` + "`" + ` field +is moved up. Since the type of annotation value is ` + "`" + `string` + "`" + `, quotes are added to value ` + "`" + `100` + "`" + ` as it will be interpreted +as ` + "`" + `int` + "`" + ` by yaml in its current form. +` diff --git a/functions/go/format/go.mod b/functions/go/format/go.mod new file mode 100644 index 000000000..d9eb91bfd --- /dev/null +++ b/functions/go/format/go.mod @@ -0,0 +1,8 @@ +module github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/format + +go 1.15 + +require ( + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + sigs.k8s.io/kustomize/kyaml v0.10.20 +) diff --git a/functions/go/format/go.sum b/functions/go/format/go.sum new file mode 100644 index 000000000..f08c30866 --- /dev/null +++ b/functions/go/format/go.sum @@ -0,0 +1,537 @@ +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/360EntSecGroup-Skylar/excelize v1.4.1/go.mod h1:vnax29X2usfl7HHkBrX5EvSCJcmH3dT9luvxzu8iGAE= +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/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +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/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM= +github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg= +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/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= +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/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +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/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/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= +github.com/bombsimon/wsl v1.2.5/go.mod h1:43lEF/i0kpXbLCeDXL9LMT8c92HyBywXb0AsgMHYngM= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +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-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +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/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/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/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/dustmop/soup v1.1.2-0.20190516214245-38228baa104e/go.mod h1:CgNC6SGbT+Xb8wGGvzilttZL1mc5sQ/5KkcxsZttMIk= +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/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/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +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/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-critic/go-critic v0.3.5-0.20190904082202-d79a9f0c64db/go.mod h1:+sE8vrLDS2M0pZkBk0wy6+nLdKexVDrl/jBqQOTDThA= +github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM= +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-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= +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/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/spec v0.19.5 h1:Xm0Ao53uqnk9QE/LlYV5DEU09UAgpliA85QoT9LzqPw= +github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= +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/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= +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.8/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4= +github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ= +github.com/go-toolsmith/astequal v0.0.0-20180903214952-dcb477bfacd6/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY= +github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY= +github.com/go-toolsmith/astfmt v0.0.0-20180903215011-8f8ee99c3086/go.mod h1:mP93XdblcopXwlyN4X4uodxXQhldPGZbcEJIimQHrkg= +github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw= +github.com/go-toolsmith/astinfo v0.0.0-20180906194353-9809ff7efb21/go.mod h1:dDStQCHtmZpYOmjRP/8gHHnCCch3Zz3oEgCdZVdtweU= +github.com/go-toolsmith/astp v0.0.0-20180903215135-0af7e3c24f30/go.mod h1:SV2ur98SGypH1UjcPpCatrV5hPazG6+IfNHbkDXBRrk= +github.com/go-toolsmith/astp v1.0.0/go.mod h1:RSyrtpVlfTFGDYRbrjyWP1pYu//tSFcvdYrA8meBmLI= +github.com/go-toolsmith/pkgload v0.0.0-20181119091011-e9e65178eee8/go.mod h1:WoMrjiy4zvdS+Bg6z9jZH82QXwkcgCBX6nOfnmdaHks= +github.com/go-toolsmith/pkgload v1.0.0/go.mod h1:5eFArkbO80v7Z0kdngIxsRXRMTaX4Ilcwuh3clNrQJc= +github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= +github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU= +github.com/gobuffalo/here v0.6.0 h1:hYrd0a6gDmWxBM4TnrGw8mQg24iSVoIkHEk7FodQcBI= +github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/gofrs/flock v0.0.0-20190320160742-5135e617513b/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.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +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/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/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4= +github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= +github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6/go.mod h1:DbHgvLiFKX1Sh2T1w8Q/h4NAI8MHIpzCdnBUDTXU3I0= +github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613/go.mod h1:SyvUF2NxV+sN8upjjeVYr5W7tyxaT1JVtvhKhOn2ii8= +github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3/go.mod h1:JXrF4TWy4tXYn62/9x8Wm/K/dm06p8tCKwFRDPZG/1o= +github.com/golangci/gocyclo v0.0.0-20180528134321-2becd97e67ee/go.mod h1:ozx7R9SIwqmqf5pRP90DhR2Oay2UIjGuKheCBCNwAYU= +github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU= +github.com/golangci/golangci-lint v1.21.0/go.mod h1:phxpHK52q7SE+5KpPnti4oZTdFCEsn/tKN+nFvCKXfk= +github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc/go.mod h1:e5tpTHCfVze+7EpLEozzMB3eafxo2KT5veNg1k6byQU= +github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg= +github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o= +github.com/golangci/misspell v0.0.0-20180809174111-950f5d19e770/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA= +github.com/golangci/prealloc v0.0.0-20180630174525-215b22d4de21/go.mod h1:tf5+bzsHdTM0bsB7+8mt0GUMvjCgwLpTapNZHU8AajI= +github.com/golangci/revgrep v0.0.0-20180526074752-d9c87f5ffaf0/go.mod h1:qOQCunEYvmd/TLamH+7LlVccLvUH5kZNhbCgTHoBbp4= +github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +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 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= +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 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= +github.com/google/gofuzz v1.0.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/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +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 h1:7XGaL1e6bYS1yIonGp9761ExpPPV1ui0SAC59Yube9k= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= +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-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/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= +github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +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/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q= +github.com/imdario/mergo v0.3.5/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/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +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/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/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/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/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= +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/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= +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/markbates/pkger v0.17.1 h1:/MKEtWqtc0mZvu9OinB9UzVN9iYCwLWuyUv4Bw+PCno= +github.com/markbates/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI= +github.com/matoous/godox v0.0.0-20190911065817-5d6d842e92eb/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-ps v0.0.0-20190716172923-621e5597135b/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +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-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 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= +github.com/mozilla/tls-observatory v0.0.0-20190404164649-a3c1b6cfecfd/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/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/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +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/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/paulmach/orb v0.1.3/go.mod h1:VFlX/8C+IQ1p6FTRRKzKoOPJnvEtA5G0Veuqwbu//Vk= +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/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/phanimarupaka/kustomize2 v0.1.0 h1:ezFwCewv1yd13MPDG2kZPZ5NyzO+taOPtgdAtx1McGg= +github.com/phanimarupaka/kustomize2 v0.1.0/go.mod h1:7z2jt4QUhXKryfKCE72QZwJlOFWZTlqtyOsbLxT10Iw= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +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/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_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/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/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/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/qri-io/starlib v0.4.2-0.20200213133954-ff2e8cd5ef8d h1:K6eOUihrFLdZjZnA4XlRp864fmWXv9YTIk7VPLhRacA= +github.com/qri-io/starlib v0.4.2-0.20200213133954-ff2e8cd5ef8d/go.mod h1:7DPO4domFU579Ga6E61sB9VFNaniPVwJP5C4bBCu3wA= +github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +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/securego/gosec v0.0.0-20191002120514-e680875ea14d/go.mod h1:w5+eXa0mYznDkHaMCXA4XYffjlH+cy1oyKbfzJXa2Do= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shirou/gopsutil v0.0.0-20190901111213-e4ec7b275ada/go.mod h1:WWnYX4lzhCH5h/3YBfyVA3VbLYjlMZZAQcW9ojMexNc= +github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sourcegraph/go-diff v0.5.1/go.mod h1:j2dHj3m8aZgQO8lMTcTnBcXkRRRqi34cd2MNlA9u1mE= +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/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.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 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.3-0.20181224173747-660f15d67dbb/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= +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/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= +github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= +github.com/uudashr/gocognit v0.0.0-20190926065955-1655d0de0517/go.mod h1:j44Ayx2KW4+oB6SWMv8KsmHzZrOInQav7D3cQMJ5JUM= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s= +github.com/valyala/quicktemplate v1.2.0/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= +github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI= +github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yujunz/go-getter v1.5.1-lite.0.20201201013212-6d9c071adddf/go.mod h1:bL0Pr07HEdsMZ1WBqZIxXj96r5LnFsY4LgPaPEGkw1k= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +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.starlark.net v0.0.0-20190528202925-30ae18b8564f/go.mod h1:c1/X6cHgvdXj6pUlmWKMkuqRnW4K8x2vwt6JAaaircg= +go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc= +go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= +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-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-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +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-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= +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/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/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-20180911220305-26e67e76b6c3/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-20190522155817-f3200d17e092/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-20190620200207-3b0461eec859/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-20190923162816-aa69164e4478/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/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/sys v0.0.0-20170830134202-bb24a47a89ea/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-20190222072716-a9d3bda3a223/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-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/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-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +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-20180525024113-a5b4c53f6e8b/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-20181117154741-2ddaf7f79a09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190110163146-51295c7ec13a/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-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd/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-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190719005602-e377ae9d6386/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190930201159-7c411dea38b0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +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/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/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +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-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +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.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +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.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +k8s.io/api v0.17.0 h1:H9d/lw+VkZKEVIUc8F3wgiQ+FUXTTr21M87jXLU7yqM= +k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= +k8s.io/apimachinery v0.17.0 h1:xRBnuie9rXcPxUkDizUsGvPf1cnlZCFu210op7J7LJo= +k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/client-go v0.17.0 h1:8QOGvUGdqDMFrm9sD6IUFl256BcffynGoe80sxgTEDg= +k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/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-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU= +k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= +mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= +mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw= +sigs.k8s.io/kustomize v1.0.11 h1:Yb+6DDt9+aR2AvQApvUaKS/ugteeG4MPyoFeUHiPOjk= +sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0= +sigs.k8s.io/kustomize/api v0.7.2 h1:ItTD/2XaKO8CosOMFZdaGFdUGTCHdQriW7zQ7AR98rs= +sigs.k8s.io/kustomize/api v0.7.2/go.mod h1:50/vLATrjhRmMr3spZsI1GcpoZJ8IARy9QstPbA9lGE= +sigs.k8s.io/kustomize/api v0.8.1 h1:7HNZ82JKD45Hnl3jLi4DR9+LbWbN0OdyeOnSGqbZ8wQ= +sigs.k8s.io/kustomize/api v0.8.1/go.mod h1:M0HMIEWuO4nBaZ3WhRe4tHKTVCqCqYkqhrRpZ0B/ElA= +sigs.k8s.io/kustomize/kyaml v0.10.6/go.mod h1:K9yg1k/HB/6xNOf5VH3LhTo1DK9/5ykSZO5uIv+Y/1k= +sigs.k8s.io/kustomize/kyaml v0.10.10 h1:caAxDDkaXZp+0kDsZVik4leFJV8LCy09PdVqpaoNeF4= +sigs.k8s.io/kustomize/kyaml v0.10.10/go.mod h1:K9yg1k/HB/6xNOf5VH3LhTo1DK9/5ykSZO5uIv+Y/1k= +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= +sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/functions/go/format/main.go b/functions/go/format/main.go new file mode 100644 index 000000000..191e8a1ca --- /dev/null +++ b/functions/go/format/main.go @@ -0,0 +1,42 @@ +package main + +import ( + "fmt" + "os" + + "github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/format/generated" + "sigs.k8s.io/kustomize/kyaml/fn/framework" + "sigs.k8s.io/kustomize/kyaml/fn/framework/command" + "sigs.k8s.io/kustomize/kyaml/kio/filters" + kyaml "sigs.k8s.io/kustomize/kyaml/yaml" +) + +//nolint +func main() { + resourceList := &framework.ResourceList{} + resourceList.FunctionConfig = &kyaml.RNode{} + asp := FormatProcessor{} + cmd := command.Build(&asp, command.StandaloneEnabled, false) + + cmd.Short = generated.FormatShort + cmd.Long = generated.FormatLong + cmd.Example = generated.FormatExamples + + if err := cmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(1) + } +} + +func (fp *FormatProcessor) Process(resourceList *framework.ResourceList) error { + f := filters.FormatFilter{ + UseSchema: true, + } + _, err := f.Filter(resourceList.Items) + if err != nil { + return fmt.Errorf("failed to format resources: %w", err) + } + return nil +} + +type FormatProcessor struct{} diff --git a/functions/go/format/metadata.yaml b/functions/go/format/metadata.yaml new file mode 100644 index 000000000..74b2f0a06 --- /dev/null +++ b/functions/go/format/metadata.yaml @@ -0,0 +1,11 @@ +image: gcr.io/kpt-fn/format +description: Format resources in a directory. +tags: + - mutator + - formatter +sourceURL: https://github.com/GoogleContainerTools/kpt-functions-catalog/tree/master/functions/go/format +examplePackageURLs: + - https://github.com/GoogleContainerTools/kpt-functions-catalog/tree/master/examples/format/imperative +emails: + - kpt-team@google.com +license: Apache-2.0 diff --git a/functions/go/search-replace/README.md b/functions/go/search-replace/README.md index fccda8b7f..c27916365 100644 --- a/functions/go/search-replace/README.md +++ b/functions/go/search-replace/README.md @@ -66,13 +66,13 @@ data: The function can be invoked using: ``` -$ kpt fn run --image gcr.io/kpt-fn/apply-setters:unstable --fn-config /path/to/fn-config.yaml +$ kpt fn run --image gcr.io/kpt-fn/search-replace:unstable --fn-config /path/to/fn-config.yaml ``` Alternatively, data can be passed as key-value pairs in the CLI ``` -$ kpt fn run --image gcr.io/kpt-fn/apply-setters:unstable -- 'by-path=metadata.name' 'put-value=the-deployment' +$ kpt fn run --image gcr.io/kpt-fn/search-replace:unstable -- 'by-path=metadata.name' 'put-value=the-deployment' ``` Supported Path expressions: @@ -148,32 +148,32 @@ a: -```sh +```shell # Matches fields with value "3": $ kpt fn run --image gcr.io/kpt-fn/search-replace:unstable -- by-value=3 ``` -```sh +```shell # Matches fields with value prefixed by "nginx-": $ kpt fn run --image gcr.io/kpt-fn/search-replace:unstable -- by-value-regex='ngnix-.*' ``` -```sh +```shell # Matches field with path "spec.namespaces" set to "bookstore": $ kpt fn run --image gcr.io/kpt-fn/search-replace:unstable -- by-path='metadata.namespace' by-value='bookstore' ``` -```sh +```shell # Matches fields with name "containerPort" arbitrarily deep in "spec" that have value of 80: $ kpt fn run --image gcr.io/kpt-fn/search-replace:unstable -- by-path='spec.**.containerPort' by-value=80 ``` -```sh +```shell # Set namespaces for all resources to "bookstore", even namespace is not set on a resource: $ kpt fn run --image gcr.io/kpt-fn/search-replace:unstable -- by-path='metadata.namespace' put-value='bookstore' ``` -```sh +```shell # Search and Set multiple values using regex numbered capture groups $ kpt fn run --image gcr.io/kpt-fn/search-replace:unstable -- by-value-regex='something-(.*)' put-value='my-project-id-${1}' metadata: @@ -185,7 +185,7 @@ metadata: namespace: my-project-id-bar ``` -```sh +```shell # Put the setter pattern as a line comment for matching fields. $ kpt fn run --image gcr.io/kpt-fn/search-replace:unstable -- by-value='my-project-id-foo' put-comment='kpt-set: ${project-id}-foo' metadata: diff --git a/functions/go/search-replace/generated/docs.go b/functions/go/search-replace/generated/docs.go index f4953af6c..a105dbf91 100644 --- a/functions/go/search-replace/generated/docs.go +++ b/functions/go/search-replace/generated/docs.go @@ -1,3 +1,5 @@ + + // Code generated by "mdtogo"; DO NOT EDIT. package generated @@ -49,11 +51,11 @@ provided as key-value pairs using ` + "`" + `data` + "`" + ` field. The function can be invoked using: - $ kpt fn run --image gcr.io/kpt-fn/apply-setters:unstable --fn-config /path/to/fn-config.yaml + $ kpt fn run --image gcr.io/kpt-fn/search-replace:unstable --fn-config /path/to/fn-config.yaml Alternatively, data can be passed as key-value pairs in the CLI - $ kpt fn run --image gcr.io/kpt-fn/apply-setters:unstable -- 'by-path=metadata.name' 'put-value=the-deployment' + $ kpt fn run --image gcr.io/kpt-fn/search-replace:unstable -- 'by-path=metadata.name' 'put-value=the-deployment' Supported Path expressions: diff --git a/functions/go/search-replace/go.mod b/functions/go/search-replace/go.mod index a45ed0057..c4443217e 100644 --- a/functions/go/search-replace/go.mod +++ b/functions/go/search-replace/go.mod @@ -5,5 +5,5 @@ go 1.15 require ( github.com/stretchr/testify v1.6.1 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect - sigs.k8s.io/kustomize/kyaml v0.10.10 + sigs.k8s.io/kustomize/kyaml v0.10.20 ) diff --git a/functions/go/search-replace/main.go b/functions/go/search-replace/main.go index 258a6ab57..44c3014d6 100644 --- a/functions/go/search-replace/main.go +++ b/functions/go/search-replace/main.go @@ -5,39 +5,46 @@ import ( "os" "github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/search-replace/generated" + "github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/search-replace/searchreplace" "sigs.k8s.io/kustomize/kyaml/fn/framework" + "sigs.k8s.io/kustomize/kyaml/fn/framework/command" kyaml "sigs.k8s.io/kustomize/kyaml/yaml" ) //nolint func main() { resourceList := &framework.ResourceList{} - resourceList.FunctionConfig = map[string]interface{}{} - cmd := framework.Command(resourceList, func() error { - resourceList.Result = &framework.Result{ - Name: "search-replace", - } - items, err := run(resourceList) - if err != nil { - resourceList.Result.Items = getErrorItem(err.Error()) - return resourceList.Result - } - resourceList.Result.Items = items - return nil - }) + resourceList.FunctionConfig = &kyaml.RNode{} + srp := SearchReplaceProcessor{} + cmd := command.Build(&srp, command.StandaloneEnabled, false) cmd.Short = generated.SearchReplaceShort cmd.Long = generated.SearchReplaceLong cmd.Example = generated.SearchReplaceExamples if err := cmd.Execute(); err != nil { - fmt.Println(err) + fmt.Fprintln(os.Stderr, err) os.Exit(1) } } -// run resolves the function params and runs the function on resources -func run(resourceList *framework.ResourceList) ([]framework.Item, error) { +type SearchReplaceProcessor struct{} + +func (srp *SearchReplaceProcessor) Process(resourceList *framework.ResourceList) error { + resourceList.Result = &framework.Result{ + Name: "search-replace", + } + items, err := run(resourceList) + if err != nil { + resourceList.Result.Items = getErrorItem(err.Error()) + return err + } + resourceList.Result.Items = items + return nil +} + +// run resolves the function params from input ResourceList and runs the function on resources +func run(resourceList *framework.ResourceList) ([]framework.ResultItem, error) { sr, err := getSearchReplaceParams(resourceList.FunctionConfig) if err != nil { return nil, err @@ -52,46 +59,25 @@ func run(resourceList *framework.ResourceList) ([]framework.Item, error) { } // getSearchReplaceParams retrieve the search parameters from input config -func getSearchReplaceParams(fc interface{}) (SearchReplace, error) { - var fcd SearchReplace - f, ok := fc.(map[string]interface{}) - if !ok { - return fcd, fmt.Errorf("function config %#v is not valid", fc) - } - rn, err := kyaml.FromMap(f) - if err != nil { - return fcd, fmt.Errorf("failed to parse input from function config: %w", err) +func getSearchReplaceParams(fc *kyaml.RNode) (searchreplace.SearchReplace, error) { + var fcd searchreplace.SearchReplace + if err := searchreplace.Decode(fc, &fcd); err != nil { + return fcd, err } - - decode(rn, &fcd) return fcd, nil } -// decode decodes the input yaml node into SearchReplace struct -func decode(rn *kyaml.RNode, fcd *SearchReplace) { - dm := rn.GetDataMap() - fcd.ByPath = getValue(dm, "by-path") - fcd.ByValue = getValue(dm, "by-value") - fcd.ByValueRegex = getValue(dm, "by-value-regex") - fcd.PutValue = getValue(dm, "put-value") - fcd.PutComment = getValue(dm, "put-comment") -} - -// getValue returns the value for 'key' in map 'm' -// returns empty string if 'key' doesn't exist in 'm' -func getValue(m map[string]string, key string) string { - if val, ok := m[key]; ok { - return val - } - return "" -} - // searchResultsToItems converts the Search and Replace results to // equivalent items([]framework.Item) -func searchResultsToItems(sr SearchReplace) []framework.Item { - var items []framework.Item +func searchResultsToItems(sr searchreplace.SearchReplace) []framework.ResultItem { + var items []framework.ResultItem + if len(sr.Results) == 0 { + items = append(items, framework.ResultItem{ + Message: "no matches", + }) + return items + } for _, res := range sr.Results { - var message string if sr.PutComment != "" || sr.PutValue != "" { message = fmt.Sprintf("Mutated field value to %q", res.Value) @@ -99,7 +85,7 @@ func searchResultsToItems(sr SearchReplace) []framework.Item { message = fmt.Sprintf("Matched field value %q", res.Value) } - items = append(items, framework.Item{ + items = append(items, framework.ResultItem{ Message: message, Field: framework.Field{Path: res.FieldPath}, File: framework.File{Path: res.FilePath}, @@ -109,8 +95,8 @@ func searchResultsToItems(sr SearchReplace) []framework.Item { } // getErrorItem returns the item for input error message -func getErrorItem(errMsg string) []framework.Item { - return []framework.Item{ +func getErrorItem(errMsg string) []framework.ResultItem { + return []framework.ResultItem{ { Message: fmt.Sprintf("failed to perform search-replace operation: %q", errMsg), Severity: framework.Error, diff --git a/functions/go/search-replace/metadata.yaml b/functions/go/search-replace/metadata.yaml index 24dad352f..d8a97d4fd 100644 --- a/functions/go/search-replace/metadata.yaml +++ b/functions/go/search-replace/metadata.yaml @@ -5,6 +5,7 @@ tags: sourceURL: https://github.com/GoogleContainerTools/kpt-functions-catalog/tree/master/functions/go/search-replace examplePackageURLs: - https://github.com/GoogleContainerTools/kpt-functions-catalog/tree/master/examples/search-replace/simple + - https://github.com/GoogleContainerTools/kpt-functions-catalog/tree/master/examples/search-replace/create-setters emails: - kpt-team@google.com license: Apache-2.0 diff --git a/functions/go/search-replace/pathparser.go b/functions/go/search-replace/searchreplace/pathparser.go similarity index 99% rename from functions/go/search-replace/pathparser.go rename to functions/go/search-replace/searchreplace/pathparser.go index 64f4f9968..f7f571d6c 100644 --- a/functions/go/search-replace/pathparser.go +++ b/functions/go/search-replace/searchreplace/pathparser.go @@ -1,4 +1,4 @@ -package main +package searchreplace import ( "strings" diff --git a/functions/go/search-replace/pathparser_test.go b/functions/go/search-replace/searchreplace/pathparser_test.go similarity index 98% rename from functions/go/search-replace/pathparser_test.go rename to functions/go/search-replace/searchreplace/pathparser_test.go index 414fe315d..3f77edaeb 100644 --- a/functions/go/search-replace/pathparser_test.go +++ b/functions/go/search-replace/searchreplace/pathparser_test.go @@ -1,4 +1,4 @@ -package main +package searchreplace import ( "testing" diff --git a/functions/go/search-replace/putcommentcases_test.go b/functions/go/search-replace/searchreplace/putcommentcases_test.go similarity index 99% rename from functions/go/search-replace/putcommentcases_test.go rename to functions/go/search-replace/searchreplace/putcommentcases_test.go index e1327e573..0d243a9d8 100644 --- a/functions/go/search-replace/putcommentcases_test.go +++ b/functions/go/search-replace/searchreplace/putcommentcases_test.go @@ -1,4 +1,4 @@ -package main +package searchreplace var putPatternCases = []test{ { diff --git a/functions/go/search-replace/search_replace.go b/functions/go/search-replace/searchreplace/search_replace.go similarity index 84% rename from functions/go/search-replace/search_replace.go rename to functions/go/search-replace/searchreplace/search_replace.go index 507e1e1e8..97acd1901 100644 --- a/functions/go/search-replace/search_replace.go +++ b/functions/go/search-replace/searchreplace/search_replace.go @@ -1,4 +1,4 @@ -package main +package searchreplace import ( "fmt" @@ -7,10 +7,23 @@ import ( "sigs.k8s.io/kustomize/kyaml/errors" "sigs.k8s.io/kustomize/kyaml/kio/kioutil" + "sigs.k8s.io/kustomize/kyaml/sets" "sigs.k8s.io/kustomize/kyaml/yaml" ) -const PathDelimiter = "." +const ( + ByValue = "by-value" + ByValueRegex = "by-value-regex" + ByPath = "by-path" + PutValue = "put-value" + PutComment = "put-comment" + PathDelimiter = "." +) + +// matchers returns the list of supported matchers +func matchers() []string { + return []string{ByValue, ByValueRegex, ByPath, PutValue, PutComment} +} // SearchReplace struct holds the input parameters and results for // Search and Replace operations on resource configs @@ -46,20 +59,20 @@ type SearchReplace struct { // SearchResult holds result of search and replace operation type SearchResult struct { - // file path of the matching field + // FilePath is the file path of the matching field FilePath string - // field path of the matching field + // FieldPath is field path of the matching field FieldPath string - // value of the matching field + // Value of the matching field Value string } // Filter performs the search and replace operation on all input nodes func (sr *SearchReplace) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) { - if sr.ByValue != "" && sr.ByValueRegex != "" { - return nodes, errors.Errorf(`only one of ["by-value", "by-value-regex"] can be provided`) + if err := sr.validateMatchers(); err != nil { + return nodes, err } // compile regex once so that it can be used everywhere @@ -89,6 +102,9 @@ func (sr *SearchReplace) Perform(object *yaml.RNode) (*yaml.RNode, error) { return object, err } sr.filePath = filePath + if err != nil { + return object, err + } // check if value should be put by path and process it directly without needing // to traverse all elements of the node @@ -346,3 +362,42 @@ func (sr *SearchReplace) resultsString() string { out += fmt.Sprintf("%s %d field(s)\n", action, sr.Count) return out } + +// Decode decodes the input yaml RNode into SearchReplace struct +// returns error if input yaml RNode contains invalid matcher name inputs +func Decode(rn *yaml.RNode, fcd *SearchReplace) error { + dm := rn.GetDataMap() + if err := validateMatcherNames(dm); err != nil { + return err + } + fcd.ByPath = dm[ByPath] + fcd.ByValue = dm[ByValue] + fcd.ByValueRegex = dm[ByValueRegex] + fcd.PutValue = dm[PutValue] + fcd.PutComment = dm[PutComment] + return nil +} + +// validateMatcherNames validates the input matcher names +func validateMatcherNames(m map[string]string) error { + matcherSet := sets.String{} + matcherSet.Insert(matchers()...) + for key := range m { + if !matcherSet.Has(key) { + return errors.Errorf("invalid matcher %q, must be one of %q", key, matchers()) + } + } + return nil +} + +// validateMatchers validates the input matchers in SearchReplace struct +func (sr *SearchReplace) validateMatchers() error { + if sr.ByValue == "" && sr.ByValueRegex == "" && sr.ByPath == "" { + return errors.Errorf(`at least one of [%q, %q, %q] must be provided`, ByValue, ByValueRegex, ByPath) + } + + if sr.ByValue != "" && sr.ByValueRegex != "" { + return errors.Errorf(`only one of [%q, %q] can be provided`, ByValue, ByValueRegex) + } + return nil +} diff --git a/functions/go/search-replace/search_replace_test.go b/functions/go/search-replace/searchreplace/search_replace_test.go similarity index 79% rename from functions/go/search-replace/search_replace_test.go rename to functions/go/search-replace/searchreplace/search_replace_test.go index 896b36173..b79233f97 100644 --- a/functions/go/search-replace/search_replace_test.go +++ b/functions/go/search-replace/searchreplace/search_replace_test.go @@ -1,4 +1,4 @@ -package main +package searchreplace import ( "io/ioutil" @@ -47,12 +47,15 @@ func TestSearchCommand(t *testing.T) { if !assert.NoError(t, err) { t.FailNow() } - decode(node, s) inout := &kio.LocalPackageReadWriter{ PackagePath: baseDir, NoDeleteFiles: true, PackageFileName: "Kptfile", } + err = Decode(node, s) + if !assert.NoError(t, err) { + t.FailNow() + } err = kio.Pipeline{ Inputs: []kio.Reader{inout}, Filters: []kio.Filter{s}, @@ -90,3 +93,22 @@ func TestSearchCommand(t *testing.T) { } } } + +func TestDecode(t *testing.T) { + rn, err := kyaml.Parse(`data: + by-value: foo + put-values: bar`) + if !assert.NoError(t, err) { + t.FailNow() + } + + err = Decode(rn, &SearchReplace{}) + if !assert.Error(t, err) { + t.FailNow() + } + expected := `invalid matcher "put-values", must be one of ["by-value" "by-value-regex" "by-path" "put-value" "put-comment"]` + if !assert.Equal(t, expected, err.Error()) { + t.FailNow() + } + +} diff --git a/functions/go/search-replace/searchreplacecases_test.go b/functions/go/search-replace/searchreplace/searchreplacecases_test.go similarity index 92% rename from functions/go/search-replace/searchreplacecases_test.go rename to functions/go/search-replace/searchreplace/searchreplacecases_test.go index 10a76ccff..06e67e179 100644 --- a/functions/go/search-replace/searchreplacecases_test.go +++ b/functions/go/search-replace/searchreplace/searchreplacecases_test.go @@ -1,4 +1,4 @@ -package main +package searchreplace var searchReplaceCases = []test{ { @@ -727,4 +727,51 @@ spec: `, errMsg: `only one of ["by-value", "by-value-regex"] can be provided`, }, + { + name: "error when none of the search matchers are provided", + config: ` +data: ~ +`, + input: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment +spec: + replicas: 3 + `, + expectedResources: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment +spec: + replicas: 3 + `, + errMsg: `at least one of ["by-value", "by-value-regex", "by-path"] must be provided`, + }, + { + name: "error when none of the required search matchers are provided", + config: ` +data: + put-value: foo +`, + input: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment +spec: + replicas: 3 + `, + expectedResources: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment +spec: + replicas: 3 + `, + errMsg: `at least one of ["by-value", "by-value-regex", "by-path"] must be provided`, + }, } diff --git a/functions/go/search-replace/searchreplace/walk.go b/functions/go/search-replace/searchreplace/walk.go new file mode 100644 index 000000000..36ca163f1 --- /dev/null +++ b/functions/go/search-replace/searchreplace/walk.go @@ -0,0 +1,69 @@ +package searchreplace + +import ( + "fmt" + + "sigs.k8s.io/kustomize/kyaml/errors" + "sigs.k8s.io/kustomize/kyaml/yaml" +) + +// visitor is implemented by structs which need to walk the configuration. +// visitor is provided to accept to walk configuration +type visitor interface { + // visitScalar is called for each scalar field value on a resource + // node is the scalar field value + // path is the path to the field; path elements are separated by '.' + visitScalar(node *yaml.RNode, path string) error + + // visitMapping is called for each Mapping field value on a resource + // node is the mapping field value + // path is the path to the field + visitMapping(node *yaml.RNode, path string) error +} + +// accept invokes the appropriate function on v for each field in object +func accept(v visitor, object *yaml.RNode) error { + // get the OpenAPI for the type if it exists + return acceptImpl(v, object, "") +} + +// acceptImpl implements accept using recursion +func acceptImpl(v visitor, object *yaml.RNode, p string) error { + switch object.YNode().Kind { + case yaml.DocumentNode: + // Traverse the child of the document + return accept(v, yaml.NewRNode(object.YNode())) + case yaml.MappingNode: + if err := v.visitMapping(object, p); err != nil { + return err + } + return object.VisitFields(func(node *yaml.MapNode) error { + // Traverse each field value + return acceptImpl(v, node.Value, p+"."+node.Key.YNode().Value) + }) + case yaml.SequenceNode: + return VisitElements(object, func(node *yaml.RNode, i int) error { + // Traverse each list element + return acceptImpl(v, node, p+fmt.Sprintf("[%d]", i)) + }) + case yaml.ScalarNode: + // Visit the scalar field + return v.visitScalar(object, p) + } + return nil +} + +// VisitElements calls fn for each element in a SequenceNode. +// Returns an error for non-SequenceNodes +func VisitElements(rn *yaml.RNode, fn func(node *yaml.RNode, i int) error) error { + elements, err := rn.Elements() + if err != nil { + return errors.Wrap(err) + } + for i := range elements { + if err := fn(elements[i], i); err != nil { + return errors.Wrap(err) + } + } + return nil +} diff --git a/functions/go/set-annotations/generated/docs.go b/functions/go/set-annotations/generated/docs.go index 6e55acbb1..e9fd9675f 100644 --- a/functions/go/set-annotations/generated/docs.go +++ b/functions/go/set-annotations/generated/docs.go @@ -1,8 +1,10 @@ + + // Code generated by "mdtogo"; DO NOT EDIT. package generated -var SetAnnotationShort = `Add a list of annotations to all resources.` -var SetAnnotationLong = ` +var SetAnnotationsShort = `Add a list of annotations to all resources.` +var SetAnnotationsLong = ` Configured using a ConfigMap with key-value pairs in ` + "`" + `data` + "`" + ` field in ` + "`" + `ConfigMap` + "`" + ` resource. @@ -65,6 +67,6 @@ Field spec has following fields: For more information about fieldSpecs, please see https://kubectl.docs.kubernetes.io/guides/extending_kustomize/builtins/#arguments-3 ` -var SetAnnotationExamples = ` +var SetAnnotationsExamples = ` https://github.com/GoogleContainerTools/kpt-functions-catalog/tree/master/examples/set-annotations/ ` diff --git a/functions/go/set-annotations/main.go b/functions/go/set-annotations/main.go index 070684dff..2ae41e26e 100644 --- a/functions/go/set-annotations/main.go +++ b/functions/go/set-annotations/main.go @@ -130,9 +130,9 @@ func main() { return nil }) - cmd.Short = generated.SetAnnotationShort - cmd.Long = generated.SetAnnotationLong - cmd.Example = generated.SetAnnotationExamples + cmd.Short = generated.SetAnnotationsShort + cmd.Long = generated.SetAnnotationsLong + cmd.Example = generated.SetAnnotationsExamples if err := cmd.Execute(); err != nil { os.Exit(1) } diff --git a/functions/go/set-labels/generated/docs.go b/functions/go/set-labels/generated/docs.go index 36fa9e2f9..83b9a7be0 100644 --- a/functions/go/set-labels/generated/docs.go +++ b/functions/go/set-labels/generated/docs.go @@ -1,8 +1,10 @@ + + // Code generated by "mdtogo"; DO NOT EDIT. package generated -var SetLabelShort = `Add a list of labels to all resources.` -var SetLabelLong = ` +var SetLabelsShort = `Add a list of labels to all resources.` +var SetLabelsLong = ` Configured using a ConfigMap with key-value pairs in ` + "`" + `data` + "`" + ` field in ` + "`" + `ConfigMap` + "`" + ` resource. @@ -66,6 +68,6 @@ Field spec has following fields: For more information about fieldSpecs, please see https://kubectl.docs.kubernetes.io/guides/extending_kustomize/builtins/#arguments-3 ` -var SetLabelExamples = ` +var SetLabelsExamples = ` https://github.com/GoogleContainerTools/kpt-functions-catalog/tree/master/examples/set-labels/ ` diff --git a/functions/go/set-labels/go.mod b/functions/go/set-labels/go.mod index 087f9fb8d..ac43eb24b 100644 --- a/functions/go/set-labels/go.mod +++ b/functions/go/set-labels/go.mod @@ -5,6 +5,6 @@ go 1.15 require ( gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect sigs.k8s.io/kustomize/api v0.7.1 - sigs.k8s.io/kustomize/kyaml v0.10.5 + sigs.k8s.io/kustomize/kyaml v0.10.20 sigs.k8s.io/yaml v1.2.0 ) diff --git a/functions/go/set-labels/main.go b/functions/go/set-labels/main.go index 4d9fa7811..40666ea47 100644 --- a/functions/go/set-labels/main.go +++ b/functions/go/set-labels/main.go @@ -4,16 +4,16 @@ import ( "fmt" "os" + "github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/set-labels/generated" "sigs.k8s.io/kustomize/api/k8sdeps/kunstruct" "sigs.k8s.io/kustomize/api/konfig/builtinpluginconsts" "sigs.k8s.io/kustomize/api/resmap" "sigs.k8s.io/kustomize/api/resource" "sigs.k8s.io/kustomize/api/types" "sigs.k8s.io/kustomize/kyaml/fn/framework" + "sigs.k8s.io/kustomize/kyaml/fn/framework/command" kyaml "sigs.k8s.io/kustomize/kyaml/yaml" "sigs.k8s.io/yaml" - - "github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/set-labels/generated" ) const ( @@ -23,6 +23,40 @@ const ( fnConfigKind = "SetLabelConfig" ) +//nolint +func main() { + resourceList := &framework.ResourceList{} + resourceList.FunctionConfig = &kyaml.RNode{} + asp := SetLabelsProcessor{} + cmd := command.Build(&asp, command.StandaloneEnabled, false) + + cmd.Short = generated.SetLabelsShort + cmd.Long = generated.SetLabelsLong + cmd.Example = generated.SetLabelsExamples + if err := cmd.Execute(); err != nil { + os.Exit(1) + } +} + +type SetLabelsProcessor struct{} + +func (slp *SetLabelsProcessor) Process(resourceList *framework.ResourceList) error { + err := run(resourceList) + if err != nil { + resourceList.Result = &framework.Result{ + Name: "set-labels", + Items: []framework.ResultItem{ + { + Message: err.Error(), + Severity: framework.Error, + }, + }, + } + return resourceList.Result + } + return nil +} + type transformerConfig struct { FieldSpecs types.FsSlice `json:"commonLabels,omitempty" yaml:"commonLabels,omitempty"` } @@ -32,15 +66,7 @@ type setLabelFunction struct { plugin `json:",inline" yaml:",inline"` } -func (f *setLabelFunction) Config(fnConfig interface{}) error { - configMap, ok := fnConfig.(map[string]interface{}) - if !ok { - return fmt.Errorf("function config %#v is not valid", fnConfig) - } - rn, err := kyaml.FromMap(configMap) - if err != nil { - return fmt.Errorf("failed to construct RNode from %#v: %w", configMap, err) - } +func (f *setLabelFunction) Config(rn *kyaml.RNode) error { switch { case f.validGVK(rn, "v1", "ConfigMap"): f.plugin.Labels = rn.GetDataMap() @@ -106,36 +132,6 @@ func newResMapFactory() *resmap.Factory { return resmap.NewFactory(resourceFactory, nil) } -//nolint -func main() { - resourceList := &framework.ResourceList{} - resourceList.FunctionConfig = map[string]interface{}{} - - cmd := framework.Command(resourceList, func() error { - err := run(resourceList) - if err != nil { - resourceList.Result = &framework.Result{ - Name: "set-labels", - Items: []framework.Item{ - { - Message: err.Error(), - Severity: framework.Error, - }, - }, - } - return resourceList.Result - } - return nil - }) - - cmd.Short = generated.SetLabelShort - cmd.Long = generated.SetLabelLong - cmd.Example = generated.SetLabelExamples - if err := cmd.Execute(); err != nil { - os.Exit(1) - } -} - func run(resourceList *framework.ResourceList) error { var fn setLabelFunction err := fn.Config(resourceList.FunctionConfig) diff --git a/functions/go/set-namespace/generated/docs.go b/functions/go/set-namespace/generated/docs.go index b09c2832f..2891a7e69 100644 --- a/functions/go/set-namespace/generated/docs.go +++ b/functions/go/set-namespace/generated/docs.go @@ -1,3 +1,5 @@ + + // Code generated by "mdtogo"; DO NOT EDIT. package generated diff --git a/functions/go/set-namespace/go.mod b/functions/go/set-namespace/go.mod index 9339b80c6..f314a64cc 100644 --- a/functions/go/set-namespace/go.mod +++ b/functions/go/set-namespace/go.mod @@ -5,6 +5,6 @@ go 1.15 require ( gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect sigs.k8s.io/kustomize/api v0.7.1 - sigs.k8s.io/kustomize/kyaml v0.10.5 + sigs.k8s.io/kustomize/kyaml v0.10.20 sigs.k8s.io/yaml v1.2.0 ) diff --git a/functions/go/set-namespace/main.go b/functions/go/set-namespace/main.go index 51335ff57..a047a97d5 100644 --- a/functions/go/set-namespace/main.go +++ b/functions/go/set-namespace/main.go @@ -4,16 +4,16 @@ import ( "fmt" "os" + "github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/set-namespace/generated" "sigs.k8s.io/kustomize/api/k8sdeps/kunstruct" "sigs.k8s.io/kustomize/api/konfig/builtinpluginconsts" "sigs.k8s.io/kustomize/api/resmap" "sigs.k8s.io/kustomize/api/resource" "sigs.k8s.io/kustomize/api/types" "sigs.k8s.io/kustomize/kyaml/fn/framework" + "sigs.k8s.io/kustomize/kyaml/fn/framework/command" kyaml "sigs.k8s.io/kustomize/kyaml/yaml" "sigs.k8s.io/yaml" - - "github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/set-namespace/generated" ) const ( @@ -23,6 +23,40 @@ const ( fnConfigKind = "SetNamespaceConfig" ) +//nolint +func main() { + resourceList := &framework.ResourceList{} + resourceList.FunctionConfig = &kyaml.RNode{} + asp := SetNamespaceProcessor{} + cmd := command.Build(&asp, command.StandaloneEnabled, false) + + cmd.Short = generated.SetNamespaceShort + cmd.Long = generated.SetNamespaceLong + cmd.Example = generated.SetNamespaceExamples + if err := cmd.Execute(); err != nil { + os.Exit(1) + } +} + +type SetNamespaceProcessor struct{} + +func (snp *SetNamespaceProcessor) Process(resourceList *framework.ResourceList) error { + err := run(resourceList) + if err != nil { + resourceList.Result = &framework.Result{ + Name: "set-namespace", + Items: []framework.ResultItem{ + { + Message: err.Error(), + Severity: framework.Error, + }, + }, + } + return resourceList.Result + } + return nil +} + type transformerConfig struct { FieldSpecs types.FsSlice `json:"namespace,omitempty" yaml:"namespace,omitempty"` } @@ -32,15 +66,7 @@ type setNamespaceFunction struct { plugin `json:",inline" yaml:",inline"` } -func (f *setNamespaceFunction) Config(fnConfig interface{}) error { - configMap, ok := fnConfig.(map[string]interface{}) - if !ok { - return fmt.Errorf("function config %#v is not valid", fnConfig) - } - rn, err := kyaml.FromMap(configMap) - if err != nil { - return fmt.Errorf("failed to construct RNode from %#v: %w", configMap, err) - } +func (f *setNamespaceFunction) Config(rn *kyaml.RNode) error { switch { case f.validGVK(rn, "v1", "ConfigMap"): f.plugin.Namespace = rn.GetDataMap()["namespace"] @@ -108,35 +134,6 @@ func newResMapFactory() *resmap.Factory { return resmap.NewFactory(resourceFactory, nil) } -//nolint -func main() { - resourceList := &framework.ResourceList{} - resourceList.FunctionConfig = map[string]interface{}{} - - cmd := framework.Command(resourceList, func() error { - err := run(resourceList) - if err != nil { - resourceList.Result = &framework.Result{ - Name: "set-namespace", - Items: []framework.Item{ - { - Message: err.Error(), - Severity: framework.Error, - }, - }, - } - return resourceList.Result - } - return nil - }) - cmd.Short = generated.SetNamespaceShort - cmd.Long = generated.SetNamespaceLong - cmd.Example = generated.SetNamespaceExamples - if err := cmd.Execute(); err != nil { - os.Exit(1) - } -} - func run(resourceList *framework.ResourceList) error { var fn setNamespaceFunction err := fn.Config(resourceList.FunctionConfig) diff --git a/functions/go/starlark/generated/docs.go b/functions/go/starlark/generated/docs.go index ba7176cf6..8c7166441 100644 --- a/functions/go/starlark/generated/docs.go +++ b/functions/go/starlark/generated/docs.go @@ -1,3 +1,5 @@ + + // Code generated by "mdtogo"; DO NOT EDIT. package generated diff --git a/functions/go/upsert-resource/Dockerfile b/functions/go/upsert-resource/Dockerfile new file mode 100644 index 000000000..4296cbdcd --- /dev/null +++ b/functions/go/upsert-resource/Dockerfile @@ -0,0 +1,15 @@ +FROM golang:1.15-alpine3.12 +ENV CGO_ENABLED=0 +WORKDIR /go/src/ + +COPY go.mod go.sum ./ +RUN go mod download + +COPY . . +RUN go build -o /usr/local/bin/function ./ + +############################################# + +FROM alpine:3.12 +COPY --from=0 /usr/local/bin/function /usr/local/bin/function +ENTRYPOINT ["function"] diff --git a/functions/go/upsert-resource/README.md b/functions/go/upsert-resource/README.md new file mode 100644 index 000000000..f3e7e578c --- /dev/null +++ b/functions/go/upsert-resource/README.md @@ -0,0 +1,128 @@ +# upsert-resource + +### Overview + + + +Upsert a resource to the input list of resources. + + + +### Synopsis + + + +Upsert is an operation that adds a resource(uniquely identified by Group, Kind, Name and Namespace) +if it does not already exist, or replaces it if it already exists in the input list of resources. +`upsert-resource` function offers a safe way to upsert a resource to the list of input resources. + + + +### Examples + + + +#### Replace an existing resource + +Let's start with the list of resources in a package: + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: myService + namespace: mySpace +spec: + selector: + app: foo +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeployment + namespace: mySpace +spec: + replicas: 3 +``` + +Resource to upsert: + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: myService + namespace: mySpace +spec: + selector: + app: bar +``` + +Invoking `upsert-resource` function replaces the resource with name `myService`: + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: myService + namespace: mySpace +spec: + selector: + app: bar +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeployment + namespace: mySpace +spec: + replicas: 3 +``` + +#### Add a new resource + +For the same input resource list above, pass the following resource to upsert. +Note that the name of the resource is `myService2`. + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: myService2 + namespace: mySpace +spec: + selector: + app: bar +``` + +Invoking `upsert-resource` function adds the input resource to the package. + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: myService + namespace: mySpace +spec: + selector: + app: foo +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeployment + namespace: mySpace +spec: + replicas: 3 +--- +apiVersion: v1 +kind: Service +metadata: + name: myService2 + namespace: mySpace +spec: + selector: + app: bar +``` + + diff --git a/functions/go/upsert-resource/generated/docs.go b/functions/go/upsert-resource/generated/docs.go new file mode 100644 index 000000000..a12de2864 --- /dev/null +++ b/functions/go/upsert-resource/generated/docs.go @@ -0,0 +1,105 @@ + + +// Code generated by "mdtogo"; DO NOT EDIT. +package generated + +var UpsertResourceShort = `Upsert a resource to the input list of resources.` +var UpsertResourceLong = ` +Upsert is an operation that adds a resource(uniquely identified by Group, Kind, Name and Namespace) +if it does not already exist, or replaces it if it already exists in the input list of resources. +` + "`" + `upsert-resource` + "`" + ` function offers a safe way to upsert a resource to the list of input resources. +` +var UpsertResourceExamples = ` +Replace an existing resource: + +Let's start with the list of resources in a package: + + apiVersion: v1 + kind: Service + metadata: + name: myService + namespace: mySpace + spec: + selector: + app: foo + --- + apiVersion: apps/v1 + kind: Deployment + metadata: + name: myDeployment + namespace: mySpace + spec: + replicas: 3 + +Resource to upsert: + + apiVersion: v1 + kind: Service + metadata: + name: myService + namespace: mySpace + spec: + selector: + app: bar + +Invoking ` + "`" + `upsert-resource` + "`" + ` function replaces the resource with name ` + "`" + `myService` + "`" + `: + + apiVersion: v1 + kind: Service + metadata: + name: myService + namespace: mySpace + spec: + selector: + app: bar + --- + apiVersion: apps/v1 + kind: Deployment + metadata: + name: myDeployment + namespace: mySpace + spec: + replicas: 3 + +Add a new resource: + +For the same input resource list above, pass the following resource to upsert. +Note that the name of the resource is ` + "`" + `myService2` + "`" + `. + + apiVersion: v1 + kind: Service + metadata: + name: myService2 + namespace: mySpace + spec: + selector: + app: bar + +Invoking ` + "`" + `upsert-resource` + "`" + ` function adds the input resource to the package. + + apiVersion: v1 + kind: Service + metadata: + name: myService + namespace: mySpace + spec: + selector: + app: foo + --- + apiVersion: apps/v1 + kind: Deployment + metadata: + name: myDeployment + namespace: mySpace + spec: + replicas: 3 + --- + apiVersion: v1 + kind: Service + metadata: + name: myService2 + namespace: mySpace + spec: + selector: + app: bar +` diff --git a/functions/go/upsert-resource/go.mod b/functions/go/upsert-resource/go.mod new file mode 100644 index 000000000..a879741c9 --- /dev/null +++ b/functions/go/upsert-resource/go.mod @@ -0,0 +1,9 @@ +module github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/upsert-resource + +go 1.15 + +require ( + github.com/stretchr/testify v1.6.1 + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + sigs.k8s.io/kustomize/kyaml v0.10.20 +) diff --git a/functions/go/upsert-resource/go.sum b/functions/go/upsert-resource/go.sum new file mode 100644 index 000000000..a7e2ad273 --- /dev/null +++ b/functions/go/upsert-resource/go.sum @@ -0,0 +1,267 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +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-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/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/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/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/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +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-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +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/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/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +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-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +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-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.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.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.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/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/spec v0.19.5 h1:Xm0Ao53uqnk9QE/LlYV5DEU09UAgpliA85QoT9LzqPw= +github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= +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/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= +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.8/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gobuffalo/here v0.6.0 h1:hYrd0a6gDmWxBM4TnrGw8mQg24iSVoIkHEk7FodQcBI= +github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM= +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/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +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/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/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/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/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/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +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/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/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/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +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/markbates/pkger v0.17.1 h1:/MKEtWqtc0mZvu9OinB9UzVN9iYCwLWuyUv4Bw+PCno= +github.com/markbates/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +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/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +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/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_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/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/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/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/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +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/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +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 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.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 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= +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.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +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/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI= +github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +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.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= +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-20180904163835-0709b304e793/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-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/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-20180826012351-8a410e7b638d/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-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-20190522155817-f3200d17e092/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-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/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/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-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +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-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-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-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/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-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-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-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +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/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/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +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-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +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.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +sigs.k8s.io/kustomize/kyaml v0.10.13 h1:edizZj6kVwFgE2Wy6cpzt+qacKmjgGoTBzNtAz6+Cl4= +sigs.k8s.io/kustomize/kyaml v0.10.13/go.mod h1:JX33L0fyBEfdkidfYQwF50t7UrjatnF+j0F9ikkhTWI= diff --git a/functions/go/upsert-resource/main.go b/functions/go/upsert-resource/main.go new file mode 100644 index 000000000..2eb8470e0 --- /dev/null +++ b/functions/go/upsert-resource/main.go @@ -0,0 +1,43 @@ +package main + +import ( + "fmt" + "os" + + "github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/upsert-resource/generated" + "github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/upsert-resource/upsertresource" + "sigs.k8s.io/kustomize/kyaml/fn/framework" + "sigs.k8s.io/kustomize/kyaml/fn/framework/command" + kyaml "sigs.k8s.io/kustomize/kyaml/yaml" +) + +//nolint +func main() { + resourceList := &framework.ResourceList{} + resourceList.FunctionConfig = &kyaml.RNode{} + asp := UpsertResourceProcessor{} + cmd := command.Build(&asp, command.StandaloneEnabled, false) + + cmd.Short = generated.UpsertResourceShort + cmd.Long = generated.UpsertResourceLong + cmd.Example = generated.UpsertResourceExamples + + if err := cmd.Execute(); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +type UpsertResourceProcessor struct{} + +func (urp *UpsertResourceProcessor) Process(resourceList *framework.ResourceList) error { + ur := &upsertresource.UpsertResource{ + Resource: resourceList.FunctionConfig, + } + var err error + resourceList.Items, err = ur.Filter(resourceList.Items) + if err != nil { + return fmt.Errorf("failed to upsert resource: %w", err) + } + return nil +} diff --git a/functions/go/upsert-resource/metadata.yaml b/functions/go/upsert-resource/metadata.yaml new file mode 100644 index 000000000..dfcb782e0 --- /dev/null +++ b/functions/go/upsert-resource/metadata.yaml @@ -0,0 +1,10 @@ +image: gcr.io/kpt-fn/upsert-resource +description: Upsert a resource to the input list of resources. +tags: + - mutator +sourceURL: https://github.com/GoogleContainerTools/kpt-functions-catalog/tree/master/functions/go/upsert-resource +examplePackageURLs: + - https://github.com/GoogleContainerTools/kpt-functions-catalog/tree/master/examples/upsert-resource/simple +emails: + - kpt-team@google.com +license: Apache-2.0 diff --git a/functions/go/upsert-resource/upsertresource/upsert_resource.go b/functions/go/upsert-resource/upsertresource/upsert_resource.go new file mode 100644 index 000000000..7b64f6250 --- /dev/null +++ b/functions/go/upsert-resource/upsertresource/upsert_resource.go @@ -0,0 +1,150 @@ +package upsertresource + +import ( + "strings" + + "sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil" + "sigs.k8s.io/kustomize/kyaml/kio/filters" + "sigs.k8s.io/kustomize/kyaml/kio/kioutil" + "sigs.k8s.io/kustomize/kyaml/yaml" +) + +// UpsertResource upserts resource to input list of resources +// resources are uniquely identifies by Group, Kind, Name and Namespace +type UpsertResource struct { + // Resource is the input resource for upsert + Resource *yaml.RNode +} + +// Filter implements UpsertResource as a yaml.Filter +func (ur UpsertResource) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) { + replaced, err := ReplaceResource(nodes, ur.Resource) + if err != nil { + return nodes, err + } + if !replaced { + return AddResource(nodes, ur.Resource) + } + return nodes, nil +} + +// ReplaceResource checks if the inputResource matches with any of the resources in nodes list +// and replaces it with inputResource +// nodes are matched based on Group, Kind, Name and Namespace +func ReplaceResource(nodes []*yaml.RNode, inputResource *yaml.RNode) (bool, error) { + found := false + inputMeta, err := inputResource.GetMeta() + if err != nil { + return false, err + } + for i := range nodes { + rMeta, err := nodes[i].GetMeta() + if err != nil { + return false, err + } + // skip processing resource if it is a function config + // TODO: remove this check after we stop support for v0.X + if IsFunctionConfig(rMeta) { + continue + } + // check if there is a match and replace the resource + if IsSameResource(inputMeta, rMeta) { + nodes[i] = inputResource.Copy() + a := combineInputAndMatchedAnnotations(inputMeta.Annotations, rMeta.Annotations) + err = nodes[i].SetAnnotations(a) + if err != nil { + return false, err + } + // found a matching resource + // but continue to replace other instances of the resource + found = true + } + } + return found, nil +} + +// AddResource appends the inputResource to the list of input nodes +// it also cleans up the meta annotations so that resource is created in new file +// by the function orchestrator +func AddResource(nodes []*yaml.RNode, inputResource *yaml.RNode) ([]*yaml.RNode, error) { + new := inputResource.Copy() + meta, err := new.GetMeta() + if err != nil { + return nodes, err + } + // remove local, function, path and index annotations from the result + // removing path and index annotations makes orchestrator write resource + // to a new file + removeLocalFnPathIndexAnnotations(meta.Annotations) + err = new.SetAnnotations(meta.Annotations) + if err != nil { + return nodes, err + } + nodes = append(nodes, new) + return nodes, nil +} + +// IsSameResource returns true if metadata of two resources +// have same Group, Kind, Name, Namespace +// TODO: phanimarupaka move this to common util https://github.com/GoogleContainerTools/kpt/issues/2043 +func IsSameResource(meta1, meta2 yaml.ResourceMeta) bool { + g1, _ := ParseGroupVersion(meta1.APIVersion) + g2, _ := ParseGroupVersion(meta1.APIVersion) + return g1 == g2 && meta1.Kind == meta2.Kind && + meta1.Name == meta2.Name && + meta1.Namespace == meta2.Namespace +} + +// ParseGroupVersion parses a KRM metadata apiVersion field. +func ParseGroupVersion(apiVersion string) (group, version string) { + if i := strings.Index(apiVersion, "/"); i > -1 { + return apiVersion[:i], apiVersion[i+1:] + } + return "", apiVersion +} + +// combineInputAndMatchedAnnotations combines user provided non-meta annotations from inputResource, +// with path and index annotations from matched resource and returns the result +func combineInputAndMatchedAnnotations(inputResourceAnno, matchedResourceAnno map[string]string) map[string]string { + if inputResourceAnno == nil { + inputResourceAnno = make(map[string]string) + } + if matchedResourceAnno == nil { + matchedResourceAnno = make(map[string]string) + } + res := make(map[string]string) + // retain the annotations from the input resource in fn-config, + // these should be written to matched resource + for k, v := range inputResourceAnno { + res[k] = v + } + // retain the path and index annotation from matched resource to result + res[kioutil.PathAnnotation] = matchedResourceAnno[kioutil.PathAnnotation] + res[kioutil.IndexAnnotation] = matchedResourceAnno[kioutil.IndexAnnotation] + // remove local and function meta annotations from the result as they should + // not be written to output resource + removeLocalAndFnAnnotations(res) + return res +} + +// removeLocalFnPathIndexAnnotations removes index, path, local and fn annotations +func removeLocalFnPathIndexAnnotations(a map[string]string) { + removeLocalAndFnAnnotations(a) + delete(a, kioutil.PathAnnotation) + delete(a, kioutil.IndexAnnotation) +} + +// removeLocalAndFnAnnotations removes local and fn annotations +// TODO: phanimarupaka remove this method after we drop support for kpt 0.X +func removeLocalAndFnAnnotations(a map[string]string) { + delete(a, filters.LocalConfigAnnotation) + delete(a, runtimeutil.FunctionAnnotationKey) + // using hard coded key as this annotation is deprecated and not exposed by kyaml + delete(a, "config.k8s.io/function") +} + +// IsFunctionConfig returns true if input resource meta has function config annotation +func IsFunctionConfig(rMeta yaml.ResourceMeta) bool { + return rMeta.Annotations != nil && + (rMeta.Annotations[runtimeutil.FunctionAnnotationKey] != "" || rMeta.Annotations["config.k8s.io/function"] != "") +} diff --git a/functions/go/upsert-resource/upsertresource/upsert_resource_test.go b/functions/go/upsert-resource/upsertresource/upsert_resource_test.go new file mode 100644 index 000000000..1f4d6234b --- /dev/null +++ b/functions/go/upsert-resource/upsertresource/upsert_resource_test.go @@ -0,0 +1,358 @@ +package upsertresource + +import ( + "bytes" + "io/ioutil" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + "sigs.k8s.io/kustomize/kyaml/kio" + kyaml "sigs.k8s.io/kustomize/kyaml/yaml" +) + +func TestUpsertResourceFilter(t *testing.T) { + var tests = []struct { + name string + fnconfig string + input string + expectedResources string + errMsg string + }{ + { + name: "replace a resource", + input: `apiVersion: v1 +kind: Service +metadata: + name: myService + annotations: + foo: bar +spec: + selector: + app: MyApp + ports: + - protocol: TCP + port: 80 + targetPort: 9376 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeployment +spec: + replicas: 3 + template: + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 +`, + fnconfig: ` +apiVersion: v1 +kind: Service +metadata: + name: myService + annotations: + abc: def +spec: + selector: + app: MyApp + ports: + - protocol: UDP + port: 8080 + targetPort: 1234 +`, + expectedResources: `apiVersion: v1 +kind: Service +metadata: + name: myService + annotations: + abc: def + config.kubernetes.io/path: f1.yaml +spec: + selector: + app: MyApp + ports: + - protocol: UDP + port: 8080 + targetPort: 1234 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeployment + annotations: + config.kubernetes.io/path: 'f1.yaml' +spec: + replicas: 3 + template: + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 +`, + }, + { + name: "Add a resource", + input: `apiVersion: v1 +kind: Service +metadata: + name: myService +spec: + selector: + app: MyApp + ports: + - protocol: TCP + port: 80 + targetPort: 9376 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeployment +spec: + replicas: 3 + template: + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 +`, + fnconfig: ` +apiVersion: v1 +kind: Service +metadata: + name: myService2 +spec: + selector: + app: MyApp + ports: + - protocol: UDP + port: 8080 + targetPort: 1234 +`, + expectedResources: `apiVersion: v1 +kind: Service +metadata: + name: myService + annotations: + config.kubernetes.io/path: 'f1.yaml' +spec: + selector: + app: MyApp + ports: + - protocol: TCP + port: 80 + targetPort: 9376 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeployment + annotations: + config.kubernetes.io/path: 'f1.yaml' +spec: + replicas: 3 + template: + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 +--- +apiVersion: v1 +kind: Service +metadata: + name: myService2 +spec: + selector: + app: MyApp + ports: + - protocol: UDP + port: 8080 + targetPort: 1234 +`, + }, + } + for i := range tests { + test := tests[i] + t.Run(test.name, func(t *testing.T) { + baseDir, err := ioutil.TempDir("", "") + if !assert.NoError(t, err) { + t.FailNow() + } + defer os.RemoveAll(baseDir) + + err = ioutil.WriteFile(filepath.Join(baseDir, "f1.yaml"), []byte(test.input), 0700) + if !assert.NoError(t, err) { + t.FailNow() + } + + node, err := kyaml.Parse(test.fnconfig) + if !assert.NoError(t, err) { + t.FailNow() + } + s := &UpsertResource{Resource: node} + if !assert.NoError(t, err) { + t.FailNow() + } + in := &kio.LocalPackageReader{ + PackagePath: baseDir, + } + out := &bytes.Buffer{} + err = kio.Pipeline{ + Inputs: []kio.Reader{in}, + Filters: []kio.Filter{s}, + Outputs: []kio.Writer{kio.ByteWriter{Writer: out}}, + }.Execute() + if test.errMsg != "" { + if !assert.NotNil(t, err) { + t.FailNow() + } + if !assert.Contains(t, err.Error(), test.errMsg) { + t.FailNow() + } + } + + if test.errMsg == "" && !assert.NoError(t, err) { + t.FailNow() + } + + if !assert.Equal(t, + test.expectedResources, + out.String()) { + t.FailNow() + } + }) + } +} + +func TestIsSameResource(t *testing.T) { + var tests = []struct { + name string + resource1 string + resource2 string + expected bool + }{ + { + name: "same resource 1", + resource1: `apiVersion: v1 +kind: Service +metadata: + name: myService +`, + resource2: `apiVersion: v1 +kind: Service +metadata: + name: myService +`, + expected: true, + }, + { + name: "same resource 2", + resource1: `apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeployment +`, + resource2: `apiVersion: apps/v1alpha1 +kind: Deployment +metadata: + name: myDeployment +`, + expected: true, + }, + { + name: "not same resource: default and empty namespace", + resource1: `apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeployment +`, + resource2: `apiVersion: apps/v1alpha1 +kind: Deployment +metadata: + name: myDeployment + namespace: default +`, + expected: false, + }, + { + name: "not same resource: different kind", + resource1: `apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeployment +`, + resource2: `apiVersion: apps/v1 +kind: Service +metadata: + name: myDeployment +`, + expected: false, + }, + { + name: "not same resource: different namespace", + resource1: `apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeployment + namespace: foo +`, + resource2: `apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeployment + namespace: bar +`, + expected: false, + }, + { + name: "not same resource: different names", + resource1: `apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeployment1 + namespace: foo +`, + resource2: `apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeployment2 + namespace: foo +`, + expected: false, + }, + } + for i := range tests { + test := tests[i] + t.Run(test.name, func(t *testing.T) { + + node1, err := kyaml.Parse(test.resource1) + if !assert.NoError(t, err) { + t.FailNow() + } + node2, err := kyaml.Parse(test.resource2) + if !assert.NoError(t, err) { + t.FailNow() + } + meta1, err := node1.GetMeta() + if !assert.NoError(t, err) { + t.FailNow() + } + meta2, err := node2.GetMeta() + if !assert.NoError(t, err) { + t.FailNow() + } + assert.Equal(t, test.expected, IsSameResource(meta1, meta2)) + }) + } +} diff --git a/functions/ts/_template/README.md b/functions/ts/_template/README.md new file mode 100644 index 000000000..349650a8f --- /dev/null +++ b/functions/ts/_template/README.md @@ -0,0 +1,22 @@ +# some-function-name + +### Overview + +Explain what this function does in one or two sentences. + +### Synopsis + +Explain the function config and behavior for this function in detail. +For each field in the function config, specify: + - An example value + - Whether it is optional, and if so, the default value + +To decouple the function orchestrator (i.e. kpt) from the function, it's +recommended to not show the kpt CLI or custom resources like the Kptfile. + +### Examples + +Omit this ection if you are poviding complete example kpt packages which +are linked from the catalog site. + +Otherwise, provide inline examples in this section. diff --git a/functions/ts/kubeval/README.md b/functions/ts/kubeval/README.md index b9db035e0..ce19b9fd2 100644 --- a/functions/ts/kubeval/README.md +++ b/functions/ts/kubeval/README.md @@ -11,11 +11,11 @@ The function configuration must be a ConfigMap. The following keys can be used in the `data` field of the ConfigMap, and all of them are optional: -- `schema_location`: The base URL used to fetch the json schemas. The default +- `schema_location`: The base URI used to fetch the json schemas. The default is empty. This feature only works with imperative runs, since declarative runs allow neither network access nor volume mount. -- `additional_schema_locations`: List of secondary base URLs used to fetch the - json schemas. These URLs will be used if the URL specified by +- `additional_schema_locations`: List of secondary base URIs used to fetch the + json schemas. These URIs will be used if the URI specified by `schema_location` did not have the required schema. The default is empty. This feature only works with imperative runs. - `ignore_missing_schemas`: Skip validation for resources without a schema. The @@ -33,8 +33,8 @@ kind: ConfigMap metadata: name: my-func-config data: - schema_location: "https://kubernetesjsonschema.dev" - additional_schema_locations: "https://example.com,file:///abs/path/to/your/schema/directory" + schema_location: "file:///abs/path/to/your/schema/directory" + additional_schema_locations: "https://kubernetesjsonschema.dev,file:///abs/path/to/your/other/schema/directory" ignore_missing_schemas: "false" skip_kinds: "DaemonSet,MyCRD" strict: "true" diff --git a/functions/ts/kubeval/build/kubeval.Dockerfile b/functions/ts/kubeval/build/kubeval.Dockerfile index 7bd09171f..4f497c99c 100644 --- a/functions/ts/kubeval/build/kubeval.Dockerfile +++ b/functions/ts/kubeval/build/kubeval.Dockerfile @@ -42,6 +42,4 @@ COPY --from=builder /home/node/app /home/node/app COPY --from=builder /usr/local/bin /usr/local/bin COPY openapi.json /home/node/ -ENV LOG_TO_STDERR=true - ENTRYPOINT ["node", "/home/node/app/dist/kubeval_run.js"] diff --git a/functions/ts/kubeval/metadata.yaml b/functions/ts/kubeval/metadata.yaml index 186d570bb..eb3c258a0 100644 --- a/functions/ts/kubeval/metadata.yaml +++ b/functions/ts/kubeval/metadata.yaml @@ -2,9 +2,9 @@ image: gcr.io/kpt-fn/kubeval description: Validates configuration using kubeval. tags: - validator -sourceURL: https://github.com/GoogleContainerTools/kpt-functions-catalog/tree/master/functions/ts/kubeval +sourceURL: https://github.com/GoogleContainerTools/kpt-functions-catalog/tree/kubeval/v0.1/functions/ts/kubeval examplePackageURLs: - - https://github.com/GoogleContainerTools/kpt-functions-catalog/tree/master/examples/kubeval/simple + - https://github.com/GoogleContainerTools/kpt-functions-catalog/tree/kubeval/v0.1/examples/kubeval/simple emails: - kpt-team@google.com license: Apache-2.0 diff --git a/functions/ts/kubeval/package-lock.json b/functions/ts/kubeval/package-lock.json index 09c663bf0..24eccd74e 100644 --- a/functions/ts/kubeval/package-lock.json +++ b/functions/ts/kubeval/package-lock.json @@ -121,9 +121,9 @@ "dev": true }, "@types/node": { - "version": "14.14.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.21.tgz", - "integrity": "sha512-cHYfKsnwllYhjOzuC5q1VpguABBeecUp24yFluHpn/BQaVxB1CuQ1FSRZCzrPxrkIfWISXV2LbeoBthLWg0+0A==", + "version": "14.14.43", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.43.tgz", + "integrity": "sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ==", "dev": true }, "@types/request": { @@ -822,9 +822,9 @@ } }, "hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", - "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, "http-cache-semantics": { @@ -1108,9 +1108,9 @@ } }, "lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, "long": { @@ -1967,15 +1967,15 @@ "dev": true }, "typescript": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", - "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz", + "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==", "dev": true }, "underscore": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.0.tgz", - "integrity": "sha512-21rQzss/XPMjolTiIezSu3JAjgagXKROtNrYFEOWK109qY1Uv2tVjPTZ1ci2HgvQDA16gHYSthQIJfB+XId/rQ==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz", + "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==", "dev": true }, "universalify": { diff --git a/functions/ts/kubeval/package.json b/functions/ts/kubeval/package.json index 9fa315294..ae3577e07 100644 --- a/functions/ts/kubeval/package.json +++ b/functions/ts/kubeval/package.json @@ -26,7 +26,7 @@ }, "devDependencies": { "@types/jasmine": "^3.6.9", - "@types/node": "^14.14.16", + "@types/node": "^14.14.43", "create-kpt-functions": "^0.17.0", "jasmine": "^3.7.0", "license-checker": "^25.0.1", @@ -34,7 +34,7 @@ "tslint": "^6.1.3", "tslint-config-prettier": "1.18.0", "tslint-consistent-codestyle": "^1.16.0", - "typescript": "~4.2.3" + "typescript": "~4.2.4" }, "kpt": { "docker_repo_base": "gcr.io/kpt-fn" diff --git a/functions/ts/kubeval/src/kubeval.ts b/functions/ts/kubeval/src/kubeval.ts index c731f7f48..8dcd80ac0 100644 --- a/functions/ts/kubeval/src/kubeval.ts +++ b/functions/ts/kubeval/src/kubeval.ts @@ -130,6 +130,20 @@ async function runKubeval( await writeToStream(kubevalProcess.stdin, serializedObject); kubevalProcess.stdin.end(); const rawOutput = await readStdoutToString(kubevalProcess); + + if (rawOutput.includes('Failed initializing schema file')) { + results.push( + kubernetesObjectResult( + `Validating arbitrary CRDs is not supported yet. You can skip them by setting ${IGNORE_MISSING_SCHEMAS} or ${SKIP_KINDS} in the function config:\n` + + rawOutput, + object, + undefined, + 'error' + ) + ); + return; + } + try { const feedback = JSON.parse(rawOutput) as Feedback; @@ -174,7 +188,7 @@ function buildKubevalArgs( skipKinds: string[], strict: boolean ) { - const args = ['--output', 'json']; + const args = ['--quiet', '--output', 'json']; if (schemaLocation) { args.push('--schema-location'); @@ -232,11 +246,11 @@ The function configuration must be a ConfigMap. The following keys can be used in the data field of the ConfigMap, and all of them are optional: -${SCHEMA_LOCATION}: The base URL used to fetch the json schemas. The default is +${SCHEMA_LOCATION}: The base URI used to fetch the json schemas. The default is empty. This feature only works with imperative runs, since declarative runs allow neither network access nor volume mount. -${ADDITIONAL_SCHEMA_LOCATIONS}: List of secondary base URLs used to fetch the - json schemas. These URLs will be used if the URL specified by +${ADDITIONAL_SCHEMA_LOCATIONS}: List of secondary base URIs used to fetch the + json schemas. These URIs will be used if the URI specified by ${SCHEMA_LOCATION} did not have the required schema. The default is empty. This feature only works with imperative runs. ${IGNORE_MISSING_SCHEMAS}: Skip validation for resources without a schema. The @@ -253,8 +267,8 @@ kind: ConfigMap metadata: name: my-func-config data: - schema_location: "https://kubernetesjsonschema.dev" - additional_schema_locations: "https://example.com,file:///abs/path/to/your/schema/directory" + schema_location: "file:///abs/path/to/your/schema/directory" + additional_schema_locations: "https://kubernetesjsonschema.dev,file:///abs/path/to/your/other/schema/directory" ignore_missing_schemas: "false" skip_kinds: "DaemonSet,MyCRD" strict: "true" diff --git a/scripts/check-site.sh b/scripts/check-site.sh new file mode 100755 index 000000000..881cfe0ee --- /dev/null +++ b/scripts/check-site.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -euo pipefail + +cd site || exit +npm i +echo "Starting check." +# Find all potential entrypoint READMEs +# Convert them to valid URLs +# Check each link for Docsify 404s +find . -name README.md -printf "%P\n" | grep -v node_modules | sed "s/README.md//" \ + | sed "s/^/http:\/\/localhost:3001\//" \ + | xargs -I {} -n1 sh -c "! (npx href-checker {} --bad-content=\"404 - Not found\" --silent --no-off-site -c=15 | grep .) || exit 255" +echo "Success." \ No newline at end of file diff --git a/scripts/generate_catalog/generate_catalog.go b/scripts/generate_catalog/generate_catalog.go index 952b72aba..8316d6df7 100644 --- a/scripts/generate_catalog/generate_catalog.go +++ b/scripts/generate_catalog/generate_catalog.go @@ -58,7 +58,6 @@ func main() { } functions := getFunctions(branches, source, dest) - err = writeFunctionIndex(functions, source, dest) if err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) @@ -74,6 +73,7 @@ func main() { type function struct { FunctionName string + ImagePath string VersionToExamples map[string]map[string]example LatestVersion string Path string @@ -100,7 +100,6 @@ var ( // Match start of a version such as v1.9.1 branchSemverPrefix = regexp.MustCompile(`[-\w]*\/(v\d*\.\d*)`) functionDirPrefix = regexp.MustCompile(`.+/functions/`) - exampleDirPrefix = regexp.MustCompile(`.+/examples/`) ) func getBranches() ([]string, error) { @@ -133,29 +132,33 @@ func getFunctions(branches []string, source string, dest string) []function { relativeFuncPath, err := getRelativeFunctionPath(source, funcName) if err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) - os.Exit(1) + continue + } + + // Skip contributed functions. + if strings.Contains(relativeFuncPath, "contrib/") { + continue } // Functions with the hidden field enabled should not be processed. metadataPath := strings.TrimSpace(fmt.Sprintf("%v:%v", b, filepath.Join(relativeFuncPath, "metadata.yaml"))) md, err := getMetadata(metadataPath) if err != nil { - fmt.Fprintf(os.Stderr, "%v\n", err) + fmt.Fprintf(os.Stderr, "Error getting metadata for %q in %q: %v\n", funcName, b, err) os.Exit(1) } if md.Hidden { continue } - err = copyExamples(b, funcName, funcDest, versionDest) if err != nil { - fmt.Fprintf(os.Stderr, "%v\n", err) + fmt.Fprintf(os.Stderr, "Error getting examples for %q in %q: %v\n", funcName, b, err) os.Exit(1) } err = copyReadme(b, funcName, relativeFuncPath, versionDest) if err != nil { - fmt.Fprintf(os.Stderr, "%v\n", err) + fmt.Fprintf(os.Stderr, "Error getting README for %q in %q: %v\n", funcName, b, err) os.Exit(1) } @@ -188,7 +191,7 @@ func copyExamples(b string, funcName string, funcDest string, versionDest string } // Copy examples for the function's version to a temporary directory. - tempDir, err := os.MkdirTemp("", "examples") + tempDir, err := ioutil.TempDir("", "examples") if err != nil { return err } @@ -209,14 +212,14 @@ func copyExamples(b string, funcName string, funcDest string, versionDest string func copyReadme(b string, funcName string, relativeFuncPath string, versionDest string) error { // Copy README for the function's version to the example directory. - tempDir, err := os.MkdirTemp("", "functions") + tempDir, err := ioutil.TempDir("", "functions") if err != nil { return err } cmd := exec.Command("git", fmt.Sprintf("--work-tree=%v", tempDir), "checkout", b, "--", filepath.Join(relativeFuncPath, "README.md")) err = cmd.Run() if err != nil { - return err + return fmt.Errorf("Error running %v: %v", cmd, err) } // Find the README in the example directory. @@ -276,18 +279,23 @@ func parseMetadata(f function, md metadata, version string, versionDest string) f.LatestVersion = version f.Path = versionDest f.Description = md.Description - sort.Sort(sort.StringSlice(md.Tags)) - f.Tags = strings.Join(md.Tags, ",") + sort.Strings(md.Tags) + f.Tags = strings.Join(md.Tags, ", ") + f.ImagePath = md.Image return f } func getRelativeFunctionPath(source string, funcName string) (string, error) { // Find the directory for the function's source. - m, err := filepath.Glob(filepath.Join(source, "functions", "*", funcName)) + sourcePattern := filepath.Join(source, "functions", "*", funcName) + m, err := filepath.Glob(sourcePattern) if err != nil { return "", err } + if m == nil { + return "", fmt.Errorf("Could not find a function with the following pattern: %v", sourcePattern) + } return functionDirPrefix.ReplaceAllString(m[0], "functions/"), nil } @@ -295,7 +303,7 @@ func getRelativeFunctionPath(source string, funcName string) (string, error) { func writeFunctionIndex(functions []function, source string, dest string) error { out := []string{"# Functions Catalog", "", "| Name | Description | Tags |", "| ---- | ----------- | ---- |"} for _, f := range functions { - functionEntry := fmt.Sprintf("| [%v](%v/) | %v | %v |", f.FunctionName, strings.Replace(f.Path, filepath.Join(source, "examples"), "", 1), f.Description, f.Tags) + functionEntry := fmt.Sprintf("| [%v](%v/) | %v | %v |", f.ImagePath, strings.Replace(f.Path, filepath.Join(source, "site"), "", 1), f.Description, f.Tags) out = append(out, functionEntry) } @@ -313,7 +321,7 @@ func writeExampleIndex(functions []function, source string, dest string) error { exampleToPaths := make(map[string]example) for exName, ex := range examples { e := ex - e.LocalExamplePath = strings.Replace(ex.LocalExamplePath, filepath.Join(source, "examples"), "", 1) + e.LocalExamplePath = strings.Replace(ex.LocalExamplePath, filepath.Join(source, "site"), "", 1) exampleToPaths[exName] = e } vToE[v] = exampleToPaths diff --git a/scripts/run-site.sh b/scripts/run-site.sh new file mode 100755 index 000000000..ed737dad1 --- /dev/null +++ b/scripts/run-site.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -euo pipefail + +# Set read/execute permissions for newly created site files in macOS or Linux. +setfacl -Rd -m o::rx site/ 2> /dev/null || chmod -R +a "everyone allow read,execute,file_inherit,directory_inherit" site/ +# Set read/execute permissions for existing site files. +chmod -R o+rx site/ +# Terminate running kpt-function-catalog docker containers and rebuild. +(docker stop kpt-fn-catalog-doc && docker rm kpt-fn-catalog-doc) || docker build site/ -t kpt-function-catalog:latest +# Mount the site directory as the default content for the docker container. +docker run -v "$(pwd)"/site:/usr/share/nginx/html -p 3001:80 -d --name kpt-fn-catalog-doc kpt-function-catalog:latest +echo "Container kpt-fn-catalog-doc is serving docs at http://127.0.0.1:3001" diff --git a/scripts/verify-docs.py b/scripts/verify-docs.py index a6d501207..5472063c5 100755 --- a/scripts/verify-docs.py +++ b/scripts/verify-docs.py @@ -31,7 +31,9 @@ examples_directories_to_skip = ['_template', 'contrib'] required_fields = ['image', 'description', 'tags', 'sourceURL', 'examplePackageURLs', 'emails', 'license'] kpt_team_email = 'kpt-team@google.com' - +disallowed_kpt_commands = ['kpt fn run', 'kpt cfg'] +gcr_prefix = 'gcr.io/kpt-fn/' +git_url_prefix = 'https://github.com/GoogleContainerTools/kpt-functions-catalog.git' def validate_master_branch(): fn_name_to_examples = validate_examples_dir_for_master_branch() @@ -49,7 +51,7 @@ def validate_examples_dir_for_master_branch(): example_list = [] for example_name in os.listdir(dir_name): example_list.append(example_name) - validate_example_md(os.path.join(dir_name, example_name), 'master') + validate_example_md(fn_name, dir_name, example_name, 'master') fn_name_to_examples[fn_name] = example_list return fn_name_to_examples @@ -89,7 +91,7 @@ def validate_examples_dir_for_release_branch(branch_name, fn_name): dir_name = os.path.join(examples_directory, fn_name) for example_name in os.listdir(dir_name): examples.append(example_name) - validate_example_md(os.path.join(dir_name, example_name), branch_name) + validate_example_md(fn_name, dir_name, example_name, branch_name) return examples @@ -106,29 +108,67 @@ def validate_functions_dir_for_release_branch(examples, branch_name, fn_name): validate_metadata(meta, branch_name, path_name, fn_name, examples) -def validate_example_md(example_path, branch): +def validate_example_md(fn_name, dir_name, example_name, branch): + example_path = os.path.join(dir_name, example_name) md_file_path = os.path.join(example_path, 'README.md') - process = subprocess.Popen(['mdrip', '--label', 'test', md_file_path], + + with open(md_file_path) as f: + first_line = f.readline().strip() + if not first_line.startswith('# '): + raise Exception(f'title must be in the 1st line and starts with one "#"') + if fn_name not in first_line: + raise Exception(f'title "{first_line}" must be in format ": Example Name" and contains "{fn_name}"') + if example_name.replace('-', ' ') not in first_line.lower(): + raise Exception(f'title "{first_line}" must be in format ": Example Name" and contains "{example_name.replace("-", " ")}"') + + process = subprocess.Popen(['mdrip', md_file_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = process.communicate() if len(stderr) > 0: print(f'stderr of mdrip: {str(stderr)}') - found_pkg_url = False - for line in str(stdout).splitlines(): + + process = subprocess.Popen(['mdrip', '--label', 'skip', md_file_path], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdout2, stderr2 = process.communicate() + if len(stderr2) > 0: + print(f'stderr of mdrip: {str(stderr2)}') + + tag = branch + if branch == 'master': + tag = 'unstable' + else: + splits = branch.split('/') + if len(splits) != 2: + raise Exception(f'the release branch {branch} must has format /vX.Y') + tag = splits[1] + + lines = stdout.decode("utf-8").splitlines() + lines2 = stdout2.decode("utf-8").splitlines() + + for line in lines: if line.startswith('#') or line.startswith('echo'): continue + for disallowed in disallowed_kpt_commands: + if disallowed in line: + raise Exception(f'command {disallowed} is not allowed in the desired package url in {md_file_path}') + + if line in lines2: + continue + for item in line.split(): - git_url_prefix = 'https://github.com/GoogleContainerTools/kpt-functions-catalog.git' if item.startswith(git_url_prefix): - found_pkg_url = True desired_pkg_url = f'{git_url_prefix}/{example_path}' if branch != 'master': desired_pkg_url = desired_pkg_url + f'@{branch}' if item != desired_pkg_url: raise Exception(f'the desired package url in {md_file_path} is {desired_pkg_url}, but found {item}') - if not found_pkg_url: - raise Exception(f'at least one fenced code block should be marked with "" in {md_file_path}') + + if gcr_prefix in item: + desired_image_name = f'{gcr_prefix}{fn_name}:{tag}' + if desired_image_name not in item: + raise Exception(f'expect "{line}" to contain "{desired_image_name}" in {md_file_path}') def validate_metadata(metadata, branch, path, fn, examples_list): @@ -154,11 +194,9 @@ def validate_metadata(metadata, branch, path, fn, examples_list): def main(): - branch_ref = os.getenv('GITHUB_REF') - ref_prefix = 'refs/heads/' - branch_name = 'master' - if branch_ref is not None and branch_ref.startswith(ref_prefix): - branch_name = branch_ref[len(ref_prefix):] + branch_name = os.getenv('GITHUB_BASE_REF') + if branch_name is None or len(branch_name) == 0: + branch_name = 'master' if branch_name == 'master': validate_master_branch() diff --git a/site/.firebaserc b/site/.firebaserc new file mode 100644 index 000000000..520b57050 --- /dev/null +++ b/site/.firebaserc @@ -0,0 +1,5 @@ +{ + "projects": { + "default": "kpt-dev" + } +} \ No newline at end of file diff --git a/site/Dockerfile b/site/Dockerfile new file mode 100644 index 000000000..1dfc118bf --- /dev/null +++ b/site/Dockerfile @@ -0,0 +1,10 @@ +# Host an nginx server with the contents of the function catalog site to emulate the live environment. +FROM nginx:1.18.0-alpine +COPY . /usr/share/nginx/html +COPY site_check.conf /etc/nginx/conf.d/configfile.template + +ENV PORT 80 +ENV HOST 0.0.0.0 +EXPOSE 80 +RUN sh -c "envsubst '\$PORT' < /etc/nginx/conf.d/configfile.template > /etc/nginx/conf.d/default.conf" +CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/site/firebase.json b/site/firebase.json new file mode 100644 index 000000000..e899284ef --- /dev/null +++ b/site/firebase.json @@ -0,0 +1,17 @@ +{ + "hosting": { + "site": "kpt-functions-catalog", + "public": ".", + "ignore": [ + "firebase.json", + "**/.*", + "**/node_modules/**" + ], + "rewrites": [ + { + "source": "**", + "destination": "/index.html" + } + ] + } +} diff --git a/examples/index.html b/site/index.html similarity index 87% rename from examples/index.html rename to site/index.html index 6d023479f..4c8b88682 100644 --- a/examples/index.html +++ b/site/index.html @@ -2,7 +2,7 @@ - Home + kpt Functions Catalog + -