mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-17 11:58:18 +00:00
Compare commits
1 Commits
api/v0.4.0
...
kustomize/
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c9d828f04 |
100
.github/workflows/go.yml
vendored
100
.github/workflows/go.yml
vendored
@@ -1,100 +0,0 @@
|
||||
name: Go
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
|
||||
lint:
|
||||
name: Lint
|
||||
runs-on: [ubuntu-latest]
|
||||
steps:
|
||||
|
||||
- name: Set up Go 1.x
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ^1.13
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Lint
|
||||
run: ./travis/kyaml-pre-commit.sh
|
||||
env:
|
||||
KUSTOMIZE_DOCKER_E2E: false # don't need to do e2e tests for linting
|
||||
|
||||
test-linux:
|
||||
name: Test Linux
|
||||
runs-on: [ubuntu-latest]
|
||||
steps:
|
||||
|
||||
- name: Set up Go 1.x
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ^1.13
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Test kyaml
|
||||
run: go test -cover ./...
|
||||
working-directory: ./kyaml
|
||||
|
||||
- name: Test cmd/config
|
||||
run: go test -cover ./...
|
||||
working-directory: ./cmd/config
|
||||
env:
|
||||
KUSTOMIZE_DOCKER_E2E: true
|
||||
|
||||
test-macos:
|
||||
name: Test MacOS
|
||||
runs-on: [macos-latest]
|
||||
steps:
|
||||
|
||||
- name: Set up Go 1.x
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ^1.13
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Test kyaml
|
||||
run: go test -cover ./...
|
||||
working-directory: ./kyaml
|
||||
|
||||
- name: Test cmd/config
|
||||
run: go test -cover ./...
|
||||
working-directory: ./cmd/config
|
||||
env:
|
||||
KUSTOMIZE_DOCKER_E2E: false # docker not installed on mac
|
||||
|
||||
test-windows:
|
||||
name: Test Windows
|
||||
runs-on: [windows-latest]
|
||||
steps:
|
||||
|
||||
- name: Set up Go 1.x
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ^1.13
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Test kyaml
|
||||
run: go test -cover ./...
|
||||
working-directory: ./kyaml
|
||||
|
||||
- name: Test cmd/config
|
||||
run: go test -cover ./...
|
||||
working-directory: ./cmd/config
|
||||
env:
|
||||
KUSTOMIZE_DOCKER_E2E: false # docker on windows not working well yet
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -5,9 +5,6 @@
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
.idea
|
||||
*.iml
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
run:
|
||||
deadline: 5m
|
||||
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
- bodyclose
|
||||
- deadcode
|
||||
- depguard
|
||||
# - dogsled
|
||||
- dupl
|
||||
# - errcheck
|
||||
# - funlen
|
||||
# - gochecknoinits
|
||||
- goconst
|
||||
# - gocritic
|
||||
- gocyclo
|
||||
- gofmt
|
||||
- goimports
|
||||
- golint
|
||||
- gosec
|
||||
- gosimple
|
||||
- govet
|
||||
- ineffassign
|
||||
- interfacer
|
||||
- lll
|
||||
- misspell
|
||||
- nakedret
|
||||
# - scopelint
|
||||
- staticcheck
|
||||
- structcheck
|
||||
# stylecheck demands that acronyms not be treated as words
|
||||
# in camelCase, so JsonOp become JSONOp, etc. Yuck.
|
||||
# - stylecheck
|
||||
- typecheck
|
||||
- unconvert
|
||||
- unparam
|
||||
- unused
|
||||
- varcheck
|
||||
# - whitespace
|
||||
|
||||
linters-settings:
|
||||
dupl:
|
||||
threshold: 400
|
||||
lll:
|
||||
line-length: 170
|
||||
gocyclo:
|
||||
min-complexity: 15
|
||||
golint:
|
||||
min-confidence: 0.85
|
||||
30
.golangci.yml
Normal file
30
.golangci.yml
Normal file
@@ -0,0 +1,30 @@
|
||||
run:
|
||||
deadline: 5m
|
||||
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
- dupl
|
||||
- goconst
|
||||
- gocyclo
|
||||
- gofmt
|
||||
- golint
|
||||
- govet
|
||||
- ineffassign
|
||||
- interfacer
|
||||
- lll
|
||||
- misspell
|
||||
- nakedret
|
||||
- structcheck
|
||||
- unparam
|
||||
- varcheck
|
||||
|
||||
linters-settings:
|
||||
dupl:
|
||||
threshold: 400
|
||||
lll:
|
||||
line-length: 170
|
||||
gocyclo:
|
||||
min-complexity: 15
|
||||
golint:
|
||||
min-confidence: 0.85
|
||||
38
.travis.yml
Normal file
38
.travis.yml
Normal file
@@ -0,0 +1,38 @@
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
# TODO: Uncomment when tests running on Windows.
|
||||
# - windows
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- tree
|
||||
homebrew:
|
||||
packages:
|
||||
- tree
|
||||
update: true
|
||||
|
||||
# Only clone the most recent commit.
|
||||
git:
|
||||
depth: 1
|
||||
|
||||
language: go
|
||||
|
||||
go:
|
||||
- "1.12"
|
||||
|
||||
go_import_path: sigs.k8s.io/kustomize
|
||||
|
||||
before_install:
|
||||
- source ./travis/consider-early-travis-exit.sh
|
||||
|
||||
# Skip the install process; let pre-commit.sh do it.
|
||||
install: true
|
||||
|
||||
script:
|
||||
- ./travis/pre-commit.sh
|
||||
|
||||
# TBD. Suppressing for now.
|
||||
notifications:
|
||||
email: false
|
||||
@@ -6,15 +6,11 @@ _As contributors and maintainers of this project, and in the interest of fosteri
|
||||
|
||||
## Getting Started
|
||||
|
||||
Dev guides:
|
||||
|
||||
- [Mac](docs/macDevGuide.md)
|
||||
|
||||
We have full documentation on how to get started contributing here:
|
||||
|
||||
- [Contributor License Agreement](https://git.k8s.io/community/CLA.md) Kubernetes projects require that you sign a Contributor License Agreement (CLA) before we can accept your pull requests
|
||||
- [Kubernetes Contributor Guide](http://git.k8s.io/community/contributors/guide) - Main contributor documentation, or you can just jump directly to the [contributing section](http://git.k8s.io/community/contributors/guide#contributing)
|
||||
- [Contributor Cheat Sheet](https://git.k8s.io/community/contributors/guide/contributor-cheatsheet/README.md) - Common resources for existing developers
|
||||
- [Contributor Cheat Sheet](https://git.k8s.io/community/contributors/guide/contributor-cheatsheet.md) - Common resources for existing developers
|
||||
|
||||
## Mentorship
|
||||
|
||||
|
||||
345
Makefile
345
Makefile
@@ -1,334 +1,37 @@
|
||||
# Copyright 2019 The Kubernetes Authors.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Makefile for kustomize CLI and API.
|
||||
BIN_NAME=kustomize
|
||||
|
||||
MYGOBIN := $(shell go env GOPATH)/bin
|
||||
SHELL := /bin/bash
|
||||
export PATH := $(MYGOBIN):$(PATH)
|
||||
COVER_FILE=coverage.out
|
||||
|
||||
.PHONY: all
|
||||
all: verify-kustomize
|
||||
export GO111MODULE=on
|
||||
|
||||
.PHONY: verify-kustomize
|
||||
verify-kustomize: \
|
||||
lint-kustomize \
|
||||
test-unit-kustomize-all \
|
||||
test-examples-kustomize-against-HEAD
|
||||
# TODO: restore test-examples-kustomize-against-3.5.5 \
|
||||
# once it works. Likely have to fix and release 3.6
|
||||
# test-examples-kustomize-against-3.5.4 no longer works because
|
||||
# the examples tests features not in 3.5.4
|
||||
all: test build
|
||||
|
||||
# The following target referenced by a file in
|
||||
# https://github.com/kubernetes/test-infra/tree/master/config/jobs/kubernetes-sigs/kustomize
|
||||
.PHONY: prow-presubmit-check
|
||||
prow-presubmit-check: \
|
||||
lint-kustomize \
|
||||
test-unit-kustomize-all \
|
||||
test-examples-kustomize-against-HEAD \
|
||||
test-unit-cmd-all \
|
||||
test-go-mod
|
||||
test: generate-code test-lint test-go
|
||||
|
||||
.PHONY: verify-kustomize-e2e
|
||||
verify-kustomize-e2e: test-examples-e2e-kustomize
|
||||
test-go:
|
||||
go test -v ./...
|
||||
|
||||
# Other builds in this repo might want a different linter version.
|
||||
# Without one Makefile to rule them all, the different makes
|
||||
# cannot assume that golanci-lint is at the version they want
|
||||
# since everything uses the same implicit GOPATH.
|
||||
# This installs in a temp dir to avoid overwriting someone else's
|
||||
# linter, then installs in MYGOBIN with a new name.
|
||||
# Version pinned by hack/go.mod
|
||||
$(MYGOBIN)/golangci-lint-kustomize:
|
||||
( \
|
||||
set -e; \
|
||||
cd hack; \
|
||||
GO111MODULE=on go build -tags=tools -o $(MYGOBIN)/golangci-lint-kustomize github.com/golangci/golangci-lint/cmd/golangci-lint; \
|
||||
)
|
||||
test-lint:
|
||||
golangci-lint run ./...
|
||||
|
||||
# Version pinned by api/go.mod
|
||||
$(MYGOBIN)/mdrip:
|
||||
cd api; \
|
||||
go install github.com/monopole/mdrip
|
||||
generate-code:
|
||||
./plugin/generateBuiltins.sh $(GOPATH)
|
||||
|
||||
# Version pinned by api/go.mod
|
||||
$(MYGOBIN)/stringer:
|
||||
cd api; \
|
||||
go install golang.org/x/tools/cmd/stringer
|
||||
build:
|
||||
go build -o $(BIN_NAME) cmd/kustomize/main.go
|
||||
|
||||
# Version pinned by api/go.mod
|
||||
$(MYGOBIN)/goimports:
|
||||
cd api; \
|
||||
go install golang.org/x/tools/cmd/goimports
|
||||
install:
|
||||
go install $(PWD)/cmd/kustomize
|
||||
|
||||
# Install resource from whatever is checked out.
|
||||
$(MYGOBIN)/resource:
|
||||
cd cmd/resource; \
|
||||
go install .
|
||||
|
||||
# To pin pluginator, use this recipe instead:
|
||||
# cd api;
|
||||
# go install sigs.k8s.io/kustomize/pluginator/v2
|
||||
$(MYGOBIN)/pluginator:
|
||||
cd pluginator; \
|
||||
go install .
|
||||
|
||||
# Install kustomize from whatever is checked out.
|
||||
$(MYGOBIN)/kustomize:
|
||||
cd kustomize; \
|
||||
go install .
|
||||
|
||||
.PHONY: install-tools
|
||||
install-tools: \
|
||||
$(MYGOBIN)/goimports \
|
||||
$(MYGOBIN)/golangci-lint-kustomize \
|
||||
$(MYGOBIN)/mdrip \
|
||||
$(MYGOBIN)/pluginator \
|
||||
$(MYGOBIN)/stringer
|
||||
|
||||
### Begin kustomize plugin rules.
|
||||
#
|
||||
# The rules to deal with builtin plugins are a bit
|
||||
# complicated because
|
||||
#
|
||||
# - Every builtin plugin is a Go plugin -
|
||||
# meaning it gets its own module directory
|
||||
# (outside of the api module) with Go
|
||||
# code in a 'main' package per Go plugin rules.
|
||||
# - kustomize locates plugins using the
|
||||
# 'apiVersion' and 'kind' fields from the
|
||||
# plugin config file.
|
||||
# - k8s wants CamelCase in 'kind' fields.
|
||||
# - The module name (the last name in the path)
|
||||
# must be the lowercased 'kind' of the
|
||||
# plugin because Go and related tools
|
||||
# demand lowercase in import paths, but
|
||||
# allow CamelCase in file names.
|
||||
# - the generated code must live in the api
|
||||
# module (it's linked into the api).
|
||||
|
||||
# Where all generated builtin plugin code should go.
|
||||
pGen=api/builtins
|
||||
# Where the builtin Go plugin modules live.
|
||||
pSrc=plugin/builtin
|
||||
|
||||
_builtinplugins = \
|
||||
AnnotationsTransformer.go \
|
||||
ConfigMapGenerator.go \
|
||||
HashTransformer.go \
|
||||
ImageTagTransformer.go \
|
||||
LabelTransformer.go \
|
||||
LegacyOrderTransformer.go \
|
||||
NamespaceTransformer.go \
|
||||
PatchJson6902Transformer.go \
|
||||
PatchStrategicMergeTransformer.go \
|
||||
PatchTransformer.go \
|
||||
PrefixSuffixTransformer.go \
|
||||
ReplicaCountTransformer.go \
|
||||
SecretGenerator.go \
|
||||
ValueAddTransformer.go
|
||||
|
||||
# Maintaining this explicit list of generated files, and
|
||||
# adding it as a dependency to a few targets, to assure
|
||||
# they get recreated if deleted. The rules below on how
|
||||
# to make them don't, by themselves, assure they will be
|
||||
# recreated if deleted.
|
||||
builtinplugins = $(patsubst %,$(pGen)/%,$(_builtinplugins))
|
||||
|
||||
# These rules are verbose, but assure that if a source file
|
||||
# is modified, the corresponding generated file, and only
|
||||
# that file, will be recreated.
|
||||
$(pGen)/AnnotationsTransformer.go: $(pSrc)/annotationstransformer/AnnotationsTransformer.go
|
||||
$(pGen)/ConfigMapGenerator.go: $(pSrc)/configmapgenerator/ConfigMapGenerator.go
|
||||
$(pGen)/HashTransformer.go: $(pSrc)/hashtransformer/HashTransformer.go
|
||||
$(pGen)/ImageTagTransformer.go: $(pSrc)/imagetagtransformer/ImageTagTransformer.go
|
||||
$(pGen)/LabelTransformer.go: $(pSrc)/labeltransformer/LabelTransformer.go
|
||||
$(pGen)/LegacyOrderTransformer.go: $(pSrc)/legacyordertransformer/LegacyOrderTransformer.go
|
||||
$(pGen)/NamespaceTransformer.go: $(pSrc)/namespacetransformer/NamespaceTransformer.go
|
||||
$(pGen)/PatchJson6902Transformer.go: $(pSrc)/patchjson6902transformer/PatchJson6902Transformer.go
|
||||
$(pGen)/PatchStrategicMergeTransformer.go: $(pSrc)/patchstrategicmergetransformer/PatchStrategicMergeTransformer.go
|
||||
$(pGen)/PatchTransformer.go: $(pSrc)/patchtransformer/PatchTransformer.go
|
||||
$(pGen)/PrefixSuffixTransformer.go: $(pSrc)/prefixsuffixtransformer/PrefixSuffixTransformer.go
|
||||
$(pGen)/ReplicaCountTransformer.go: $(pSrc)/replicacounttransformer/ReplicaCountTransformer.go
|
||||
$(pGen)/SecretGenerator.go: $(pSrc)/secretgenerator/SecretGenerator.go
|
||||
$(pGen)/ValueAddTransformer.go: $(pSrc)/valueaddtransformer/ValueAddTransformer.go
|
||||
|
||||
# The (verbose but portable) Makefile way to convert to lowercase.
|
||||
toLowerCase = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$1))))))))))))))))))))))))))
|
||||
|
||||
$(pGen)/%.go: $(MYGOBIN)/pluginator
|
||||
@echo "generating $*"
|
||||
( \
|
||||
set -e; \
|
||||
cd $(pSrc)/$(call toLowerCase,$*); \
|
||||
go generate .; \
|
||||
cd ../../../$(pGen); \
|
||||
$(MYGOBIN)/goimports -w $*.go \
|
||||
)
|
||||
|
||||
# Target is for debugging.
|
||||
.PHONY: generate-kustomize-builtin-plugins
|
||||
generate-kustomize-builtin-plugins: $(builtinplugins)
|
||||
|
||||
.PHONY: kustomize-external-go-plugin-build
|
||||
kustomize-external-go-plugin-build:
|
||||
./hack/buildExternalGoPlugins.sh ./plugin
|
||||
|
||||
.PHONY: kustomize-external-go-plugin-clean
|
||||
kustomize-external-go-plugin-clean:
|
||||
./hack/buildExternalGoPlugins.sh ./plugin clean
|
||||
|
||||
### End kustomize plugin rules.
|
||||
|
||||
.PHONY: lint-kustomize
|
||||
lint-kustomize: install-tools $(builtinplugins)
|
||||
cd api; \
|
||||
$(MYGOBIN)/golangci-lint-kustomize -c ../.golangci-kustomize.yml run ./...
|
||||
cd kustomize; \
|
||||
$(MYGOBIN)/golangci-lint-kustomize -c ../.golangci-kustomize.yml run ./...
|
||||
cd pluginator; \
|
||||
$(MYGOBIN)/golangci-lint-kustomize -c ../.golangci-kustomize.yml run ./...
|
||||
|
||||
# Used to add non-default compilation flags when experimenting with
|
||||
# plugin-to-api compatibility checks.
|
||||
.PHONY: build-kustomize-api
|
||||
build-kustomize-api: $(builtinplugins)
|
||||
cd api; go build ./...
|
||||
|
||||
.PHONY: test-unit-kustomize-api
|
||||
test-unit-kustomize-api: build-kustomize-api
|
||||
cd api; go test ./...
|
||||
|
||||
.PHONY: test-unit-kustomize-plugins
|
||||
test-unit-kustomize-plugins:
|
||||
./hack/testUnitKustomizePlugins.sh
|
||||
|
||||
.PHONY: test-unit-kustomize-cli
|
||||
test-unit-kustomize-cli:
|
||||
cd kustomize; go test ./...
|
||||
|
||||
.PHONY: test-unit-kustomize-all
|
||||
test-unit-kustomize-all: \
|
||||
test-unit-kustomize-api \
|
||||
test-unit-kustomize-cli \
|
||||
test-unit-kustomize-plugins
|
||||
|
||||
test-unit-cmd-all:
|
||||
./travis/kyaml-pre-commit.sh
|
||||
|
||||
test-go-mod:
|
||||
./travis/check-go-mod.sh
|
||||
|
||||
.PHONY:
|
||||
test-examples-e2e-kustomize: $(MYGOBIN)/mdrip $(MYGOBIN)/kind
|
||||
( \
|
||||
set -e; \
|
||||
/bin/rm -f $(MYGOBIN)/kustomize; \
|
||||
echo "Installing kustomize from ."; \
|
||||
cd kustomize; go install .; cd ..; \
|
||||
./hack/testExamplesE2EAgainstKustomize.sh .; \
|
||||
)
|
||||
|
||||
.PHONY:
|
||||
test-examples-kustomize-against-HEAD: $(MYGOBIN)/kustomize $(MYGOBIN)/mdrip
|
||||
./hack/testExamplesAgainstKustomize.sh HEAD
|
||||
|
||||
.PHONY:
|
||||
test-examples-kustomize-against-3.5.4: $(MYGOBIN)/mdrip
|
||||
( \
|
||||
set -e; \
|
||||
tag=v3.5.4; \
|
||||
/bin/rm -f $(MYGOBIN)/kustomize; \
|
||||
echo "Installing kustomize $$tag."; \
|
||||
GO111MODULE=on go get sigs.k8s.io/kustomize/kustomize/v3@$${tag}; \
|
||||
./hack/testExamplesAgainstKustomize.sh $$tag; \
|
||||
echo "Reinstalling kustomize from HEAD."; \
|
||||
cd kustomize; go install .; \
|
||||
)
|
||||
|
||||
.PHONY:
|
||||
test-examples-kustomize-against-3.5.5: $(MYGOBIN)/mdrip
|
||||
( \
|
||||
set -e; \
|
||||
tag=v3.5.5; \
|
||||
/bin/rm -f $(MYGOBIN)/kustomize; \
|
||||
echo "Installing kustomize $$tag."; \
|
||||
GO111MODULE=on go get sigs.k8s.io/kustomize/kustomize/v3@$${tag}; \
|
||||
./hack/testExamplesAgainstKustomize.sh $$tag; \
|
||||
echo "Reinstalling kustomize from HEAD."; \
|
||||
cd kustomize; go install .; \
|
||||
)
|
||||
cover:
|
||||
# The plugin directory eludes coverage, and is therefore omitted
|
||||
go test ./pkg/... ./k8sdeps/... ./internal/... -coverprofile=$(COVER_FILE) && \
|
||||
go tool cover -html=$(COVER_FILE)
|
||||
|
||||
|
||||
# linux only.
|
||||
# This is for testing an example plugin that
|
||||
# uses kubeval for validation.
|
||||
# Don't want to add a hard dependence in go.mod file
|
||||
# to github.com/instrumenta/kubeval.
|
||||
# Instead, download the binary.
|
||||
$(MYGOBIN)/kubeval:
|
||||
( \
|
||||
set -e; \
|
||||
d=$(shell mktemp -d); cd $$d; \
|
||||
wget https://github.com/instrumenta/kubeval/releases/latest/download/kubeval-linux-amd64.tar.gz; \
|
||||
tar xf kubeval-linux-amd64.tar.gz; \
|
||||
mv kubeval $(MYGOBIN); \
|
||||
rm -rf $$d; \
|
||||
)
|
||||
clean:
|
||||
go clean
|
||||
rm -f $(BIN_NAME)
|
||||
rm -f $(COVER_FILE)
|
||||
|
||||
# linux only.
|
||||
# This is for testing an example plugin that uses helm to inflate a chart
|
||||
# for subsequent kustomization.
|
||||
# Don't want to add a hard dependence in go.mod file to helm.
|
||||
# Instead, download the binaries.
|
||||
$(MYGOBIN)/helmV2:
|
||||
( \
|
||||
set -e; \
|
||||
d=$(shell mktemp -d); cd $$d; \
|
||||
tgzFile=helm-v2.13.1-linux-amd64.tar.gz; \
|
||||
wget https://storage.googleapis.com/kubernetes-helm/$$tgzFile; \
|
||||
tar -xvzf $$tgzFile; \
|
||||
mv linux-amd64/helm $(MYGOBIN)/helmV2; \
|
||||
rm -rf $$d \
|
||||
)
|
||||
|
||||
# Helm V3 differs from helm V2; downloading it to provide coverage for the
|
||||
# chart inflator plugin under helm v3.
|
||||
$(MYGOBIN)/helmV3:
|
||||
( \
|
||||
set -e; \
|
||||
d=$(shell mktemp -d); cd $$d; \
|
||||
tgzFile=helm-v3.2.0-rc.1-linux-amd64.tar.gz; \
|
||||
wget https://get.helm.sh/$$tgzFile; \
|
||||
tar -xvzf $$tgzFile; \
|
||||
mv linux-amd64/helm $(MYGOBIN)/helmV3; \
|
||||
rm -rf $$d \
|
||||
)
|
||||
|
||||
# Default version of helm is v2 for the time being.
|
||||
$(MYGOBIN)/helm: $(MYGOBIN)/helmV2
|
||||
ln -s $(MYGOBIN)/helmV2 $(MYGOBIN)/helm
|
||||
|
||||
$(MYGOBIN)/kind:
|
||||
( \
|
||||
set -e; \
|
||||
d=$(shell mktemp -d); cd $$d; \
|
||||
wget -O ./kind https://github.com/kubernetes-sigs/kind/releases/download/v0.7.0/kind-$(shell uname)-amd64; \
|
||||
chmod +x ./kind; \
|
||||
mv ./kind $(MYGOBIN); \
|
||||
rm -rf $$d; \
|
||||
)
|
||||
|
||||
.PHONY: clean
|
||||
clean: kustomize-external-go-plugin-clean
|
||||
go clean --cache
|
||||
rm -f $(builtinplugins)
|
||||
rm -f $(MYGOBIN)/pluginator
|
||||
rm -f $(MYGOBIN)/kustomize
|
||||
rm -f $(MYGOBIN)/golangci-lint-kustomize
|
||||
|
||||
# Nuke the site from orbit. It's the only way to be sure.
|
||||
.PHONY: nuke
|
||||
nuke: clean
|
||||
go clean --modcache
|
||||
.PHONY: test build install clean generate-code test-go test-lint cover
|
||||
|
||||
@@ -9,5 +9,3 @@ aliases:
|
||||
- mengqiy
|
||||
- monopole
|
||||
- pwittrock
|
||||
- mortent
|
||||
- phanimarupaka
|
||||
|
||||
19
README.md
19
README.md
@@ -12,7 +12,8 @@ and it's like [`sed`], in that it emits edited text.
|
||||
This tool is sponsored by [sig-cli] ([KEP]), and
|
||||
inspired by [DAM].
|
||||
|
||||
[](https://prow.k8s.io/job-history/kubernetes-jenkins/pr-logs/directory/kustomize-presubmit-master)
|
||||
|
||||
[](https://travis-ci.org/kubernetes-sigs/kustomize)
|
||||
[](https://goreportcard.com/report/github.com/kubernetes-sigs/kustomize)
|
||||
|
||||
Download a binary from the [release page], or see
|
||||
@@ -27,9 +28,9 @@ Since [v1.14][kubectl announcement] the kustomize build system has been included
|
||||
|
||||
| kubectl version | kustomize version |
|
||||
|---------|--------|
|
||||
| v1.16.0 | [v2.0.3](/../../tree/v2.0.3) |
|
||||
| v1.15.x | [v2.0.3](/../../tree/v2.0.3) |
|
||||
| v1.14.x | [v2.0.3](/../../tree/v2.0.3) |
|
||||
| v1.16.0 | [v2.0.3](https://github.com/kubernetes-sigs/kustomize/tree/v2.0.3) |
|
||||
| v1.15.x | [v2.0.3](https://github.com/kubernetes-sigs/kustomize/tree/v2.0.3) |
|
||||
| v1.14.x | [v2.0.3](https://github.com/kubernetes-sigs/kustomize/tree/v2.0.3) |
|
||||
|
||||
For examples and guides for using the kubectl integration please see the [kubectl book] or the [kubernetes documentation].
|
||||
|
||||
@@ -106,7 +107,7 @@ Take the work from step (1) above, move it into a
|
||||
`someApp` subdirectory called `base`, then
|
||||
place overlays in a sibling directory.
|
||||
|
||||
An overlay is just another kustomization, referring to
|
||||
An overlay is just another kustomization, refering to
|
||||
the base, and referring to patches to apply to that
|
||||
base.
|
||||
|
||||
@@ -166,7 +167,7 @@ is governed by the [Kubernetes Code of Conduct].
|
||||
[eschewed feature list]: docs/eschewedFeatures.md
|
||||
[imageBase]: docs/images/base.jpg
|
||||
[imageOverlay]: docs/images/overlay.jpg
|
||||
[kind/feature]: /../../labels/kind%2Ffeature
|
||||
[kind/feature]: https://github.com/kubernetes-sigs/kustomize/labels/kind%2Ffeature
|
||||
[kubectl announcement]: https://kubernetes.io/blog/2019/03/25/kubernetes-1-14-release-announcement
|
||||
[kubectl book]: https://kubectl.docs.kubernetes.io/pages/app_customization/introduction.html
|
||||
[kubernetes documentation]: https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization/
|
||||
@@ -174,12 +175,12 @@ is governed by the [Kubernetes Code of Conduct].
|
||||
[kustomization]: docs/glossary.md#kustomization
|
||||
[overlay]: docs/glossary.md#overlay
|
||||
[overlays]: docs/glossary.md#overlay
|
||||
[release page]: /../../releases
|
||||
[release page]: https://github.com/kubernetes-sigs/kustomize/releases
|
||||
[resource]: docs/glossary.md#resource
|
||||
[resources]: docs/glossary.md#resource
|
||||
[sig-cli]: https://github.com/kubernetes/community/blob/master/sig-cli/README.md
|
||||
[variant]: docs/glossary.md#variant
|
||||
[variants]: docs/glossary.md#variant
|
||||
[v2.0.3]: /../../releases/tag/v2.0.3
|
||||
[v2.1.0]: /../../releases/tag/v2.1.0
|
||||
[v2.0.3]: https://github.com/kubernetes-sigs/kustomize/releases/tag/v2.0.3
|
||||
[v2.1.0]: https://github.com/kubernetes-sigs/kustomize/releases/tag/v2.1.0
|
||||
[workflows]: docs/workflows.md
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
// Code generated by pluginator on AnnotationsTransformer; DO NOT EDIT.
|
||||
// pluginator {unknown 1970-01-01T00:00:00Z }
|
||||
|
||||
package builtins
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/filters/annotations"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/filtersutil"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// Add the given annotations to the given field specifications.
|
||||
type AnnotationsTransformerPlugin struct {
|
||||
Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"`
|
||||
FieldSpecs []types.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||
}
|
||||
|
||||
func (p *AnnotationsTransformerPlugin) Config(
|
||||
_ *resmap.PluginHelpers, c []byte) (err error) {
|
||||
p.Annotations = nil
|
||||
p.FieldSpecs = nil
|
||||
return yaml.Unmarshal(c, p)
|
||||
}
|
||||
|
||||
func (p *AnnotationsTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||
for _, r := range m.Resources() {
|
||||
err := filtersutil.ApplyToJSON(annotations.Filter{
|
||||
Annotations: p.Annotations,
|
||||
FsSlice: p.FieldSpecs,
|
||||
}, r.Kunstructured)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewAnnotationsTransformerPlugin() resmap.TransformerPlugin {
|
||||
return &AnnotationsTransformerPlugin{}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
// Code generated by pluginator on LabelTransformer; DO NOT EDIT.
|
||||
// pluginator {unknown 1970-01-01T00:00:00Z }
|
||||
|
||||
package builtins
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/filters/labels"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/filtersutil"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// Add the given labels to the given field specifications.
|
||||
type LabelTransformerPlugin struct {
|
||||
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
|
||||
FieldSpecs []types.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||
}
|
||||
|
||||
func (p *LabelTransformerPlugin) Config(
|
||||
_ *resmap.PluginHelpers, c []byte) (err error) {
|
||||
p.Labels = nil
|
||||
p.FieldSpecs = nil
|
||||
return yaml.Unmarshal(c, p)
|
||||
}
|
||||
|
||||
func (p *LabelTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||
for _, r := range m.Resources() {
|
||||
err := filtersutil.ApplyToJSON(labels.Filter{
|
||||
Labels: p.Labels,
|
||||
FsSlice: p.FieldSpecs,
|
||||
}, r.Kunstructured)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewLabelTransformerPlugin() resmap.TransformerPlugin {
|
||||
return &LabelTransformerPlugin{}
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
// Code generated by pluginator on PatchStrategicMergeTransformer; DO NOT EDIT.
|
||||
// pluginator {unknown 1970-01-01T00:00:00Z }
|
||||
|
||||
package builtins
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
kyaml "sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/filters/patchstrategicmerge"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/filtersutil"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
type PatchStrategicMergeTransformerPlugin struct {
|
||||
h *resmap.PluginHelpers
|
||||
loadedPatches []*resource.Resource
|
||||
Paths []types.PatchStrategicMerge `json:"paths,omitempty" yaml:"paths,omitempty"`
|
||||
Patches string `json:"patches,omitempty" yaml:"patches,omitempty"`
|
||||
|
||||
YAMLSupport bool `json:"yamlSupport,omitempty" yaml:"yamlSupport,omitempty"`
|
||||
}
|
||||
|
||||
func (p *PatchStrategicMergeTransformerPlugin) Config(
|
||||
h *resmap.PluginHelpers, c []byte) (err error) {
|
||||
p.h = h
|
||||
err = yaml.Unmarshal(c, p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(p.Paths) == 0 && p.Patches == "" {
|
||||
return fmt.Errorf("empty file path and empty patch content")
|
||||
}
|
||||
if len(p.Paths) != 0 {
|
||||
for _, onePath := range p.Paths {
|
||||
res, err := p.h.ResmapFactory().RF().SliceFromBytes([]byte(onePath))
|
||||
if err == nil {
|
||||
p.loadedPatches = append(p.loadedPatches, res...)
|
||||
continue
|
||||
}
|
||||
res, err = p.h.ResmapFactory().RF().SliceFromPatches(
|
||||
p.h.Loader(), []types.PatchStrategicMerge{onePath})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.loadedPatches = append(p.loadedPatches, res...)
|
||||
}
|
||||
}
|
||||
if p.Patches != "" {
|
||||
res, err := p.h.ResmapFactory().RF().SliceFromBytes([]byte(p.Patches))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.loadedPatches = append(p.loadedPatches, res...)
|
||||
}
|
||||
|
||||
if len(p.loadedPatches) == 0 {
|
||||
return fmt.Errorf(
|
||||
"patch appears to be empty; files=%v, Patch=%s", p.Paths, p.Patches)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PatchStrategicMergeTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||
patches, err := p.h.ResmapFactory().MergePatches(p.loadedPatches)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, patch := range patches.Resources() {
|
||||
target, err := m.GetById(patch.OrgId())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !p.YAMLSupport {
|
||||
err = target.Patch(patch.Kunstructured)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// remove the resource from resmap
|
||||
// when the patch is to $patch: delete that target
|
||||
if len(target.Map()) == 0 {
|
||||
err = m.Remove(target.CurId())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
node, err := getRNode(patch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = filtersutil.ApplyToJSON(patchstrategicmerge.Filter{
|
||||
Patch: node,
|
||||
}, target.Kunstructured)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//TODO: Remove this once the next version of kyaml is released which
|
||||
// exposes GetRNode from the filutersutil package.
|
||||
func getRNode(k json.Marshaler) (*kyaml.RNode, error) {
|
||||
j, err := k.MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return kyaml.Parse(string(j))
|
||||
}
|
||||
|
||||
func NewPatchStrategicMergeTransformerPlugin() resmap.TransformerPlugin {
|
||||
return &PatchStrategicMergeTransformerPlugin{}
|
||||
}
|
||||
@@ -1,193 +0,0 @@
|
||||
// Code generated by pluginator on PatchTransformer; DO NOT EDIT.
|
||||
// pluginator {unknown 1970-01-01T00:00:00Z }
|
||||
|
||||
package builtins
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
jsonpatch "github.com/evanphx/json-patch"
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/kustomize/api/filters/patchjson6902"
|
||||
"sigs.k8s.io/kustomize/api/filters/patchstrategicmerge"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/filtersutil"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
type PatchTransformerPlugin struct {
|
||||
loadedPatch *resource.Resource
|
||||
decodedPatch jsonpatch.Patch
|
||||
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||
Patch string `json:"patch,omitempty" yaml:"patch,omitempty"`
|
||||
Target *types.Selector `json:"target,omitempty" yaml:"target,omitempty"`
|
||||
|
||||
YAMLSupport bool `json:"yamlSupport,omitempty" yaml:"yamlSupport,omitempty"`
|
||||
}
|
||||
|
||||
func (p *PatchTransformerPlugin) Config(
|
||||
h *resmap.PluginHelpers, c []byte) error {
|
||||
err := yaml.Unmarshal(c, p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.Patch = strings.TrimSpace(p.Patch)
|
||||
if p.Patch == "" && p.Path == "" {
|
||||
return fmt.Errorf(
|
||||
"must specify one of patch and path in\n%s", string(c))
|
||||
}
|
||||
if p.Patch != "" && p.Path != "" {
|
||||
return fmt.Errorf(
|
||||
"patch and path can't be set at the same time\n%s", string(c))
|
||||
}
|
||||
|
||||
if p.Path != "" {
|
||||
loaded, loadErr := h.Loader().Load(p.Path)
|
||||
if loadErr != nil {
|
||||
return loadErr
|
||||
}
|
||||
p.Patch = string(loaded)
|
||||
}
|
||||
|
||||
patchSM, errSM := h.ResmapFactory().RF().FromBytes([]byte(p.Patch))
|
||||
patchJson, errJson := jsonPatchFromBytes([]byte(p.Patch))
|
||||
if (errSM == nil && errJson == nil) ||
|
||||
(patchSM != nil && patchJson != nil) {
|
||||
return fmt.Errorf(
|
||||
"illegally qualifies as both an SM and JSON patch: [%v]",
|
||||
p.Patch)
|
||||
}
|
||||
if errSM != nil && errJson != nil {
|
||||
return fmt.Errorf(
|
||||
"unable to parse SM or JSON patch from [%v]", p.Patch)
|
||||
}
|
||||
if errSM == nil {
|
||||
p.loadedPatch = patchSM
|
||||
} else {
|
||||
p.decodedPatch = patchJson
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PatchTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||
if p.loadedPatch != nil {
|
||||
// The patch was a strategic merge patch
|
||||
return p.transformStrategicMerge(m, p.loadedPatch)
|
||||
} else {
|
||||
return p.transformJson6902(m, p.decodedPatch)
|
||||
}
|
||||
}
|
||||
|
||||
// transformStrategicMerge applies the provided strategic merge patch
|
||||
// to all the resources in the ResMap that match either the Target or
|
||||
// the identifier of the patch.
|
||||
func (p *PatchTransformerPlugin) transformStrategicMerge(m resmap.ResMap, patch *resource.Resource) error {
|
||||
if p.Target == nil {
|
||||
target, err := m.GetById(patch.OrgId())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return p.applySMPatch(target, patch)
|
||||
}
|
||||
|
||||
resources, err := m.Select(*p.Target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, res := range resources {
|
||||
patchCopy := patch.DeepCopy()
|
||||
patchCopy.SetName(res.GetName())
|
||||
patchCopy.SetNamespace(res.GetNamespace())
|
||||
patchCopy.SetGvk(res.GetGvk())
|
||||
err := p.applySMPatch(res, patchCopy)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// applySMPatch applies the provided strategic merge patch to the
|
||||
// given resource. Depending on the value of YAMLSupport, it will either
|
||||
// use the legacy implementation or the kyaml-based solution.
|
||||
func (p *PatchTransformerPlugin) applySMPatch(resource, patch *resource.Resource) error {
|
||||
if !p.YAMLSupport {
|
||||
return resource.Patch(patch.Kunstructured)
|
||||
} else {
|
||||
node, err := filtersutil.GetRNode(patch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return filtersutil.ApplyToJSON(patchstrategicmerge.Filter{
|
||||
Patch: node,
|
||||
}, resource.Kunstructured)
|
||||
}
|
||||
}
|
||||
|
||||
// transformJson6902 applies the provided json6902 patch
|
||||
// to all the resources in the ResMap that match the Target.
|
||||
func (p *PatchTransformerPlugin) transformJson6902(m resmap.ResMap, patch jsonpatch.Patch) error {
|
||||
if p.Target == nil {
|
||||
return fmt.Errorf("must specify a target for patch %s", p.Patch)
|
||||
}
|
||||
|
||||
resources, err := m.Select(*p.Target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, res := range resources {
|
||||
err = p.applyJson6902Patch(res, patch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// applyJson6902Patch applies the provided patch to the given resource.
|
||||
// Depending on the value of YAMLSupport, it will either
|
||||
// use the legacy implementation or the kyaml-based solution.
|
||||
func (p *PatchTransformerPlugin) applyJson6902Patch(resource *resource.Resource, patch jsonpatch.Patch) error {
|
||||
if !p.YAMLSupport {
|
||||
rawObj, err := resource.MarshalJSON()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
modifiedObj, err := patch.Apply(rawObj)
|
||||
if err != nil {
|
||||
return errors.Wrapf(
|
||||
err, "failed to apply json patch '%s'", p.Patch)
|
||||
}
|
||||
return resource.UnmarshalJSON(modifiedObj)
|
||||
} else {
|
||||
return filtersutil.ApplyToJSON(patchjson6902.Filter{
|
||||
Patch: p.Patch,
|
||||
}, resource.Kunstructured)
|
||||
}
|
||||
}
|
||||
|
||||
// jsonPatchFromBytes loads a Json 6902 patch from
|
||||
// a bytes input
|
||||
func jsonPatchFromBytes(
|
||||
in []byte) (jsonpatch.Patch, error) {
|
||||
ops := string(in)
|
||||
if ops == "" {
|
||||
return nil, fmt.Errorf("empty json patch operations")
|
||||
}
|
||||
|
||||
if ops[0] != '[' {
|
||||
jsonOps, err := yaml.YAMLToJSON(in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ops = string(jsonOps)
|
||||
}
|
||||
return jsonpatch.DecodePatch([]byte(ops))
|
||||
}
|
||||
|
||||
func NewPatchTransformerPlugin() resmap.TransformerPlugin {
|
||||
return &PatchTransformerPlugin{}
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
// Code generated by pluginator on ValueAddTransformer; DO NOT EDIT.
|
||||
// pluginator {unknown 1970-01-01T00:00:00Z }
|
||||
|
||||
package builtins
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/filters/namespace"
|
||||
"sigs.k8s.io/kustomize/api/filters/valueadd"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/filtersutil"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// An 'Add' transformer inspired by the IETF RFC 6902 JSON spec Add operation.
|
||||
type ValueAddTransformerPlugin struct {
|
||||
// Value is the value to add.
|
||||
// Defaults to base name of encompassing kustomization root.
|
||||
Value string `json:"value,omitempty" yaml:"value,omitempty"`
|
||||
|
||||
// Targets is a slice of targets that should have the value added.
|
||||
Targets []Target `json:"targets,omitempty" yaml:"targets,omitempty"`
|
||||
|
||||
// TargetFilePath is a file path. If specified, the file will be parsed into
|
||||
// a slice of Target, and appended to anything that was specified in the
|
||||
// Targets field. This is just a means to share common target specifications.
|
||||
TargetFilePath string `json:"targetFilePath,omitempty" yaml:"targetFilePath,omitempty"`
|
||||
}
|
||||
|
||||
// Target describes where to put the value.
|
||||
type Target struct {
|
||||
// Selector selects the resources to modify.
|
||||
Selector *types.Selector `json:"selector,omitempty" yaml:"selector,omitempty"`
|
||||
|
||||
// NotSelector selects the resources to exclude
|
||||
// from those included by overly broad selectors.
|
||||
// TODO: implement this?
|
||||
// NotSelector *types.Selector `json:"notSelector,omitempty" yaml:"notSelector,omitempty"`
|
||||
|
||||
// FieldPath is a JSON-style path to the field intended to hold the value.
|
||||
FieldPath string `json:"fieldPath,omitempty" yaml:"fieldPath,omitempty"`
|
||||
|
||||
// FilePathPosition is passed to the filter directly. Look there for doc.
|
||||
FilePathPosition int `json:"filePathPosition,omitempty" yaml:"filePathPosition,omitempty"`
|
||||
}
|
||||
|
||||
func (p *ValueAddTransformerPlugin) Config(h *resmap.PluginHelpers, c []byte) error {
|
||||
err := yaml.Unmarshal(c, p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.Value = strings.TrimSpace(p.Value)
|
||||
if p.Value == "" {
|
||||
p.Value = filepath.Base(h.Loader().Root())
|
||||
}
|
||||
if p.TargetFilePath != "" {
|
||||
bytes, err := h.Loader().Load(p.TargetFilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var targets struct {
|
||||
Targets []Target `json:"targets,omitempty" yaml:"targets,omitempty"`
|
||||
}
|
||||
err = yaml.Unmarshal(bytes, &targets)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.Targets = append(p.Targets, targets.Targets...)
|
||||
}
|
||||
if len(p.Targets) == 0 {
|
||||
return fmt.Errorf("must specify at least one target")
|
||||
}
|
||||
for _, target := range p.Targets {
|
||||
if err = validateSelector(target.Selector); err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO: call validateSelector(target.NotSelector) if field added.
|
||||
if err = validateJsonFieldPath(target.FieldPath); err != nil {
|
||||
return err
|
||||
}
|
||||
if target.FilePathPosition < 0 {
|
||||
return fmt.Errorf(
|
||||
"value of FilePathPosition (%d) cannot be negative",
|
||||
target.FilePathPosition)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: implement
|
||||
func validateSelector(_ *types.Selector) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: Enforce RFC 6902?
|
||||
func validateJsonFieldPath(p string) error {
|
||||
if len(p) == 0 {
|
||||
return fmt.Errorf("fieldPath cannot be empty")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *ValueAddTransformerPlugin) Transform(m resmap.ResMap) (err error) {
|
||||
for _, t := range p.Targets {
|
||||
var resources []*resource.Resource
|
||||
if t.Selector == nil {
|
||||
resources = m.Resources()
|
||||
} else {
|
||||
resources, err = m.Select(*t.Selector)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// TODO: consider t.NotSelector if implemented
|
||||
for _, res := range resources {
|
||||
if t.FieldPath == types.MetadataNamespacePath {
|
||||
err = filtersutil.ApplyToJSON(namespace.Filter{
|
||||
Namespace: p.Value,
|
||||
}, res.Kunstructured)
|
||||
} else {
|
||||
err = filtersutil.ApplyToJSON(valueadd.Filter{
|
||||
Value: p.Value,
|
||||
FieldPath: t.FieldPath,
|
||||
FilePathPosition: t.FilePathPosition,
|
||||
}, res.Kunstructured)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewValueAddTransformerPlugin() resmap.TransformerPlugin {
|
||||
return &ValueAddTransformerPlugin{}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package builtins holds code generated from the builtin plugins.
|
||||
// The "builtin" plugins are written as normal plugins and can
|
||||
// be used as such, but they are also used to generate the code
|
||||
// in this package so they can be statically linked to client code.
|
||||
package builtins
|
||||
@@ -1,15 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package filesys
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// File groups the basic os.File methods.
|
||||
type File interface {
|
||||
io.ReadWriteCloser
|
||||
Stat() (os.FileInfo, error)
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package filesys
|
||||
|
||||
import (
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
var _ os.FileInfo = fileInfo{}
|
||||
|
||||
// fileInfo implements os.FileInfo for a fileInMemory instance.
|
||||
type fileInfo struct {
|
||||
node *fsNode
|
||||
}
|
||||
|
||||
// Name returns the name of the file
|
||||
func (fi fileInfo) Name() string { return fi.node.Name() }
|
||||
|
||||
// Size returns the size of the file
|
||||
func (fi fileInfo) Size() int64 { return fi.node.Size() }
|
||||
|
||||
// Mode returns the file mode
|
||||
func (fi fileInfo) Mode() os.FileMode { return 0777 }
|
||||
|
||||
// ModTime returns a bogus time
|
||||
func (fi fileInfo) ModTime() time.Time { return time.Time{} }
|
||||
|
||||
// IsDir returns true if it is a directory
|
||||
func (fi fileInfo) IsDir() bool { return fi.node.isNodeADir() }
|
||||
|
||||
// Sys should return underlying data source, but it now returns nil
|
||||
func (fi fileInfo) Sys() interface{} { return nil }
|
||||
@@ -1,557 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package filesys
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var _ File = &fsNode{}
|
||||
var _ FileSystem = &fsNode{}
|
||||
|
||||
// fsNode is either a file or a directory.
|
||||
type fsNode struct {
|
||||
// What node owns me?
|
||||
parent *fsNode
|
||||
|
||||
// Value to return as the Name() when the
|
||||
// parent is nil.
|
||||
nilParentName string
|
||||
|
||||
// A directory mapping names to nodes.
|
||||
// If dir is nil, then self node is a file.
|
||||
// If dir is non-nil, then self node is a directory,
|
||||
// albeit possibly an empty directory.
|
||||
dir map[string]*fsNode
|
||||
|
||||
// if this node is a file, this is the content.
|
||||
content []byte
|
||||
|
||||
// if this node is a file, this tracks whether or
|
||||
// not it is "open".
|
||||
open bool
|
||||
}
|
||||
|
||||
// MakeEmptyDirInMemory returns an empty directory.
|
||||
// The paths of nodes in this object will never
|
||||
// report a leading Separator, meaning they
|
||||
// aren't "absolute" in the sense defined by
|
||||
// https://golang.org/pkg/path/filepath/#IsAbs.
|
||||
func MakeEmptyDirInMemory() *fsNode {
|
||||
return &fsNode{
|
||||
dir: make(map[string]*fsNode),
|
||||
}
|
||||
}
|
||||
|
||||
// MakeFsInMemory returns an empty 'file system'.
|
||||
// The paths of nodes in this object will always
|
||||
// report a leading Separator, meaning they
|
||||
// are "absolute" in the sense defined by
|
||||
// https://golang.org/pkg/path/filepath/#IsAbs.
|
||||
// This is a relevant difference when using Walk,
|
||||
// Glob, Match, etc.
|
||||
func MakeFsInMemory() FileSystem {
|
||||
return &fsNode{
|
||||
nilParentName: Separator,
|
||||
dir: make(map[string]*fsNode),
|
||||
}
|
||||
}
|
||||
|
||||
// Name returns the name of the node.
|
||||
func (n *fsNode) Name() string {
|
||||
if n.parent == nil {
|
||||
// Unable to lookup name in parent.
|
||||
return n.nilParentName
|
||||
}
|
||||
if !n.parent.isNodeADir() {
|
||||
log.Fatal("parent not a dir")
|
||||
}
|
||||
for key, value := range n.parent.dir {
|
||||
if value == n {
|
||||
return key
|
||||
}
|
||||
}
|
||||
log.Fatal("unable to find fsNode name")
|
||||
return ""
|
||||
}
|
||||
|
||||
// Path returns the full path to the node.
|
||||
func (n *fsNode) Path() string {
|
||||
if n.parent == nil {
|
||||
return n.nilParentName
|
||||
}
|
||||
if !n.parent.isNodeADir() {
|
||||
log.Fatal("parent not a dir, structural error")
|
||||
}
|
||||
return filepath.Join(n.parent.Path(), n.Name())
|
||||
}
|
||||
|
||||
// mySplit trims trailing separators from the directory
|
||||
// result of filepath.Split.
|
||||
func mySplit(s string) (string, string) {
|
||||
dName, fName := filepath.Split(s)
|
||||
return StripTrailingSeps(dName), fName
|
||||
}
|
||||
|
||||
func (n *fsNode) addFile(name string, c []byte) (result *fsNode, err error) {
|
||||
parent := n
|
||||
dName, fileName := mySplit(name)
|
||||
if dName != "" {
|
||||
parent, err = parent.addDir(dName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if !isLegalFileNameForCreation(fileName) {
|
||||
return nil, fmt.Errorf(
|
||||
"illegal name '%s' in file creation", fileName)
|
||||
}
|
||||
result, ok := parent.dir[fileName]
|
||||
if ok {
|
||||
// File already exists; overwrite it.
|
||||
result.content = c
|
||||
return result, nil
|
||||
}
|
||||
result = &fsNode{
|
||||
content: c,
|
||||
parent: parent,
|
||||
}
|
||||
parent.dir[fileName] = result
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Create implements FileSystem.
|
||||
// Create makes an empty file.
|
||||
func (n *fsNode) Create(path string) (result File, err error) {
|
||||
return n.AddFile(path, []byte{})
|
||||
}
|
||||
|
||||
// WriteFile implements FileSystem.
|
||||
func (n *fsNode) WriteFile(path string, d []byte) error {
|
||||
_, err := n.AddFile(path, d)
|
||||
return err
|
||||
}
|
||||
|
||||
// AddFile adds a file and any necessary containing
|
||||
// directories to the node.
|
||||
func (n *fsNode) AddFile(
|
||||
name string, c []byte) (result *fsNode, err error) {
|
||||
if n.dir == nil {
|
||||
return nil, fmt.Errorf(
|
||||
"cannot add a file to a non-directory '%s'", n.Name())
|
||||
}
|
||||
return n.addFile(cleanQueryPath(name), c)
|
||||
}
|
||||
|
||||
func (n *fsNode) addDir(path string) (result *fsNode, err error) {
|
||||
parent := n
|
||||
dName, subDirName := mySplit(path)
|
||||
if dName != "" {
|
||||
parent, err = n.addDir(dName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
switch subDirName {
|
||||
case "", SelfDir:
|
||||
return n, nil
|
||||
case ParentDir:
|
||||
if n.parent == nil {
|
||||
return nil, fmt.Errorf(
|
||||
"cannot add a directory above '%s'", n.Path())
|
||||
}
|
||||
return n.parent, nil
|
||||
default:
|
||||
if !isLegalFileNameForCreation(subDirName) {
|
||||
return nil, fmt.Errorf(
|
||||
"illegal name '%s' in directory creation", subDirName)
|
||||
}
|
||||
result, ok := parent.dir[subDirName]
|
||||
if ok {
|
||||
if result.isNodeADir() {
|
||||
// it's already there.
|
||||
return result, nil
|
||||
}
|
||||
return nil, fmt.Errorf(
|
||||
"cannot make dir '%s'; a file of that name already exists in '%s'",
|
||||
subDirName, parent.Name())
|
||||
}
|
||||
result = &fsNode{
|
||||
dir: make(map[string]*fsNode),
|
||||
parent: parent,
|
||||
}
|
||||
parent.dir[subDirName] = result
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Mkdir implements FileSystem.
|
||||
// Mkdir creates a directory.
|
||||
func (n *fsNode) Mkdir(path string) error {
|
||||
_, err := n.AddDir(path)
|
||||
return err
|
||||
}
|
||||
|
||||
// MkdirAll implements FileSystem.
|
||||
// MkdirAll creates a directory.
|
||||
func (n *fsNode) MkdirAll(path string) error {
|
||||
_, err := n.AddDir(path)
|
||||
return err
|
||||
}
|
||||
|
||||
// AddDir adds a directory to the node, not complaining
|
||||
// if it is already there.
|
||||
func (n *fsNode) AddDir(path string) (result *fsNode, err error) {
|
||||
if n.dir == nil {
|
||||
return nil, fmt.Errorf(
|
||||
"cannot add a directory to file node '%s'", n.Name())
|
||||
}
|
||||
return n.addDir(cleanQueryPath(path))
|
||||
}
|
||||
|
||||
// CleanedAbs implements FileSystem.
|
||||
func (n *fsNode) CleanedAbs(path string) (ConfirmedDir, string, error) {
|
||||
node, err := n.Find(path)
|
||||
if err != nil {
|
||||
return "", "", errors.Wrap(err, "unable to clean")
|
||||
}
|
||||
if node == nil {
|
||||
return "", "", fmt.Errorf("'%s' doesn't exist", path)
|
||||
}
|
||||
if node.isNodeADir() {
|
||||
return ConfirmedDir(node.Path()), "", nil
|
||||
}
|
||||
return ConfirmedDir(node.parent.Path()), node.Name(), nil
|
||||
}
|
||||
|
||||
// Exists implements FileSystem.
|
||||
// Exists returns true if the path exists.
|
||||
func (n *fsNode) Exists(path string) bool {
|
||||
if !n.isNodeADir() {
|
||||
return n.Name() == path
|
||||
}
|
||||
result, err := n.Find(path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return result != nil
|
||||
}
|
||||
|
||||
func cleanQueryPath(path string) string {
|
||||
// Always ignore leading separator?
|
||||
// Remember that filepath.Clean returns "." if
|
||||
// given an empty string argument.
|
||||
return filepath.Clean(StripLeadingSeps(path))
|
||||
}
|
||||
|
||||
// Find finds the given node, else nil if not found.
|
||||
// Return error on structural/argument errors.
|
||||
func (n *fsNode) Find(path string) (*fsNode, error) {
|
||||
if !n.isNodeADir() {
|
||||
return nil, fmt.Errorf("can only find inside a dir")
|
||||
}
|
||||
if path == "" {
|
||||
// Special case; check *before* cleaning and *before*
|
||||
// comparison to nilParentName.
|
||||
return nil, nil
|
||||
}
|
||||
if (n.parent == nil && path == n.nilParentName) || path == SelfDir {
|
||||
// Special case
|
||||
return n, nil
|
||||
}
|
||||
return n.findIt(cleanQueryPath(path))
|
||||
}
|
||||
|
||||
func (n *fsNode) findIt(path string) (result *fsNode, err error) {
|
||||
parent := n
|
||||
dName, item := mySplit(path)
|
||||
if dName != "" {
|
||||
parent, err = n.findIt(dName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if parent == nil {
|
||||
// all done, target doesn't exist.
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
if !parent.isNodeADir() {
|
||||
return nil, fmt.Errorf("'%s' is not a directory", parent.Path())
|
||||
}
|
||||
return parent.dir[item], nil
|
||||
}
|
||||
|
||||
// RemoveAll implements FileSystem.
|
||||
// RemoveAll removes an item and everything it contains.
|
||||
func (n *fsNode) RemoveAll(path string) error {
|
||||
result, err := n.Find(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if result == nil {
|
||||
return fmt.Errorf("cannot find '%s' to remove it", path)
|
||||
}
|
||||
return result.Remove()
|
||||
}
|
||||
|
||||
// Remove drop the node, and everything it contains, from its parent.
|
||||
func (n *fsNode) Remove() error {
|
||||
if n.parent == nil {
|
||||
return fmt.Errorf("cannot remove a root node")
|
||||
}
|
||||
if !n.parent.isNodeADir() {
|
||||
log.Fatal("parent not a dir")
|
||||
}
|
||||
for key, value := range n.parent.dir {
|
||||
if value == n {
|
||||
delete(n.parent.dir, key)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
log.Fatal("unable to find self in parent")
|
||||
return nil
|
||||
}
|
||||
|
||||
// isNodeADir returns true if the node is a directory.
|
||||
// Cannot collide with the poorly named "IsDir".
|
||||
func (n *fsNode) isNodeADir() bool {
|
||||
return n.dir != nil
|
||||
}
|
||||
|
||||
// IsDir implements FileSystem.
|
||||
// IsDir returns true if the argument resolves
|
||||
// to a directory rooted at the node.
|
||||
func (n *fsNode) IsDir(path string) bool {
|
||||
result, err := n.Find(path)
|
||||
if err != nil || result == nil {
|
||||
return false
|
||||
}
|
||||
return result.isNodeADir()
|
||||
}
|
||||
|
||||
// Size returns the size of the node.
|
||||
func (n *fsNode) Size() int64 {
|
||||
if n.isNodeADir() {
|
||||
return int64(len(n.dir))
|
||||
}
|
||||
return int64(len(n.content))
|
||||
}
|
||||
|
||||
// Open implements FileSystem.
|
||||
// Open opens the node for reading (just marks it).
|
||||
func (n *fsNode) Open(path string) (File, error) {
|
||||
result, err := n.Find(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if result == nil {
|
||||
return nil, fmt.Errorf("cannot find '%s' to open it", path)
|
||||
}
|
||||
result.open = true
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Close marks the node closed.
|
||||
func (n *fsNode) Close() error {
|
||||
n.open = false
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadFile implements FileSystem.
|
||||
func (n *fsNode) ReadFile(path string) (c []byte, err error) {
|
||||
result, err := n.Find(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if result == nil {
|
||||
return nil, fmt.Errorf("cannot find '%s' to read it", path)
|
||||
}
|
||||
c = make([]byte, len(result.content))
|
||||
_, err = result.Read(c)
|
||||
return c, err
|
||||
}
|
||||
|
||||
// Read returns the content of the file node.
|
||||
func (n *fsNode) Read(d []byte) (c int, err error) {
|
||||
if n.isNodeADir() {
|
||||
return 0, fmt.Errorf(
|
||||
"cannot read content from non-file '%s'", n.Path())
|
||||
}
|
||||
return copy(d, n.content), nil
|
||||
}
|
||||
|
||||
// Write saves the contents of the argument to the file node.
|
||||
func (n *fsNode) Write(p []byte) (c int, err error) {
|
||||
if n.isNodeADir() {
|
||||
return 0, fmt.Errorf(
|
||||
"cannot write content to non-file '%s'", n.Path())
|
||||
}
|
||||
n.content = make([]byte, len(p))
|
||||
return copy(n.content, p), nil
|
||||
}
|
||||
|
||||
// ContentMatches returns true if v matches fake file's content.
|
||||
func (n *fsNode) ContentMatches(v []byte) bool {
|
||||
return bytes.Equal(v, n.content)
|
||||
}
|
||||
|
||||
// GetContent the content of a fake file.
|
||||
func (n *fsNode) GetContent() []byte {
|
||||
return n.content
|
||||
}
|
||||
|
||||
// Stat returns an instance of FileInfo.
|
||||
func (n *fsNode) Stat() (os.FileInfo, error) {
|
||||
return fileInfo{node: n}, nil
|
||||
}
|
||||
|
||||
// Walk implements FileSystem.
|
||||
func (n *fsNode) Walk(path string, walkFn filepath.WalkFunc) error {
|
||||
result, err := n.Find(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if result == nil {
|
||||
return fmt.Errorf("cannot find '%s' to walk it", path)
|
||||
}
|
||||
return result.WalkMe(walkFn)
|
||||
}
|
||||
|
||||
// Walk runs the given walkFn on each node.
|
||||
func (n *fsNode) WalkMe(walkFn filepath.WalkFunc) error {
|
||||
fi, err := n.Stat()
|
||||
// always visit self first
|
||||
err = walkFn(n.Path(), fi, err)
|
||||
if !n.isNodeADir() {
|
||||
// it's a file, so nothing more to do
|
||||
return err
|
||||
}
|
||||
// process self as a directory
|
||||
if err == filepath.SkipDir {
|
||||
return nil
|
||||
}
|
||||
// Walk is supposed to visit in lexical order.
|
||||
for _, k := range n.sortedDirEntries() {
|
||||
if err := n.dir[k].WalkMe(walkFn); err != nil {
|
||||
if err == filepath.SkipDir {
|
||||
// stop processing this directory
|
||||
break
|
||||
}
|
||||
// bail out completely
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *fsNode) sortedDirEntries() []string {
|
||||
keys := make([]string, len(n.dir))
|
||||
i := 0
|
||||
for k := range n.dir {
|
||||
keys[i] = k
|
||||
i++
|
||||
}
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
||||
|
||||
// FileCount returns a count of files.
|
||||
// Directories, empty or otherwise, not counted.
|
||||
func (n *fsNode) FileCount() int {
|
||||
count := 0
|
||||
n.WalkMe(func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !info.IsDir() {
|
||||
count++
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return count
|
||||
}
|
||||
|
||||
func (n *fsNode) DebugPrint() {
|
||||
n.WalkMe(func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
fmt.Printf("err '%v' at path %q\n", err, path)
|
||||
return nil
|
||||
}
|
||||
if info.IsDir() {
|
||||
if info.Size() == 0 {
|
||||
fmt.Println("empty dir: " + path)
|
||||
}
|
||||
} else {
|
||||
fmt.Println(" file: " + path)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
var legalFileNamePattern = regexp.MustCompile("^[a-zA-Z0-9-_.]+$")
|
||||
|
||||
// This rules enforced here should be simpler and tighter
|
||||
// than what's allowed on a real OS.
|
||||
// Should be fine for testing or in-memory purposes.
|
||||
func isLegalFileNameForCreation(n string) bool {
|
||||
if n == "" || n == SelfDir || !legalFileNamePattern.MatchString(n) {
|
||||
return false
|
||||
}
|
||||
return !strings.Contains(n, ParentDir)
|
||||
}
|
||||
|
||||
// RegExpGlob returns a list of file paths matching the regexp.
|
||||
// Excludes directories.
|
||||
func (n *fsNode) RegExpGlob(pattern string) ([]string, error) {
|
||||
var result []string
|
||||
var expression = regexp.MustCompile(pattern)
|
||||
n.WalkMe(func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !info.IsDir() {
|
||||
if expression.MatchString(path) {
|
||||
result = append(result, path)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
sort.Strings(result)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Glob implements FileSystem.
|
||||
// Glob returns the list of file paths matching
|
||||
// per filepath.Match semantics, i.e. unlike RegExpGlob,
|
||||
// Match("foo/a*") will not match sub-sub directories of foo.
|
||||
// This is how /bin/ls behaves.
|
||||
func (n *fsNode) Glob(pattern string) ([]string, error) {
|
||||
var result []string
|
||||
n.WalkMe(func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !info.IsDir() {
|
||||
match, err := filepath.Match(pattern, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if match {
|
||||
result = append(result, path)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
sort.Strings(result)
|
||||
return result, nil
|
||||
}
|
||||
@@ -1,788 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package filesys
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const content = `
|
||||
Lorem ipsum dolor sit amet,
|
||||
consectetur adipiscing elit,
|
||||
sed do eiusmod tempor incididunt
|
||||
ut labore et dolore magna aliqua.
|
||||
`
|
||||
const shortContent = "hi"
|
||||
|
||||
var topCases = []pathCase{
|
||||
{
|
||||
what: "dotdot",
|
||||
arg: ParentDir,
|
||||
errStr: "illegal name '..' in file creation",
|
||||
},
|
||||
{
|
||||
what: "empty",
|
||||
arg: "",
|
||||
name: "",
|
||||
errStr: "illegal name '.' in file creation",
|
||||
},
|
||||
{
|
||||
what: "simple",
|
||||
arg: "bob",
|
||||
name: "bob",
|
||||
path: "bob",
|
||||
},
|
||||
{
|
||||
what: "longer",
|
||||
arg: filepath.Join("longer", "bob"),
|
||||
name: "bob",
|
||||
path: filepath.Join("longer", "bob"),
|
||||
},
|
||||
{
|
||||
what: "longer yet",
|
||||
arg: filepath.Join("longer", "foo", "bar", "beans", "bob"),
|
||||
name: "bob",
|
||||
path: filepath.Join("longer", "foo", "bar", "beans", "bob"),
|
||||
},
|
||||
{
|
||||
what: "tricky",
|
||||
arg: filepath.Join("bob", ParentDir, "sally"),
|
||||
name: "sally",
|
||||
path: "sally",
|
||||
},
|
||||
{
|
||||
what: "trickier",
|
||||
arg: filepath.Join("bob", "sally", ParentDir, ParentDir, "jean"),
|
||||
name: "jean",
|
||||
path: "jean",
|
||||
},
|
||||
}
|
||||
|
||||
func TestMakeEmptyDirInMemory(t *testing.T) {
|
||||
n := MakeEmptyDirInMemory()
|
||||
if !n.isNodeADir() {
|
||||
t.Fatalf("not a directory")
|
||||
}
|
||||
if n.Size() != 0 {
|
||||
t.Fatalf("unexpected size %d", n.Size())
|
||||
}
|
||||
if n.Name() != "" {
|
||||
t.Fatalf("unexpected name '%s'", n.Name())
|
||||
}
|
||||
if n.Path() != "" {
|
||||
t.Fatalf("unexpected path '%s'", n.Path())
|
||||
}
|
||||
runBasicOperations(
|
||||
t, "MakeEmptyDirInMemory", false, topCases, n)
|
||||
}
|
||||
|
||||
func TestMakeFsInMemory(t *testing.T) {
|
||||
runBasicOperations(
|
||||
t, "MakeFsInMemory", true, topCases, MakeFsInMemory())
|
||||
}
|
||||
|
||||
//nolint:gocyclo
|
||||
func runBasicOperations(
|
||||
t *testing.T, tName string, isFSysRooted bool,
|
||||
cases []pathCase, fSys FileSystem) {
|
||||
buff := make([]byte, 500)
|
||||
for _, c := range cases {
|
||||
err := fSys.WriteFile(c.arg, []byte(content))
|
||||
if c.errStr != "" {
|
||||
if err == nil {
|
||||
t.Fatalf("%s; expected error writing to '%s'!", c.what, c.arg)
|
||||
}
|
||||
if !strings.Contains(err.Error(), c.errStr) {
|
||||
t.Fatalf("%s; expected err containing '%s', got '%v'",
|
||||
c.what, c.errStr, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("%s; unexpected error: %v", c.what, err)
|
||||
}
|
||||
if !fSys.Exists(c.path) {
|
||||
t.Fatalf("%s; expect existence of '%s'", c.what, c.path)
|
||||
}
|
||||
stuff, err := fSys.ReadFile(c.path)
|
||||
if err != nil {
|
||||
t.Fatalf("%s; unexpected error: %v", c.what, err)
|
||||
}
|
||||
if string(stuff) != content {
|
||||
t.Fatalf("%s; unexpected content '%s'", c.what, stuff)
|
||||
}
|
||||
f, err := fSys.Open(c.arg)
|
||||
if err != nil {
|
||||
t.Fatalf("%s; unexpected error: %v", c.what, err)
|
||||
}
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
t.Fatalf("%s; unexpected error: %v", c.what, err)
|
||||
}
|
||||
if fi.Name() != c.name {
|
||||
t.Fatalf("%s; expected name '%s', got '%s'", c.what, c.name, fi.Name())
|
||||
}
|
||||
count, err := f.Read(buff)
|
||||
if err != nil {
|
||||
t.Fatalf("%s; unexpected error: %v", c.what, err)
|
||||
}
|
||||
if string(buff[:count]) != content {
|
||||
t.Fatalf("%s; unexpected buff '%s'", c.what, buff)
|
||||
}
|
||||
count, err = f.Write([]byte(shortContent))
|
||||
if err != nil {
|
||||
t.Fatalf("%s; unexpected error: %v", c.what, err)
|
||||
}
|
||||
if count != len(shortContent) {
|
||||
t.Fatalf("%s; unexpected count: %d", c.what, len(shortContent))
|
||||
}
|
||||
stuff, err = fSys.ReadFile(c.path)
|
||||
if err != nil {
|
||||
t.Fatalf("%s; unexpected error: %v", c.what, err)
|
||||
}
|
||||
if string(stuff) != shortContent {
|
||||
t.Fatalf("%s; unexpected content '%s'", c.what, stuff)
|
||||
}
|
||||
}
|
||||
|
||||
var actualPaths []string
|
||||
var err error
|
||||
prefix := ""
|
||||
{
|
||||
root := SelfDir
|
||||
if isFSysRooted {
|
||||
root = Separator
|
||||
prefix = Separator
|
||||
}
|
||||
err = fSys.Walk(root, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
fmt.Printf("err '%v' at path %q\n", err, path)
|
||||
return nil
|
||||
}
|
||||
if !info.IsDir() {
|
||||
actualPaths = append(actualPaths, path)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
var expectedPaths []string
|
||||
for _, c := range cases {
|
||||
if c.errStr == "" {
|
||||
expectedPaths = append(expectedPaths, prefix+c.path)
|
||||
}
|
||||
}
|
||||
sort.Strings(expectedPaths)
|
||||
assertEqualStringSlices(t, expectedPaths, actualPaths, tName)
|
||||
}
|
||||
|
||||
type pathCase struct {
|
||||
what string
|
||||
arg string
|
||||
name string
|
||||
path string
|
||||
errStr string
|
||||
}
|
||||
|
||||
func TestAddDir(t *testing.T) {
|
||||
cases := []pathCase{
|
||||
{
|
||||
what: "dotdot",
|
||||
arg: ParentDir,
|
||||
errStr: "cannot add a directory above ''",
|
||||
},
|
||||
{
|
||||
what: "empty",
|
||||
arg: "",
|
||||
name: "",
|
||||
path: "",
|
||||
},
|
||||
{
|
||||
what: "simple",
|
||||
arg: "bob",
|
||||
name: "bob",
|
||||
path: "bob",
|
||||
},
|
||||
{
|
||||
what: "longer",
|
||||
arg: filepath.Join("longer", "bob"),
|
||||
name: "bob",
|
||||
path: filepath.Join("longer", "bob"),
|
||||
},
|
||||
{
|
||||
what: "longer yet",
|
||||
arg: filepath.Join("longer", "foo", "bar", "beans", "bob"),
|
||||
name: "bob",
|
||||
path: filepath.Join("longer", "foo", "bar", "beans", "bob"),
|
||||
},
|
||||
{
|
||||
what: "tricky",
|
||||
arg: filepath.Join("bob", ParentDir, "sally"),
|
||||
name: "sally",
|
||||
path: "sally",
|
||||
},
|
||||
{
|
||||
what: "trickier",
|
||||
arg: filepath.Join("bob", "sally", ParentDir, ParentDir, "jean"),
|
||||
name: "jean",
|
||||
path: "jean",
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
n := MakeEmptyDirInMemory()
|
||||
f, err := n.AddDir(c.arg)
|
||||
if c.errStr != "" {
|
||||
if err == nil {
|
||||
t.Fatalf("%s; expected error!", c.what)
|
||||
}
|
||||
if !strings.Contains(err.Error(), c.errStr) {
|
||||
t.Fatalf(
|
||||
"%s; expected error with '%s', got '%v'",
|
||||
c.what, c.errStr, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("%s; unexpected error: %v", c.what, err)
|
||||
}
|
||||
checkNode(t, c.what, f, c.name, 0, true, c.path)
|
||||
checkOsStat(t, c.what, f, f.Name(), 0, true)
|
||||
}
|
||||
}
|
||||
|
||||
var bagOfCases = []pathCase{
|
||||
{
|
||||
what: "empty",
|
||||
arg: "",
|
||||
errStr: "illegal name '.' in file creation",
|
||||
},
|
||||
{
|
||||
what: "simple",
|
||||
arg: "bob",
|
||||
name: "bob",
|
||||
path: "bob",
|
||||
},
|
||||
{
|
||||
what: "longer",
|
||||
arg: filepath.Join("longer", "bob"),
|
||||
name: "bob",
|
||||
path: filepath.Join("longer", "bob"),
|
||||
},
|
||||
{
|
||||
what: "longer",
|
||||
arg: filepath.Join("longer", "sally"),
|
||||
name: "sally",
|
||||
path: filepath.Join("longer", "sally"),
|
||||
},
|
||||
{
|
||||
what: "even longer",
|
||||
arg: filepath.Join("longer", "than", "the", "other", "bob"),
|
||||
name: "bob",
|
||||
path: filepath.Join("longer", "than", "the", "other", "bob"),
|
||||
},
|
||||
{
|
||||
what: "even longer",
|
||||
arg: filepath.Join("even", "much", "longer", "than", "the", "other", "bob"),
|
||||
name: "bob",
|
||||
path: filepath.Join("even", "much", "longer", "than", "the", "other", "bob"),
|
||||
},
|
||||
}
|
||||
|
||||
func TestAddFile(t *testing.T) {
|
||||
n := MakeEmptyDirInMemory()
|
||||
if n.FileCount() != 0 {
|
||||
t.Fatalf("expected no files, got %d", n.FileCount())
|
||||
}
|
||||
expectedFileCount := 0
|
||||
for _, c := range bagOfCases {
|
||||
f, err := n.AddFile(c.arg, []byte(content))
|
||||
if c.errStr != "" {
|
||||
if err == nil {
|
||||
t.Fatalf("%s; expected error!", c.what)
|
||||
}
|
||||
if !strings.Contains(err.Error(), c.errStr) {
|
||||
t.Fatalf("%s; expected err containing '%s', got '%v'",
|
||||
c.what, c.errStr, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("%s; unexpected error %v", c.what, err)
|
||||
}
|
||||
checkNode(t, c.what, f, c.name, len(content), false, c.path)
|
||||
checkOsStat(t, c.what, f, f.Name(), len(content), false)
|
||||
|
||||
result, err := n.Find(c.arg)
|
||||
if err != nil {
|
||||
t.Fatalf("%s; unexpected find error %v", c.what, err)
|
||||
}
|
||||
if result != f {
|
||||
t.Fatalf("%s; unexpected find result %v", c.what, result)
|
||||
}
|
||||
|
||||
result, err = n.Find(filepath.Join("longer", "bogus"))
|
||||
if err != nil {
|
||||
t.Fatalf("%s; unexpected find error %v", c.what, err)
|
||||
}
|
||||
if result != nil {
|
||||
t.Fatalf("%s; unexpected find result %v", c.what, result)
|
||||
}
|
||||
|
||||
expectedFileCount++
|
||||
fc := n.FileCount()
|
||||
if fc != expectedFileCount {
|
||||
t.Fatalf("expected file count %d, got %d",
|
||||
expectedFileCount, fc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func checkNode(
|
||||
t *testing.T, what string, f *fsNode, name string,
|
||||
size int, isDir bool, path string) {
|
||||
if f.isNodeADir() != isDir {
|
||||
t.Fatalf("%s; unexpected isNodeADir = %v", what, f.isNodeADir())
|
||||
}
|
||||
if f.Size() != int64(size) {
|
||||
t.Fatalf("%s; unexpected size %d", what, f.Size())
|
||||
}
|
||||
if name != f.Name() {
|
||||
t.Fatalf("%s; expected name '%s', got '%s'", what, name, f.Name())
|
||||
}
|
||||
if path != f.Path() {
|
||||
t.Fatalf("%s; expected path '%s', got '%s'", what, path, f.Path())
|
||||
}
|
||||
}
|
||||
|
||||
func checkOsStat(
|
||||
t *testing.T, what string, f File, name string,
|
||||
size int, isDir bool) {
|
||||
info, err := f.Stat()
|
||||
if err != nil {
|
||||
t.Fatalf("%s; unexpected stat error %v", what, err)
|
||||
}
|
||||
if info.IsDir() != isDir {
|
||||
t.Fatalf("%s; unexpected info.isNodeADir = %v", what, info.IsDir())
|
||||
}
|
||||
if info.Size() != int64(size) {
|
||||
t.Fatalf("%s; unexpected info.size %d", what, info.Size())
|
||||
}
|
||||
if info.Name() != name {
|
||||
t.Fatalf("%s; expected name '%s', got info.Name '%s'", what, name, info.Name())
|
||||
}
|
||||
}
|
||||
|
||||
var bunchOfFiles = []struct {
|
||||
path string
|
||||
addAsDir bool
|
||||
}{
|
||||
{
|
||||
path: filepath.Join("b", "e", "a", "c", "g"),
|
||||
},
|
||||
{
|
||||
path: filepath.Join("z", "r", "a", "b", "g"),
|
||||
},
|
||||
{
|
||||
path: filepath.Join("b", "q", "a", "c", "g"),
|
||||
},
|
||||
{
|
||||
path: filepath.Join("b", "a", "a", "m", "g"),
|
||||
addAsDir: true,
|
||||
},
|
||||
{
|
||||
path: filepath.Join("b", "w"),
|
||||
},
|
||||
{
|
||||
path: filepath.Join("b", "d", "a", "c", "m"),
|
||||
},
|
||||
{
|
||||
path: filepath.Join("b", "d", "z"),
|
||||
},
|
||||
{
|
||||
path: filepath.Join("b", "d", "y"),
|
||||
},
|
||||
{
|
||||
path: filepath.Join("b", "d", "ignore", "c", "n"),
|
||||
},
|
||||
{
|
||||
path: filepath.Join("b", "d", "x"),
|
||||
},
|
||||
{
|
||||
path: filepath.Join("b", "d", "ignore", "c", "o"),
|
||||
},
|
||||
{
|
||||
path: filepath.Join("b", "d", "ignore", "c", "m"),
|
||||
},
|
||||
{
|
||||
path: filepath.Join("b", "d", "a", "c", "i"),
|
||||
addAsDir: true,
|
||||
},
|
||||
{
|
||||
path: filepath.Join("x"),
|
||||
},
|
||||
{
|
||||
path: filepath.Join("y"),
|
||||
},
|
||||
{
|
||||
path: filepath.Join("b", "d", "a", "c", "i", "beans"),
|
||||
},
|
||||
{
|
||||
path: filepath.Join("b", "d", "a", "c", "r", "w"),
|
||||
addAsDir: true,
|
||||
},
|
||||
{
|
||||
path: filepath.Join("b", "d", "a", "c", "u"),
|
||||
},
|
||||
}
|
||||
|
||||
func makeLoadedFileTree(t *testing.T) *fsNode {
|
||||
n := MakeEmptyDirInMemory()
|
||||
var err error
|
||||
expectedFileCount := 0
|
||||
for _, item := range bunchOfFiles {
|
||||
if item.addAsDir {
|
||||
_, err = n.AddDir(item.path)
|
||||
} else {
|
||||
_, err = n.AddFile(item.path, []byte(content))
|
||||
expectedFileCount++
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
}
|
||||
fc := n.FileCount()
|
||||
if fc != expectedFileCount {
|
||||
t.Fatalf("expected file count %d, got %d",
|
||||
expectedFileCount, fc)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func TestWalkMe(t *testing.T) {
|
||||
n := makeLoadedFileTree(t)
|
||||
var actualPaths []string
|
||||
err := n.WalkMe(func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
fmt.Printf("err '%v' at path %q\n", err, path)
|
||||
return nil
|
||||
}
|
||||
if info.IsDir() {
|
||||
if info.Name() == "ignore" {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
} else {
|
||||
actualPaths = append(actualPaths, path)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
var expectedPaths []string
|
||||
for _, c := range bunchOfFiles {
|
||||
if !c.addAsDir && !strings.Contains(c.path, "ignore") {
|
||||
expectedPaths = append(expectedPaths, c.path)
|
||||
}
|
||||
}
|
||||
sort.Strings(expectedPaths)
|
||||
assertEqualStringSlices(t, expectedPaths, actualPaths, "testWalkMe")
|
||||
}
|
||||
|
||||
func TestRemove(t *testing.T) {
|
||||
n := makeLoadedFileTree(t)
|
||||
orgCount := n.FileCount()
|
||||
|
||||
// Remove the "ignore" directory and everything below it.
|
||||
path := filepath.Join("b", "d", "ignore")
|
||||
result, err := n.Find(path)
|
||||
if err != nil {
|
||||
t.Fatalf("%s; unexpected error %v", path, err)
|
||||
}
|
||||
if result == nil {
|
||||
t.Fatalf("%s; expected to find '%s'", path, path)
|
||||
}
|
||||
if !result.isNodeADir() {
|
||||
t.Fatalf("%s; expected to find a directory", path)
|
||||
}
|
||||
err = result.Remove()
|
||||
if err != nil {
|
||||
t.Fatalf("%s; unable to remove: %v", path, err)
|
||||
}
|
||||
result, err = n.Find(path)
|
||||
if err != nil {
|
||||
// Just because it's gone doesn't mean error.
|
||||
t.Fatalf("%s; unexpected error %v", path, err)
|
||||
}
|
||||
if result != nil {
|
||||
t.Fatalf("%s; should not have been able to find '%s'", path, path)
|
||||
}
|
||||
|
||||
// There were three files below "ignore".
|
||||
orgCount -= 3
|
||||
|
||||
// Now drop one more for a total of four dropped.
|
||||
result, _ = n.Find(filepath.Join("y"))
|
||||
err = result.Remove()
|
||||
if err != nil {
|
||||
t.Fatalf("%s; unable to remove: %v", path, err)
|
||||
}
|
||||
orgCount -= 1
|
||||
|
||||
fc := n.FileCount()
|
||||
if fc != orgCount {
|
||||
t.Fatalf("expected file count %d, got %d",
|
||||
orgCount, fc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExists(t *testing.T) {
|
||||
n := makeLoadedFileTree(t)
|
||||
path := filepath.Join("b", "d", "a")
|
||||
if !n.Exists(path) {
|
||||
t.Fatalf("expected existence at %s", path)
|
||||
}
|
||||
if !n.IsDir(path) {
|
||||
t.Fatalf("expected directory at %s", path)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegExpGlob(t *testing.T) {
|
||||
n := makeLoadedFileTree(t)
|
||||
expected := []string{
|
||||
filepath.Join("b", "d", "a", "c", "i", "beans"),
|
||||
filepath.Join("b", "d", "a", "c", "m"),
|
||||
filepath.Join("b", "d", "a", "c", "u"),
|
||||
filepath.Join("b", "d", "ignore", "c", "m"),
|
||||
filepath.Join("b", "d", "ignore", "c", "n"),
|
||||
filepath.Join("b", "d", "ignore", "c", "o"),
|
||||
filepath.Join("b", "d", "x"),
|
||||
filepath.Join("b", "d", "y"),
|
||||
filepath.Join("b", "d", "z"),
|
||||
}
|
||||
paths, err := n.RegExpGlob("b/d/*")
|
||||
if err != nil {
|
||||
t.Fatalf("glob error: %v", err)
|
||||
}
|
||||
assertEqualStringSlices(t, expected, paths, "glob test")
|
||||
}
|
||||
|
||||
func TestGlob(t *testing.T) {
|
||||
n := makeLoadedFileTree(t)
|
||||
expected := []string{
|
||||
filepath.Join("b", "d", "x"),
|
||||
filepath.Join("b", "d", "y"),
|
||||
filepath.Join("b", "d", "z"),
|
||||
}
|
||||
paths, err := n.Glob("b/d/*")
|
||||
if err != nil {
|
||||
t.Fatalf("glob error: %v", err)
|
||||
}
|
||||
assertEqualStringSlices(t, expected, paths, "glob test")
|
||||
}
|
||||
|
||||
func assertEqualStringSlices(t *testing.T, expected, actual []string, message string) {
|
||||
if len(expected) != len(actual) {
|
||||
t.Fatalf(
|
||||
"%s; unequal sizes; len(expected)=%d, len(actual)=%d\n%+v\n%+v\n",
|
||||
message, len(expected), len(actual), expected, actual)
|
||||
}
|
||||
for i := range expected {
|
||||
if expected[i] != actual[i] {
|
||||
t.Fatalf(
|
||||
"%s; unequal entries; expected=%s, actual=%s",
|
||||
message, expected[i], actual[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFind(t *testing.T) {
|
||||
cases := []struct {
|
||||
what string
|
||||
arg string
|
||||
expectDir bool
|
||||
expectFile bool
|
||||
errStr string
|
||||
}{
|
||||
{
|
||||
what: "garbage",
|
||||
arg: "///1(*&SA",
|
||||
},
|
||||
{
|
||||
what: "simple",
|
||||
arg: "bob",
|
||||
},
|
||||
{
|
||||
what: "no directory",
|
||||
arg: filepath.Join("b", "rrrrrr"),
|
||||
},
|
||||
{
|
||||
what: "is a directory",
|
||||
arg: filepath.Join("b", "d", "ignore"),
|
||||
expectDir: true,
|
||||
},
|
||||
{
|
||||
what: "longer, ending in file",
|
||||
arg: filepath.Join("b", "d", "x"),
|
||||
expectFile: true,
|
||||
},
|
||||
{
|
||||
what: "moar longer, ending in file",
|
||||
arg: filepath.Join("b", "d", "a", "c", "u"),
|
||||
expectFile: true,
|
||||
},
|
||||
{
|
||||
what: "directory",
|
||||
arg: filepath.Join("b"),
|
||||
expectDir: true,
|
||||
},
|
||||
{
|
||||
// Querying for the empty string could
|
||||
// 1) be an error,
|
||||
// 2) return no result (and no error) as with
|
||||
// any illegal and therefore non-existent
|
||||
// file name,
|
||||
// 3) return the node itself, like running
|
||||
// 'ls' with no argument.
|
||||
// Going with option 2 (no result, no error),
|
||||
// since at this low level it makes more sense
|
||||
// if the results for the empty string query
|
||||
// differ from the results for the "." query.
|
||||
what: "empty name",
|
||||
arg: "",
|
||||
},
|
||||
{
|
||||
what: "self dir",
|
||||
arg: SelfDir,
|
||||
expectDir: true,
|
||||
},
|
||||
{
|
||||
what: "parent dir - doesn't exist",
|
||||
arg: ParentDir,
|
||||
},
|
||||
{
|
||||
what: "many parents - doesn't exist",
|
||||
arg: filepath.Join(ParentDir, ParentDir, ParentDir),
|
||||
},
|
||||
}
|
||||
|
||||
n := makeLoadedFileTree(t)
|
||||
for _, item := range cases {
|
||||
result, err := n.Find(item.arg)
|
||||
if item.errStr != "" {
|
||||
if err == nil {
|
||||
t.Fatalf("%s; expected error", item.what)
|
||||
}
|
||||
if !strings.Contains(err.Error(), item.errStr) {
|
||||
t.Fatalf("%s; expected err containing '%s', got '%v'",
|
||||
item.what, item.errStr, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("%s; unexpected error: %v", item.what, err)
|
||||
}
|
||||
if result == nil {
|
||||
if item.expectDir {
|
||||
t.Fatalf(
|
||||
"%s; expected to find directory '%s'", item.what, item.arg)
|
||||
}
|
||||
if item.expectFile {
|
||||
t.Fatalf(
|
||||
"%s; expected to find file '%s'", item.what, item.arg)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if item.expectDir {
|
||||
if !result.isNodeADir() {
|
||||
t.Fatalf(
|
||||
"%s; expected '%s' to be a directory", item.what, item.arg)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if item.expectFile {
|
||||
if result.isNodeADir() {
|
||||
t.Fatalf("%s; expected '%s' to be a file", item.what, item.arg)
|
||||
}
|
||||
continue
|
||||
}
|
||||
t.Fatalf(
|
||||
"%s; expected nothing for '%s', but got '%s'",
|
||||
item.what, item.arg, result.Path())
|
||||
}
|
||||
}
|
||||
|
||||
func TestCleanedAbs(t *testing.T) {
|
||||
cases := []struct {
|
||||
what string
|
||||
full string
|
||||
cDir string
|
||||
name string
|
||||
errStr string
|
||||
}{
|
||||
{
|
||||
what: "empty",
|
||||
full: "",
|
||||
errStr: "doesn't exist",
|
||||
},
|
||||
{
|
||||
what: "simple",
|
||||
full: "bob",
|
||||
errStr: "'bob' doesn't exist",
|
||||
},
|
||||
{
|
||||
what: "no directory",
|
||||
full: filepath.Join("b", "rrrrrr"),
|
||||
errStr: "'b/rrrrrr' doesn't exist",
|
||||
},
|
||||
{
|
||||
what: "longer, ending in file",
|
||||
full: filepath.Join("b", "d", "x"),
|
||||
cDir: filepath.Join("b", "d"),
|
||||
name: "x",
|
||||
},
|
||||
{
|
||||
what: "moar longer, ending in file",
|
||||
full: filepath.Join("b", "d", "a", "c", "u"),
|
||||
cDir: filepath.Join("b", "d", "a", "c"),
|
||||
name: "u",
|
||||
},
|
||||
{
|
||||
what: "directory",
|
||||
full: filepath.Join("b", "d"),
|
||||
cDir: filepath.Join("b", "d"),
|
||||
name: "",
|
||||
},
|
||||
}
|
||||
|
||||
n := makeLoadedFileTree(t)
|
||||
for _, item := range cases {
|
||||
cDir, name, err := n.CleanedAbs(item.full)
|
||||
if item.errStr != "" {
|
||||
if err == nil {
|
||||
t.Fatalf("%s; expected error", item.what)
|
||||
}
|
||||
if !strings.Contains(err.Error(), item.errStr) {
|
||||
t.Fatalf("%s; expected err containing '%s', got '%v'",
|
||||
item.what, item.errStr, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("%s; unexpected error: %v", item.what, err)
|
||||
}
|
||||
if cDir != ConfirmedDir(item.cDir) {
|
||||
t.Fatalf("%s; expected cDir=%s, got '%s'", item.what, item.cDir, cDir)
|
||||
}
|
||||
if name != item.name {
|
||||
t.Fatalf("%s; expected name=%s, got '%s'", item.what, item.name, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package filesys
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// RootedPath returns a rooted path, e.g. "/foo/bar" as
|
||||
// opposed to "foo/bar".
|
||||
func RootedPath(elem ...string) string {
|
||||
return Separator + filepath.Join(elem...)
|
||||
}
|
||||
|
||||
// StripTrailingSeps trims trailing filepath separators from input.
|
||||
func StripTrailingSeps(s string) string {
|
||||
k := len(s)
|
||||
for k > 0 && s[k-1] == filepath.Separator {
|
||||
k--
|
||||
}
|
||||
return s[:k]
|
||||
}
|
||||
|
||||
// StripLeadingSeps trims leading filepath separators from input.
|
||||
func StripLeadingSeps(s string) string {
|
||||
k := 0
|
||||
for k < len(s) && s[k] == filepath.Separator {
|
||||
k++
|
||||
}
|
||||
return s[k:]
|
||||
}
|
||||
|
||||
// PathSplit converts a file path to a slice of string.
|
||||
// If the path is absolute (if the path has a leading slash),
|
||||
// then the first entry in the result is an empty string.
|
||||
// Desired: path == PathJoin(PathSplit(path))
|
||||
func PathSplit(incoming string) []string {
|
||||
if incoming == "" {
|
||||
return []string{}
|
||||
}
|
||||
dir, path := filepath.Split(incoming)
|
||||
if dir == string(os.PathSeparator) {
|
||||
if path == "" {
|
||||
return []string{""}
|
||||
}
|
||||
return []string{"", path}
|
||||
}
|
||||
dir = strings.TrimSuffix(dir, string(os.PathSeparator))
|
||||
if dir == "" {
|
||||
return []string{path}
|
||||
}
|
||||
return append(PathSplit(dir), path)
|
||||
}
|
||||
|
||||
// PathJoin converts a slice of string to a file path.
|
||||
// If the first entry is an empty string, then the returned
|
||||
// path is absolute (it has a leading slash).
|
||||
// Desired: path == PathJoin(PathSplit(path))
|
||||
func PathJoin(incoming []string) string {
|
||||
if len(incoming) == 0 {
|
||||
return ""
|
||||
}
|
||||
if incoming[0] == "" {
|
||||
return string(os.PathSeparator) + filepath.Join(incoming[1:]...)
|
||||
}
|
||||
return filepath.Join(incoming...)
|
||||
}
|
||||
|
||||
// InsertPathPart inserts 'part' at position 'pos' in the given filepath.
|
||||
// The first position is 0.
|
||||
//
|
||||
// E.g. if part == 'PEACH'
|
||||
//
|
||||
// OLD : NEW : POS
|
||||
// --------------------------------------------------------
|
||||
// {empty} : PEACH : irrelevant
|
||||
// / : /PEACH : irrelevant
|
||||
// pie : PEACH/pie : 0 (or negative)
|
||||
// /pie : /PEACH/pie : 0 (or negative)
|
||||
// raw : raw/PEACH : 1 (or larger)
|
||||
// /raw : /raw/PEACH : 1 (or larger)
|
||||
// a/nice/warm/pie : a/nice/warm/PEACH/pie : 3
|
||||
// /a/nice/warm/pie : /a/nice/warm/PEACH/pie : 3
|
||||
//
|
||||
// * An empty part results in no change.
|
||||
//
|
||||
// * Absolute paths get their leading '/' stripped, treated like
|
||||
// relative paths, and the leading '/' is re-added on output.
|
||||
// The meaning of pos is intentionally the same in either absolute or
|
||||
// relative paths; if it weren't, this function could convert absolute
|
||||
// paths to relative paths, which is not desirable.
|
||||
//
|
||||
// * For robustness (liberal input, conservative output) Pos values that
|
||||
// that are too small (large) to index the split filepath result in a
|
||||
// prefix (postfix) rather than an error. Use extreme position values
|
||||
// to assure a prefix or postfix (e.g. 0 will always prefix, and
|
||||
// 9999 will presumably always postfix).
|
||||
func InsertPathPart(path string, pos int, part string) string {
|
||||
if part == "" {
|
||||
return path
|
||||
}
|
||||
parts := PathSplit(path)
|
||||
if pos < 0 {
|
||||
pos = 0
|
||||
} else if pos > len(parts) {
|
||||
pos = len(parts)
|
||||
}
|
||||
if len(parts) > 0 && parts[0] == "" && pos < len(parts) {
|
||||
// An empty string at 0 indicates an absolute path, and means
|
||||
// we must increment pos. This change means that a position
|
||||
// specification has the same meaning in relative and absolute paths.
|
||||
// E.g. in either the path 'a/b/c' or the path '/a/b/c',
|
||||
// 'a' is at 0, 'b' is at 1 and 'c' is at 2, and inserting at
|
||||
// zero means a new first field _without_ changing an absolute
|
||||
// path to a relative path.
|
||||
pos++
|
||||
}
|
||||
result := make([]string, len(parts)+1)
|
||||
copy(result, parts[0:pos])
|
||||
result[pos] = part
|
||||
return PathJoin(append(result, parts[pos:]...))
|
||||
}
|
||||
@@ -1,374 +0,0 @@
|
||||
package filesys_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
. "sigs.k8s.io/kustomize/api/filesys"
|
||||
)
|
||||
|
||||
// Confirm behavior of filepath.Match
|
||||
func TestFilePathMatch(t *testing.T) {
|
||||
cases := []struct {
|
||||
pattern string
|
||||
path string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
pattern: "*e*",
|
||||
path: "hey",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
pattern: "*e*",
|
||||
path: "hay",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
pattern: "*e*",
|
||||
path: filepath.Join("h", "e", "y"),
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
pattern: "*/e/*",
|
||||
path: filepath.Join("h", "e", "y"),
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
pattern: "h/e/*",
|
||||
path: filepath.Join("h", "e", "y"),
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
pattern: "*/e/y",
|
||||
path: filepath.Join("h", "e", "y"),
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
pattern: "*/*/*",
|
||||
path: filepath.Join("h", "e", "y"),
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
pattern: "*/*/*",
|
||||
path: filepath.Join("h", "e", "y", "there"),
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
pattern: "*/*/*/t*e",
|
||||
path: filepath.Join("h", "e", "y", "there"),
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
for _, item := range cases {
|
||||
match, err := filepath.Match(item.pattern, item.path)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected err: %v", err)
|
||||
}
|
||||
if match != item.expected {
|
||||
t.Fatalf("'%s' '%s' %v\n", item.pattern, item.path, match)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Confirm behavior of filepath.Split
|
||||
func TestFilePathSplit(t *testing.T) {
|
||||
cases := []struct {
|
||||
full string
|
||||
dir string
|
||||
file string
|
||||
}{
|
||||
{
|
||||
full: "",
|
||||
dir: "",
|
||||
file: "",
|
||||
},
|
||||
{
|
||||
full: SelfDir,
|
||||
dir: "",
|
||||
file: SelfDir,
|
||||
},
|
||||
{
|
||||
full: "rabbit.jpg",
|
||||
dir: "",
|
||||
file: "rabbit.jpg",
|
||||
},
|
||||
{
|
||||
full: "/",
|
||||
dir: "/",
|
||||
file: "",
|
||||
},
|
||||
{
|
||||
full: "/beans",
|
||||
dir: "/",
|
||||
file: "beans",
|
||||
},
|
||||
{
|
||||
full: "/home/foo/bar",
|
||||
dir: "/home/foo/",
|
||||
file: "bar",
|
||||
},
|
||||
{
|
||||
full: "/usr/local/",
|
||||
dir: "/usr/local/",
|
||||
file: "",
|
||||
},
|
||||
{
|
||||
full: "/usr//local//go",
|
||||
dir: "/usr//local//",
|
||||
file: "go",
|
||||
},
|
||||
}
|
||||
for _, p := range cases {
|
||||
dir, file := filepath.Split(p.full)
|
||||
if dir != p.dir || file != p.file {
|
||||
t.Fatalf(
|
||||
"in '%s',\ngot dir='%s' (expected '%s'),\n got file='%s' (expected %s).",
|
||||
p.full, dir, p.dir, file, p.file)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPathSplitAndJoin(t *testing.T) {
|
||||
cases := map[string]struct {
|
||||
original string
|
||||
expected []string
|
||||
}{
|
||||
"Empty": {
|
||||
original: "",
|
||||
expected: []string{},
|
||||
},
|
||||
"One": {
|
||||
original: "hello",
|
||||
expected: []string{"hello"},
|
||||
},
|
||||
"Two": {
|
||||
original: "hello/there",
|
||||
expected: []string{"hello", "there"},
|
||||
},
|
||||
"Three": {
|
||||
original: "hello/my/friend",
|
||||
expected: []string{"hello", "my", "friend"},
|
||||
},
|
||||
}
|
||||
for n, c := range cases {
|
||||
f := func(t *testing.T, original string, expected []string) {
|
||||
actual := PathSplit(original)
|
||||
if len(actual) != len(expected) {
|
||||
t.Fatalf(
|
||||
"expected len %d, got len %d",
|
||||
len(expected), len(actual))
|
||||
}
|
||||
for i := range expected {
|
||||
if expected[i] != actual[i] {
|
||||
t.Fatalf(
|
||||
"at i=%d, expected '%s', got '%s'",
|
||||
i, expected[i], actual[i])
|
||||
}
|
||||
}
|
||||
joined := PathJoin(actual)
|
||||
if joined != original {
|
||||
t.Fatalf(
|
||||
"when rejoining, expected '%s', got '%s'",
|
||||
original, joined)
|
||||
}
|
||||
}
|
||||
t.Run("relative"+n, func(t *testing.T) {
|
||||
f(t, c.original, c.expected)
|
||||
})
|
||||
t.Run("absolute"+n, func(t *testing.T) {
|
||||
f(t,
|
||||
string(os.PathSeparator)+c.original,
|
||||
append([]string{""}, c.expected...))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestInsertPathPart(t *testing.T) {
|
||||
cases := map[string]struct {
|
||||
original string
|
||||
pos int
|
||||
part string
|
||||
expected string
|
||||
}{
|
||||
"rootOne": {
|
||||
original: "/",
|
||||
pos: 0,
|
||||
part: "___",
|
||||
expected: "/___",
|
||||
},
|
||||
"rootTwo": {
|
||||
original: "/",
|
||||
pos: 444,
|
||||
part: "___",
|
||||
expected: "/___",
|
||||
},
|
||||
"rootedFirst": {
|
||||
original: "/apple",
|
||||
pos: 0,
|
||||
part: "___",
|
||||
expected: "/___/apple",
|
||||
},
|
||||
"rootedSecond": {
|
||||
original: "/apple",
|
||||
pos: 444,
|
||||
part: "___",
|
||||
expected: "/apple/___",
|
||||
},
|
||||
"rootedThird": {
|
||||
original: "/apple/banana",
|
||||
pos: 444,
|
||||
part: "___",
|
||||
expected: "/apple/banana/___",
|
||||
},
|
||||
"emptyLow": {
|
||||
original: "",
|
||||
pos: -3,
|
||||
part: "___",
|
||||
expected: "___",
|
||||
},
|
||||
"emptyHigh": {
|
||||
original: "",
|
||||
pos: 444,
|
||||
part: "___",
|
||||
expected: "___",
|
||||
},
|
||||
"peachPie": {
|
||||
original: "a/nice/warm/pie",
|
||||
pos: 3,
|
||||
part: "PEACH",
|
||||
expected: "a/nice/warm/PEACH/pie",
|
||||
},
|
||||
"rootedPeachPie": {
|
||||
original: "/a/nice/warm/pie",
|
||||
pos: 3,
|
||||
part: "PEACH",
|
||||
expected: "/a/nice/warm/PEACH/pie",
|
||||
},
|
||||
"longStart": {
|
||||
original: "a/b/c/d/e/f",
|
||||
pos: 0,
|
||||
part: "___",
|
||||
expected: "___/a/b/c/d/e/f",
|
||||
},
|
||||
"rootedLongStart": {
|
||||
original: "/a/b/c/d/e/f",
|
||||
pos: 0,
|
||||
part: "___",
|
||||
expected: "/___/a/b/c/d/e/f",
|
||||
},
|
||||
"longMiddle": {
|
||||
original: "a/b/c/d/e/f",
|
||||
pos: 3,
|
||||
part: "___",
|
||||
expected: "a/b/c/___/d/e/f",
|
||||
},
|
||||
"rootedLongMiddle": {
|
||||
original: "/a/b/c/d/e/f",
|
||||
pos: 3,
|
||||
part: "___",
|
||||
expected: "/a/b/c/___/d/e/f",
|
||||
},
|
||||
"longEnd": {
|
||||
original: "a/b/c/d/e/f",
|
||||
pos: 444,
|
||||
part: "___",
|
||||
expected: "a/b/c/d/e/f/___",
|
||||
},
|
||||
"rootedLongEnd": {
|
||||
original: "/a/b/c/d/e/f",
|
||||
pos: 444,
|
||||
part: "___",
|
||||
expected: "/a/b/c/d/e/f/___",
|
||||
},
|
||||
}
|
||||
for n, c := range cases {
|
||||
t.Run(n, func(t *testing.T) {
|
||||
actual := InsertPathPart(c.original, c.pos, c.part)
|
||||
if actual != c.expected {
|
||||
t.Fatalf("expected '%s', got '%s'", c.expected, actual)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestStripTrailingSeps(t *testing.T) {
|
||||
cases := []struct {
|
||||
full string
|
||||
rem string
|
||||
}{
|
||||
{
|
||||
full: "foo",
|
||||
rem: "foo",
|
||||
},
|
||||
{
|
||||
full: "",
|
||||
rem: "",
|
||||
},
|
||||
{
|
||||
full: "foo/",
|
||||
rem: "foo",
|
||||
},
|
||||
{
|
||||
full: "foo///bar///",
|
||||
rem: "foo///bar",
|
||||
},
|
||||
{
|
||||
full: "/////",
|
||||
rem: "",
|
||||
},
|
||||
{
|
||||
full: "/",
|
||||
rem: "",
|
||||
},
|
||||
}
|
||||
for _, p := range cases {
|
||||
dir := StripTrailingSeps(p.full)
|
||||
if dir != p.rem {
|
||||
t.Fatalf(
|
||||
"in '%s', got dir='%s' (expected '%s')",
|
||||
p.full, dir, p.rem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStripLeadingSeps(t *testing.T) {
|
||||
cases := []struct {
|
||||
full string
|
||||
rem string
|
||||
}{
|
||||
{
|
||||
full: "foo",
|
||||
rem: "foo",
|
||||
},
|
||||
{
|
||||
full: "",
|
||||
rem: "",
|
||||
},
|
||||
{
|
||||
full: "/foo",
|
||||
rem: "foo",
|
||||
},
|
||||
{
|
||||
full: "///foo///bar///",
|
||||
rem: "foo///bar///",
|
||||
},
|
||||
{
|
||||
full: "/////",
|
||||
rem: "",
|
||||
},
|
||||
{
|
||||
full: "/",
|
||||
rem: "",
|
||||
},
|
||||
}
|
||||
for _, p := range cases {
|
||||
dir := StripLeadingSeps(p.full)
|
||||
if dir != p.rem {
|
||||
t.Fatalf(
|
||||
"in '%s', got dir='%s' (expected '%s')",
|
||||
p.full, dir, p.rem)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package annotations
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/filters/filtersutil"
|
||||
"sigs.k8s.io/kustomize/api/filters/fsslice"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
type annoMap map[string]string
|
||||
|
||||
type Filter struct {
|
||||
// Annotations is the set of annotations to apply to the inputs
|
||||
Annotations annoMap `yaml:"annotations,omitempty"`
|
||||
|
||||
// FsSlice contains the FieldSpecs to locate the namespace field
|
||||
FsSlice types.FsSlice
|
||||
}
|
||||
|
||||
var _ kio.Filter = Filter{}
|
||||
|
||||
func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||
keys := filtersutil.SortedMapKeys(f.Annotations)
|
||||
_, err := kio.FilterAll(yaml.FilterFunc(
|
||||
func(node *yaml.RNode) (*yaml.RNode, error) {
|
||||
for _, k := range keys {
|
||||
if err := node.PipeE(fsslice.Filter{
|
||||
FsSlice: f.FsSlice,
|
||||
SetValue: fsslice.SetEntry(k, f.Annotations[k], yaml.StringTag),
|
||||
CreateKind: yaml.MappingNode, // Annotations are MappingNodes.
|
||||
CreateTag: "!!map",
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return node, nil
|
||||
})).Filter(nodes)
|
||||
return nodes, err
|
||||
}
|
||||
@@ -1,226 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package annotations
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
|
||||
filtertest_test "sigs.k8s.io/kustomize/api/testutils/filtertest"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
var annosFs = builtinconfig.MakeDefaultConfig().CommonAnnotations
|
||||
|
||||
func TestAnnotations_Filter(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
input string
|
||||
expectedOutput string
|
||||
filter Filter
|
||||
fsslice types.FsSlice
|
||||
}{
|
||||
"add": {
|
||||
input: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
annotations:
|
||||
hero: batman
|
||||
fiend: riddler
|
||||
`,
|
||||
expectedOutput: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
annotations:
|
||||
hero: batman
|
||||
fiend: riddler
|
||||
auto: ford
|
||||
bean: cannellini
|
||||
clown: emmett kelley
|
||||
dragon: smaug
|
||||
`,
|
||||
filter: Filter{Annotations: annoMap{
|
||||
"clown": "emmett kelley",
|
||||
"auto": "ford",
|
||||
"dragon": "smaug",
|
||||
"bean": "cannellini",
|
||||
}},
|
||||
},
|
||||
"update": {
|
||||
input: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
annotations:
|
||||
hero: batman
|
||||
fiend: riddler
|
||||
`,
|
||||
expectedOutput: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
annotations:
|
||||
hero: superman
|
||||
fiend: luthor
|
||||
bean: cannellini
|
||||
clown: emmett kelley
|
||||
`,
|
||||
filter: Filter{Annotations: annoMap{
|
||||
"clown": "emmett kelley",
|
||||
"hero": "superman",
|
||||
"fiend": "luthor",
|
||||
"bean": "cannellini",
|
||||
}},
|
||||
},
|
||||
"data-fieldspecs": {
|
||||
input: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance
|
||||
`,
|
||||
expectedOutput: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
annotations:
|
||||
sleater: kinney
|
||||
a:
|
||||
b:
|
||||
sleater: kinney
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance
|
||||
annotations:
|
||||
sleater: kinney
|
||||
a:
|
||||
b:
|
||||
sleater: kinney
|
||||
`,
|
||||
filter: Filter{Annotations: annoMap{
|
||||
"sleater": "kinney",
|
||||
}},
|
||||
fsslice: []types.FieldSpec{
|
||||
{
|
||||
Path: "a/b",
|
||||
CreateIfNotPresent: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"number": {
|
||||
input: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
annotations:
|
||||
hero: batman
|
||||
fiend: riddler
|
||||
`,
|
||||
expectedOutput: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
annotations:
|
||||
hero: batman
|
||||
fiend: riddler
|
||||
2: ford
|
||||
clown: "1"
|
||||
`,
|
||||
filter: Filter{Annotations: annoMap{
|
||||
"clown": "1",
|
||||
"2": "ford",
|
||||
}},
|
||||
},
|
||||
|
||||
// test quoting of values which are not considered strings in yaml 1.1
|
||||
"yaml_1_1_compatibility": {
|
||||
input: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
annotations:
|
||||
hero: batman
|
||||
fiend: riddler
|
||||
`,
|
||||
expectedOutput: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
annotations:
|
||||
hero: batman
|
||||
fiend: riddler
|
||||
a: "y"
|
||||
b: y1
|
||||
c: "yes"
|
||||
d: yes1
|
||||
e: "true"
|
||||
f: true1
|
||||
`,
|
||||
filter: Filter{Annotations: annoMap{
|
||||
"a": "y",
|
||||
"b": "y1",
|
||||
"c": "yes",
|
||||
"d": "yes1",
|
||||
"e": "true",
|
||||
"f": "true1",
|
||||
}},
|
||||
},
|
||||
|
||||
// test quoting of values which are not considered strings in yaml 1.1
|
||||
"null_annotations": {
|
||||
input: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
annotations: null
|
||||
`,
|
||||
expectedOutput: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
annotations:
|
||||
a: a1
|
||||
b: b1
|
||||
`,
|
||||
filter: Filter{Annotations: annoMap{
|
||||
"a": "a1",
|
||||
"b": "b1",
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
for tn, tc := range testCases {
|
||||
t.Run(tn, func(t *testing.T) {
|
||||
filter := tc.filter
|
||||
filter.FsSlice = append(annosFs, tc.fsslice...)
|
||||
if !assert.Equal(t,
|
||||
strings.TrimSpace(tc.expectedOutput),
|
||||
strings.TrimSpace(filtertest_test.RunFilter(t, tc.input, filter))) {
|
||||
t.FailNow()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package annotations contains a kio.Filter implementation of the kustomize
|
||||
// annotations transformer.
|
||||
package annotations
|
||||
@@ -1,55 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package annotations
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
)
|
||||
|
||||
func ExampleFilter() {
|
||||
fss := builtinconfig.MakeDefaultConfig().CommonAnnotations
|
||||
err := kio.Pipeline{
|
||||
Inputs: []kio.Reader{&kio.ByteReader{Reader: bytes.NewBufferString(`
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance
|
||||
`)}},
|
||||
Filters: []kio.Filter{Filter{
|
||||
Annotations: map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
FsSlice: fss,
|
||||
}},
|
||||
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
|
||||
}.Execute()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// apiVersion: example.com/v1
|
||||
// kind: Foo
|
||||
// metadata:
|
||||
// name: instance
|
||||
// annotations:
|
||||
// foo: bar
|
||||
// ---
|
||||
// apiVersion: example.com/v1
|
||||
// kind: Bar
|
||||
// metadata:
|
||||
// name: instance
|
||||
// annotations:
|
||||
// foo: bar
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package filtersutil
|
||||
|
||||
import (
|
||||
"sort"
|
||||
)
|
||||
|
||||
// SortedMapKeys returns a sorted slice of keys to the given map.
|
||||
// Writing this function never gets old.
|
||||
func SortedMapKeys(m map[string]string) []string {
|
||||
keys := make([]string, len(m))
|
||||
i := 0
|
||||
for k := range m {
|
||||
keys[i] = k
|
||||
i++
|
||||
}
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package filtersutil_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"sigs.k8s.io/kustomize/api/filters/filtersutil"
|
||||
)
|
||||
|
||||
func TestSortedKeys(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
input map[string]string
|
||||
expected []string
|
||||
}{
|
||||
"empty": {
|
||||
input: map[string]string{},
|
||||
expected: []string{}},
|
||||
"one": {
|
||||
input: map[string]string{"a": "aaa"},
|
||||
expected: []string{"a"}},
|
||||
"three": {
|
||||
input: map[string]string{"c": "ccc", "b": "bbb", "a": "aaa"},
|
||||
expected: []string{"a", "b", "c"}},
|
||||
}
|
||||
for tn, tc := range testCases {
|
||||
t.Run(tn, func(t *testing.T) {
|
||||
if !assert.Equal(t,
|
||||
filtersutil.SortedMapKeys(tc.input),
|
||||
tc.expected) {
|
||||
t.FailNow()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package fsslice contains a yaml.Filter to modify a resource using an
|
||||
// FsSlice to identify fields to be updated within the resource.
|
||||
package fsslice
|
||||
@@ -1,62 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package fsslice_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/filters/fsslice"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
func ExampleFilter() {
|
||||
in := &kio.ByteReader{
|
||||
Reader: bytes.NewBufferString(`
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance
|
||||
`),
|
||||
}
|
||||
fltr := fsslice.Filter{
|
||||
CreateKind: yaml.ScalarNode,
|
||||
SetValue: fsslice.SetScalar("green"),
|
||||
FsSlice: []types.FieldSpec{
|
||||
{Path: "a/b", CreateIfNotPresent: true},
|
||||
},
|
||||
}
|
||||
|
||||
err := kio.Pipeline{
|
||||
Inputs: []kio.Reader{in},
|
||||
Filters: []kio.Filter{kio.FilterAll(fltr)},
|
||||
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
|
||||
}.Execute()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// apiVersion: example.com/v1
|
||||
// kind: Foo
|
||||
// metadata:
|
||||
// name: instance
|
||||
// a:
|
||||
// b: green
|
||||
// ---
|
||||
// apiVersion: example.com/v1
|
||||
// kind: Bar
|
||||
// metadata:
|
||||
// name: instance
|
||||
// a:
|
||||
// b: green
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package fsslice
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
// fieldSpecFilter applies a single fieldSpec to a single object
|
||||
// fieldSpecFilter stores internal state and should not be reused
|
||||
type fieldSpecFilter struct {
|
||||
// FieldSpec contains the path to the value to set.
|
||||
FieldSpec types.FieldSpec `yaml:"fieldSpec"`
|
||||
|
||||
// Set the field using this function
|
||||
SetValue SetFn
|
||||
|
||||
// CreateKind defines the type of node to create if the field is not found
|
||||
CreateKind yaml.Kind
|
||||
|
||||
CreateTag string
|
||||
|
||||
// path keeps internal state about the current path
|
||||
path []string
|
||||
}
|
||||
|
||||
func (fltr fieldSpecFilter) Filter(obj *yaml.RNode) (*yaml.RNode, error) {
|
||||
// check if the FieldSpec applies to the object
|
||||
if match, err := isMatchGVK(fltr.FieldSpec, obj); !match || err != nil {
|
||||
return obj, errors.Wrap(err)
|
||||
}
|
||||
fltr.path = strings.Split(fltr.FieldSpec.Path, "/")
|
||||
if err := fltr.filter(obj); err != nil {
|
||||
s, _ := obj.String()
|
||||
return nil, errors.WrapPrefixf(err,
|
||||
"obj %v at path %v", s, fltr.FieldSpec.Path)
|
||||
}
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
func (fltr fieldSpecFilter) filter(obj *yaml.RNode) error {
|
||||
if len(fltr.path) == 0 {
|
||||
// found the field -- set its value
|
||||
return fltr.SetValue(obj)
|
||||
}
|
||||
switch obj.YNode().Kind {
|
||||
case yaml.SequenceNode:
|
||||
return fltr.seq(obj)
|
||||
case yaml.MappingNode:
|
||||
return fltr.field(obj)
|
||||
}
|
||||
// not found -- this might be an error since the type doesn't match
|
||||
|
||||
return errors.Errorf("unsupported yaml node")
|
||||
}
|
||||
|
||||
// field calls filter on the field matching the next path element
|
||||
func (fltr fieldSpecFilter) field(obj *yaml.RNode) error {
|
||||
fieldName, isSeq := isSequenceField(fltr.path[0])
|
||||
|
||||
// lookup the field matching the next path element
|
||||
var lookupField yaml.Filter
|
||||
var kind yaml.Kind
|
||||
var tag string
|
||||
switch {
|
||||
case !fltr.FieldSpec.CreateIfNotPresent || fltr.CreateKind == 0 || isSeq:
|
||||
// dont' create the field if we don't find it
|
||||
lookupField = yaml.Lookup(fieldName)
|
||||
case len(fltr.path) <= 1:
|
||||
// create the field if it is missing: use the provided node kind
|
||||
lookupField = yaml.LookupCreate(fltr.CreateKind, fieldName)
|
||||
kind = fltr.CreateKind
|
||||
tag = fltr.CreateTag
|
||||
default:
|
||||
// create the field if it is missing: must be a mapping node
|
||||
lookupField = yaml.LookupCreate(yaml.MappingNode, fieldName)
|
||||
kind = yaml.MappingNode
|
||||
tag = "!!map"
|
||||
}
|
||||
|
||||
// locate (or maybe create) the field
|
||||
field, err := obj.Pipe(lookupField)
|
||||
if err != nil || field == nil {
|
||||
return errors.WrapPrefixf(err, "fieldName: %s", fieldName)
|
||||
}
|
||||
|
||||
// if the value exists, but is null, then change it to the creation type
|
||||
// TODO: update yaml.LookupCreate to support this
|
||||
if field.YNode().Tag == "!!null" {
|
||||
field.YNode().Kind = kind
|
||||
field.YNode().Tag = tag
|
||||
}
|
||||
|
||||
// copy the current fltr and change the path on the copy
|
||||
var next = fltr
|
||||
// call filter for the next path element on the matching field
|
||||
next.path = fltr.path[1:]
|
||||
return next.filter(field)
|
||||
}
|
||||
|
||||
// seq calls filter on all sequence elements
|
||||
func (fltr fieldSpecFilter) seq(obj *yaml.RNode) error {
|
||||
if err := obj.VisitElements(func(node *yaml.RNode) error {
|
||||
// recurse on each element -- re-allocating a fieldSpecFilter is
|
||||
// not strictly required, but is more consistent with field
|
||||
// and less likely to have side effects
|
||||
// keep the entire path -- it does not contain parts for sequences
|
||||
return fltr.filter(node)
|
||||
}); err != nil {
|
||||
return errors.WrapPrefixf(err,
|
||||
"visit traversal on path: %v", fltr.path)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// isSequenceField returns true if the path element is for a sequence field.
|
||||
// isSequence also returns the path element with the '[]' suffix trimmed
|
||||
func isSequenceField(name string) (string, bool) {
|
||||
isSeq := strings.HasSuffix(name, "[]")
|
||||
name = strings.TrimSuffix(name, "[]")
|
||||
return name, isSeq
|
||||
}
|
||||
|
||||
// isMatchGVK returns true if the fs.GVK matches the obj GVK.
|
||||
func isMatchGVK(fs types.FieldSpec, obj *yaml.RNode) (bool, error) {
|
||||
meta, err := obj.GetMeta()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if fs.Kind != "" && fs.Kind != meta.Kind {
|
||||
// kind doesn't match
|
||||
return false, err
|
||||
}
|
||||
|
||||
// parse the group and version from the apiVersion field
|
||||
group, version := parseGV(meta.APIVersion)
|
||||
|
||||
if fs.Group != "" && fs.Group != group {
|
||||
// group doesn't match
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if fs.Version != "" && fs.Version != version {
|
||||
// version doesn't match
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package fsslice
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
// SetFn sets a value
|
||||
type SetFn func(*yaml.RNode) error
|
||||
|
||||
// SetScalar returns a SetFn to set a scalar value
|
||||
func SetScalar(value string) SetFn {
|
||||
return func(node *yaml.RNode) error {
|
||||
return node.PipeE(yaml.FieldSetter{StringValue: value})
|
||||
}
|
||||
}
|
||||
|
||||
// SetEntry returns a SetFn to set an entry in a map
|
||||
func SetEntry(key, value, tag string) SetFn {
|
||||
n := &yaml.Node{
|
||||
Kind: yaml.ScalarNode,
|
||||
Value: value,
|
||||
Tag: tag,
|
||||
}
|
||||
if tag == yaml.StringTag && yaml.IsYaml1_1NonString(n) {
|
||||
n.Style = yaml.DoubleQuotedStyle
|
||||
}
|
||||
return func(node *yaml.RNode) error {
|
||||
return node.PipeE(yaml.FieldSetter{
|
||||
Name: key,
|
||||
Value: yaml.NewRNode(n),
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var _ yaml.Filter = Filter{}
|
||||
|
||||
// Filter uses an FsSlice to modify fields on a single object
|
||||
type Filter struct {
|
||||
// FieldSpecList list of FieldSpecs to set
|
||||
FsSlice types.FsSlice `yaml:"fsSlice"`
|
||||
|
||||
// SetValue is called on each field that matches one of the FieldSpecs
|
||||
SetValue SetFn
|
||||
|
||||
// CreateKind is used to create fields that do not exist
|
||||
CreateKind yaml.Kind
|
||||
|
||||
// CreateTag is used to set the tag if encountering a null field
|
||||
CreateTag string
|
||||
}
|
||||
|
||||
func (fltr Filter) Filter(obj *yaml.RNode) (*yaml.RNode, error) {
|
||||
for i := range fltr.FsSlice {
|
||||
// apply this FieldSpec
|
||||
// create a new filter for each iteration because they
|
||||
// store internal state about the field paths
|
||||
_, err := (&fieldSpecFilter{
|
||||
FieldSpec: fltr.FsSlice[i],
|
||||
SetValue: fltr.SetValue,
|
||||
CreateKind: fltr.CreateKind,
|
||||
CreateTag: fltr.CreateTag,
|
||||
}).Filter(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return obj, nil
|
||||
}
|
||||
@@ -1,379 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package fsslice_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"sigs.k8s.io/kustomize/api/filters/fsslice"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
type TestCase struct {
|
||||
name string
|
||||
input string
|
||||
expected string
|
||||
filter fsslice.Filter
|
||||
fsSlice string
|
||||
error string
|
||||
}
|
||||
|
||||
var tests = []TestCase{
|
||||
{
|
||||
name: "update",
|
||||
fsSlice: `
|
||||
- path: a/b
|
||||
group: foo
|
||||
kind: Bar
|
||||
`,
|
||||
input: `
|
||||
apiVersion: foo/v1beta1
|
||||
kind: Bar
|
||||
a:
|
||||
b: c
|
||||
`,
|
||||
expected: `
|
||||
apiVersion: foo/v1beta1
|
||||
kind: Bar
|
||||
a:
|
||||
b: e
|
||||
`,
|
||||
filter: fsslice.Filter{
|
||||
SetValue: fsslice.SetScalar("e"),
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "update-kind-not-match",
|
||||
fsSlice: `
|
||||
- path: a/b
|
||||
group: foo
|
||||
kind: Bar1
|
||||
`,
|
||||
input: `
|
||||
apiVersion: foo/v1beta1
|
||||
kind: Bar2
|
||||
a:
|
||||
b: c
|
||||
`,
|
||||
expected: `
|
||||
apiVersion: foo/v1beta1
|
||||
kind: Bar2
|
||||
a:
|
||||
b: c
|
||||
`,
|
||||
filter: fsslice.Filter{
|
||||
SetValue: fsslice.SetScalar("e"),
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "update-group-not-match",
|
||||
fsSlice: `
|
||||
- path: a/b
|
||||
group: foo1
|
||||
kind: Bar
|
||||
`,
|
||||
input: `
|
||||
apiVersion: foo2/v1beta1
|
||||
kind: Bar
|
||||
a:
|
||||
b: c
|
||||
`,
|
||||
expected: `
|
||||
apiVersion: foo2/v1beta1
|
||||
kind: Bar
|
||||
a:
|
||||
b: c
|
||||
`,
|
||||
filter: fsslice.Filter{
|
||||
SetValue: fsslice.SetScalar("e"),
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "update-version-not-match",
|
||||
fsSlice: `
|
||||
- path: a/b
|
||||
group: foo
|
||||
version: v1beta1
|
||||
kind: Bar
|
||||
`,
|
||||
input: `
|
||||
apiVersion: foo/v1beta2
|
||||
kind: Bar
|
||||
a:
|
||||
b: c
|
||||
`,
|
||||
expected: `
|
||||
apiVersion: foo/v1beta2
|
||||
kind: Bar
|
||||
a:
|
||||
b: c
|
||||
`,
|
||||
filter: fsslice.Filter{
|
||||
SetValue: fsslice.SetScalar("e"),
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "bad-version",
|
||||
fsSlice: `
|
||||
- path: a/b
|
||||
group: foo
|
||||
version: v1beta1
|
||||
kind: Bar
|
||||
`,
|
||||
input: `
|
||||
apiVersion: foo/v1beta2/something
|
||||
kind: Bar
|
||||
a:
|
||||
b: c
|
||||
`,
|
||||
expected: `
|
||||
apiVersion: foo/v1beta2/something
|
||||
kind: Bar
|
||||
a:
|
||||
b: c
|
||||
`,
|
||||
filter: fsslice.Filter{
|
||||
SetValue: fsslice.SetScalar("e"),
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "bad-meta",
|
||||
fsSlice: `
|
||||
- path: a/b
|
||||
group: foo
|
||||
version: v1beta1
|
||||
kind: Bar
|
||||
`,
|
||||
input: `
|
||||
a:
|
||||
b: c
|
||||
`,
|
||||
filter: fsslice.Filter{
|
||||
SetValue: fsslice.SetScalar("e"),
|
||||
},
|
||||
error: "missing Resource metadata",
|
||||
},
|
||||
|
||||
{
|
||||
name: "miss-match-type",
|
||||
fsSlice: `
|
||||
- path: a/b/c
|
||||
kind: Bar
|
||||
`,
|
||||
input: `
|
||||
kind: Bar
|
||||
a:
|
||||
b: a
|
||||
`,
|
||||
error: "obj kind: Bar\na:\n b: a\n at path a/b/c: unsupported yaml node",
|
||||
filter: fsslice.Filter{
|
||||
SetValue: fsslice.SetScalar("e"),
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "add",
|
||||
fsSlice: `
|
||||
- path: a/b/c/d
|
||||
group: foo
|
||||
create: true
|
||||
kind: Bar
|
||||
`,
|
||||
input: `
|
||||
apiVersion: foo/v1beta1
|
||||
kind: Bar
|
||||
a: {}
|
||||
`,
|
||||
expected: `
|
||||
apiVersion: foo/v1beta1
|
||||
kind: Bar
|
||||
a: {b: {c: {d: e}}}
|
||||
`,
|
||||
filter: fsslice.Filter{
|
||||
SetValue: fsslice.SetScalar("e"),
|
||||
CreateKind: yaml.ScalarNode,
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "update-in-sequence",
|
||||
fsSlice: `
|
||||
- path: a/b[]/c/d
|
||||
group: foo
|
||||
kind: Bar
|
||||
`,
|
||||
input: `
|
||||
apiVersion: foo/v1beta1
|
||||
kind: Bar
|
||||
a:
|
||||
b:
|
||||
- c:
|
||||
d: a
|
||||
`,
|
||||
expected: `
|
||||
apiVersion: foo/v1beta1
|
||||
kind: Bar
|
||||
a:
|
||||
b:
|
||||
- c:
|
||||
d: e
|
||||
`,
|
||||
filter: fsslice.Filter{
|
||||
SetValue: fsslice.SetScalar("e"),
|
||||
},
|
||||
},
|
||||
|
||||
// Don't create a sequence
|
||||
{
|
||||
name: "empty-sequence-no-create",
|
||||
fsSlice: `
|
||||
- path: a/b[]/c/d
|
||||
group: foo
|
||||
create: true
|
||||
kind: Bar
|
||||
`,
|
||||
input: `
|
||||
apiVersion: foo/v1beta1
|
||||
kind: Bar
|
||||
a: {}
|
||||
`,
|
||||
expected: `
|
||||
apiVersion: foo/v1beta1
|
||||
kind: Bar
|
||||
a: {}
|
||||
`,
|
||||
filter: fsslice.Filter{
|
||||
SetValue: fsslice.SetScalar("e"),
|
||||
CreateKind: yaml.ScalarNode,
|
||||
},
|
||||
},
|
||||
|
||||
// Create a new field for an element in a sequence
|
||||
{
|
||||
name: "empty-sequence-create",
|
||||
fsSlice: `
|
||||
- path: a/b[]/c/d
|
||||
group: foo
|
||||
create: true
|
||||
kind: Bar
|
||||
`,
|
||||
input: `
|
||||
apiVersion: foo/v1beta1
|
||||
kind: Bar
|
||||
a:
|
||||
b:
|
||||
- c: {}
|
||||
`,
|
||||
expected: `
|
||||
apiVersion: foo/v1beta1
|
||||
kind: Bar
|
||||
a:
|
||||
b:
|
||||
- c: {d: e}
|
||||
`,
|
||||
filter: fsslice.Filter{
|
||||
SetValue: fsslice.SetScalar("e"),
|
||||
CreateKind: yaml.ScalarNode,
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "group v1",
|
||||
fsSlice: `
|
||||
- path: a/b
|
||||
group: v1
|
||||
create: true
|
||||
kind: Bar
|
||||
`,
|
||||
input: `
|
||||
apiVersion: v1
|
||||
kind: Bar
|
||||
`,
|
||||
expected: `
|
||||
apiVersion: v1
|
||||
kind: Bar
|
||||
`,
|
||||
filter: fsslice.Filter{
|
||||
SetValue: fsslice.SetScalar("e"),
|
||||
CreateKind: yaml.ScalarNode,
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "version v1",
|
||||
fsSlice: `
|
||||
- path: a/b
|
||||
version: v1
|
||||
create: true
|
||||
kind: Bar
|
||||
`,
|
||||
input: `
|
||||
apiVersion: v1
|
||||
kind: Bar
|
||||
`,
|
||||
expected: `
|
||||
apiVersion: v1
|
||||
kind: Bar
|
||||
a:
|
||||
b: e
|
||||
`,
|
||||
filter: fsslice.Filter{
|
||||
SetValue: fsslice.SetScalar("e"),
|
||||
CreateKind: yaml.ScalarNode,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestFilter_Filter(t *testing.T) {
|
||||
for i := range tests {
|
||||
test := tests[i]
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
err := yaml.Unmarshal([]byte(test.fsSlice), &test.filter.FsSlice)
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
out := &bytes.Buffer{}
|
||||
rw := &kio.ByteReadWriter{
|
||||
Reader: bytes.NewBufferString(test.input),
|
||||
Writer: out,
|
||||
OmitReaderAnnotations: true,
|
||||
}
|
||||
|
||||
// run the filter
|
||||
err = kio.Pipeline{
|
||||
Inputs: []kio.Reader{rw},
|
||||
Filters: []kio.Filter{kio.FilterAll(test.filter)},
|
||||
Outputs: []kio.Writer{rw},
|
||||
}.Execute()
|
||||
if test.error != "" {
|
||||
if !assert.EqualError(t, err, test.error) {
|
||||
t.FailNow()
|
||||
}
|
||||
// stop rest of test
|
||||
return
|
||||
}
|
||||
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// check results
|
||||
if !assert.Equal(t,
|
||||
strings.TrimSpace(test.expected),
|
||||
strings.TrimSpace(out.String())) {
|
||||
t.FailNow()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package fsslice
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
// Return true for 'v' followed by a 1 or 2, and don't look at rest.
|
||||
// I.e. 'v1', 'v1beta1', 'v2', would return true.
|
||||
func looksLikeACoreApiVersion(s string) bool {
|
||||
if len(s) < 2 {
|
||||
return false
|
||||
}
|
||||
if s[0:1] != "v" {
|
||||
return false
|
||||
}
|
||||
return s[1:2] == "1" || s[1:2] == "2"
|
||||
}
|
||||
|
||||
// parseGV parses apiVersion field into group and version.
|
||||
func parseGV(apiVersion string) (group, version string) {
|
||||
// parse the group and version from the apiVersion field
|
||||
parts := strings.SplitN(apiVersion, "/", 2)
|
||||
group = parts[0]
|
||||
if len(parts) > 1 {
|
||||
version = parts[1]
|
||||
}
|
||||
// Special case the original "apiVersion" of what
|
||||
// we now call the "core" (empty) group.
|
||||
if version == "" && looksLikeACoreApiVersion(group) {
|
||||
version = group
|
||||
group = ""
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetGVK parses the metadata into a GVK
|
||||
func GetGVK(meta yaml.ResourceMeta) resid.Gvk {
|
||||
group, version := parseGV(meta.APIVersion)
|
||||
return resid.Gvk{
|
||||
Group: group,
|
||||
Version: version,
|
||||
Kind: meta.Kind,
|
||||
}
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package fsslice
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
func TestParseGV(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
input string
|
||||
expectedGroup string
|
||||
expectedVersion string
|
||||
}{
|
||||
"empty": {
|
||||
input: "",
|
||||
expectedGroup: "",
|
||||
expectedVersion: "",
|
||||
},
|
||||
"certSigning": {
|
||||
input: "certificates.k8s.io/v1beta1",
|
||||
expectedGroup: "certificates.k8s.io",
|
||||
expectedVersion: "v1beta1",
|
||||
},
|
||||
"extensions": {
|
||||
input: "extensions/v1beta1",
|
||||
expectedGroup: "extensions",
|
||||
expectedVersion: "v1beta1",
|
||||
},
|
||||
"normal": {
|
||||
input: "apps/v1",
|
||||
expectedGroup: "apps",
|
||||
expectedVersion: "v1",
|
||||
},
|
||||
"justApps": {
|
||||
input: "apps",
|
||||
expectedGroup: "apps",
|
||||
expectedVersion: "",
|
||||
},
|
||||
"coreV1": {
|
||||
input: "v1",
|
||||
expectedGroup: "",
|
||||
expectedVersion: "v1",
|
||||
},
|
||||
"coreV2": {
|
||||
input: "v2",
|
||||
expectedGroup: "",
|
||||
expectedVersion: "v2",
|
||||
},
|
||||
"coreV2Beta1": {
|
||||
input: "v2beta1",
|
||||
expectedGroup: "",
|
||||
expectedVersion: "v2beta1",
|
||||
},
|
||||
}
|
||||
|
||||
for tn, tc := range testCases {
|
||||
t.Run(tn, func(t *testing.T) {
|
||||
group, version := parseGV(tc.input)
|
||||
if !assert.Equal(t, tc.expectedGroup, group) {
|
||||
t.FailNow()
|
||||
}
|
||||
if !assert.Equal(t, tc.expectedVersion, version) {
|
||||
t.FailNow()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetGVK(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
input string
|
||||
expected resid.Gvk
|
||||
parseError string
|
||||
metaError string
|
||||
}{
|
||||
"empty": {
|
||||
input: `
|
||||
`,
|
||||
parseError: "EOF",
|
||||
},
|
||||
"junk": {
|
||||
input: `
|
||||
congress: effective
|
||||
`,
|
||||
metaError: "missing Resource metadata",
|
||||
},
|
||||
"normal": {
|
||||
input: `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
`,
|
||||
expected: resid.Gvk{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||
},
|
||||
"apiVersionOnlyWithSlash": {
|
||||
input: `
|
||||
apiVersion: apps/v1
|
||||
`,
|
||||
expected: resid.Gvk{Group: "apps", Version: "v1", Kind: ""},
|
||||
},
|
||||
"apiVersionOnlyNoSlash1": {
|
||||
input: `
|
||||
apiVersion: apps
|
||||
`,
|
||||
expected: resid.Gvk{Group: "apps", Version: "", Kind: ""},
|
||||
},
|
||||
"apiVersionOnlyNoSlash2": {
|
||||
input: `
|
||||
apiVersion: v1
|
||||
`,
|
||||
expected: resid.Gvk{Group: "", Version: "v1", Kind: ""},
|
||||
},
|
||||
}
|
||||
|
||||
for tn, tc := range testCases {
|
||||
t.Run(tn, func(t *testing.T) {
|
||||
obj, err := yaml.Parse(tc.input)
|
||||
if len(tc.parseError) != 0 {
|
||||
if err == nil {
|
||||
t.Error("expected parse error")
|
||||
return
|
||||
}
|
||||
if !strings.Contains(err.Error(), tc.parseError) {
|
||||
t.Errorf("expected parse err '%s', got '%v'", tc.parseError, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
meta, err := obj.GetMeta()
|
||||
if len(tc.metaError) != 0 {
|
||||
if err == nil {
|
||||
t.Error("expected meta error")
|
||||
return
|
||||
}
|
||||
if !strings.Contains(err.Error(), tc.metaError) {
|
||||
t.Errorf("expected meta err '%s', got '%v'", tc.metaError, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
gvk := GetGVK(meta)
|
||||
if !assert.Equal(t, tc.expected, gvk) {
|
||||
t.FailNow()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package imagetag contains two kio.Filter implementations to cover the
|
||||
// functionality of the kustomize imagetag transformer.
|
||||
//
|
||||
// Filter updates fields based on a FieldSpec and an ImageTag.
|
||||
//
|
||||
// LegacyFilter doesn't use a FieldSpec, and instead only updates image
|
||||
// references if the field is name image and it is underneath a field called
|
||||
// either containers or initContainers.
|
||||
package imagetag
|
||||
@@ -1,126 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package imagetag
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
)
|
||||
|
||||
func ExampleFilter() {
|
||||
err := kio.Pipeline{
|
||||
Inputs: []kio.Reader{&kio.ByteReader{Reader: bytes.NewBufferString(`
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
spec:
|
||||
containers:
|
||||
- name: FooBar
|
||||
image: nginx
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance
|
||||
spec:
|
||||
containers:
|
||||
- name: BarFoo
|
||||
image: nginx:1.2.1
|
||||
`)}},
|
||||
Filters: []kio.Filter{Filter{
|
||||
ImageTag: types.Image{
|
||||
Name: "nginx",
|
||||
NewName: "apache",
|
||||
Digest: "12345",
|
||||
},
|
||||
FsSlice: []types.FieldSpec{
|
||||
{
|
||||
Path: "spec/containers[]/image",
|
||||
},
|
||||
},
|
||||
}},
|
||||
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
|
||||
}.Execute()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// apiVersion: example.com/v1
|
||||
// kind: Foo
|
||||
// metadata:
|
||||
// name: instance
|
||||
// spec:
|
||||
// containers:
|
||||
// - name: FooBar
|
||||
// image: apache@12345
|
||||
// ---
|
||||
// apiVersion: example.com/v1
|
||||
// kind: Bar
|
||||
// metadata:
|
||||
// name: instance
|
||||
// spec:
|
||||
// containers:
|
||||
// - name: BarFoo
|
||||
// image: apache@12345
|
||||
}
|
||||
|
||||
func ExampleLegacyFilter() {
|
||||
err := kio.Pipeline{
|
||||
Inputs: []kio.Reader{&kio.ByteReader{Reader: bytes.NewBufferString(`
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
spec:
|
||||
containers:
|
||||
- name: FooBar
|
||||
image: nginx
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance
|
||||
spec:
|
||||
containers:
|
||||
- name: BarFoo
|
||||
image: nginx:1.2.1
|
||||
`)}},
|
||||
Filters: []kio.Filter{LegacyFilter{
|
||||
ImageTag: types.Image{
|
||||
Name: "nginx",
|
||||
NewName: "apache",
|
||||
Digest: "12345",
|
||||
},
|
||||
}},
|
||||
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
|
||||
}.Execute()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// apiVersion: example.com/v1
|
||||
// kind: Foo
|
||||
// metadata:
|
||||
// name: instance
|
||||
// spec:
|
||||
// containers:
|
||||
// - name: FooBar
|
||||
// image: apache@12345
|
||||
// ---
|
||||
// apiVersion: example.com/v1
|
||||
// kind: Bar
|
||||
// metadata:
|
||||
// name: instance
|
||||
// spec:
|
||||
// containers:
|
||||
// - name: BarFoo
|
||||
// image: apache@12345
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package imagetag
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/filters/fsslice"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
type Filter struct {
|
||||
// imageTag is the tag we want to apply to the inputs
|
||||
ImageTag types.Image `json:"imageTag,omitempty" yaml:"imageTag,omitempty"`
|
||||
|
||||
// FsSlice contains the FieldSpecs to locate the namespace field
|
||||
FsSlice types.FsSlice `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||
}
|
||||
|
||||
var _ kio.Filter = Filter{}
|
||||
|
||||
func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||
_, err := kio.FilterAll(yaml.FilterFunc(f.filter)).Filter(nodes)
|
||||
return nodes, err
|
||||
}
|
||||
|
||||
func (f Filter) filter(node *yaml.RNode) (*yaml.RNode, error) {
|
||||
if err := node.PipeE(fsslice.Filter{
|
||||
FsSlice: f.FsSlice,
|
||||
SetValue: updateImageTagFn(f.ImageTag),
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return node, nil
|
||||
}
|
||||
|
||||
func updateImageTagFn(imageTag types.Image) fsslice.SetFn {
|
||||
return func(node *yaml.RNode) error {
|
||||
return node.PipeE(imageTagUpdater{
|
||||
ImageTag: imageTag,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package imagetag
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
filtertest "sigs.k8s.io/kustomize/api/testutils/filtertest"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
func TestImageTagUpdater_Filter(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
input string
|
||||
expectedOutput string
|
||||
filter Filter
|
||||
fsSlice types.FsSlice
|
||||
}{
|
||||
"update with digest": {
|
||||
input: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
spec:
|
||||
image: nginx:1.2.1
|
||||
`,
|
||||
expectedOutput: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
spec:
|
||||
image: apache@12345
|
||||
`,
|
||||
filter: Filter{
|
||||
ImageTag: types.Image{
|
||||
Name: "nginx",
|
||||
NewName: "apache",
|
||||
Digest: "12345",
|
||||
},
|
||||
},
|
||||
fsSlice: []types.FieldSpec{
|
||||
{
|
||||
Path: "spec/image",
|
||||
},
|
||||
},
|
||||
},
|
||||
"multiple matches in sequence": {
|
||||
input: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx:1.2.1
|
||||
- image: not_nginx@54321
|
||||
- image: nginx:1.2.1
|
||||
`,
|
||||
expectedOutput: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
spec:
|
||||
containers:
|
||||
- image: apache:3.2.1
|
||||
- image: not_nginx@54321
|
||||
- image: apache:3.2.1
|
||||
`,
|
||||
filter: Filter{
|
||||
ImageTag: types.Image{
|
||||
Name: "nginx",
|
||||
NewName: "apache",
|
||||
NewTag: "3.2.1",
|
||||
},
|
||||
},
|
||||
fsSlice: []types.FieldSpec{
|
||||
{
|
||||
Path: "spec/containers/image",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for tn, tc := range testCases {
|
||||
t.Run(tn, func(t *testing.T) {
|
||||
filter := tc.filter
|
||||
filter.FsSlice = tc.fsSlice
|
||||
if !assert.Equal(t,
|
||||
strings.TrimSpace(tc.expectedOutput),
|
||||
strings.TrimSpace(filtertest.RunFilter(t, tc.input, filter))) {
|
||||
t.FailNow()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package imagetag
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
// LegacyFilter is an implementation of the kio.Filter interface
|
||||
// that scans through the provided kyaml data structure and updates
|
||||
// any values of any image fields that is inside a sequence under
|
||||
// a field called either containers or initContainers. The field is only
|
||||
// update if it has a value that matches and image reference and the name
|
||||
// of the image is a match with the provided ImageTag.
|
||||
type LegacyFilter struct {
|
||||
ImageTag types.Image `json:"imageTag,omitempty" yaml:"imageTag,omitempty"`
|
||||
}
|
||||
|
||||
var _ kio.Filter = LegacyFilter{}
|
||||
|
||||
func (lf LegacyFilter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||
return kio.FilterAll(yaml.FilterFunc(lf.filter)).Filter(nodes)
|
||||
}
|
||||
|
||||
func (lf LegacyFilter) filter(node *yaml.RNode) (*yaml.RNode, error) {
|
||||
meta, err := node.GetMeta()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// We do not make any changes if the type of the resource
|
||||
// is CustomResourceDefinition.
|
||||
if meta.Kind == `CustomResourceDefinition` {
|
||||
return node, nil
|
||||
}
|
||||
|
||||
fff := findFieldsFilter{
|
||||
fields: []string{"containers", "initContainers"},
|
||||
fieldCallback: checkImageTagsFn(lf.ImageTag),
|
||||
}
|
||||
if err := node.PipeE(fff); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return node, nil
|
||||
}
|
||||
|
||||
type fieldCallback func(node *yaml.RNode) error
|
||||
|
||||
// findFieldsFilter is an implementation of the kio.Filter
|
||||
// interface. It will walk the data structure and look for fields
|
||||
// that matches the provided list of field names. For each match,
|
||||
// the value of the field will be passed in as a parameter to the
|
||||
// provided fieldCallback.
|
||||
// TODO: move this to kyaml/filterutils
|
||||
type findFieldsFilter struct {
|
||||
fields []string
|
||||
|
||||
fieldCallback fieldCallback
|
||||
}
|
||||
|
||||
func (f findFieldsFilter) Filter(obj *yaml.RNode) (*yaml.RNode, error) {
|
||||
return obj, f.walk(obj)
|
||||
}
|
||||
|
||||
func (f findFieldsFilter) walk(node *yaml.RNode) error {
|
||||
switch node.YNode().Kind {
|
||||
case yaml.MappingNode:
|
||||
return node.VisitFields(func(n *yaml.MapNode) error {
|
||||
err := f.walk(n.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
key := n.Key.YNode().Value
|
||||
if contains(f.fields, key) {
|
||||
return f.fieldCallback(n.Value)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
case yaml.SequenceNode:
|
||||
return node.VisitElements(func(n *yaml.RNode) error {
|
||||
return f.walk(n)
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func contains(slice []string, str string) bool {
|
||||
for _, s := range slice {
|
||||
if s == str {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func checkImageTagsFn(imageTag types.Image) fieldCallback {
|
||||
return func(node *yaml.RNode) error {
|
||||
if node.YNode().Kind != yaml.SequenceNode {
|
||||
return nil
|
||||
}
|
||||
|
||||
return node.VisitElements(func(n *yaml.RNode) error {
|
||||
// Look up any fields on the provided node that is named
|
||||
// image.
|
||||
return n.PipeE(yaml.Get("image"), imageTagUpdater{
|
||||
ImageTag: imageTag,
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package imagetag
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
filtertest "sigs.k8s.io/kustomize/api/testutils/filtertest"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
func TestLegacyImageTag_Filter(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
input string
|
||||
expectedOutput string
|
||||
filter LegacyFilter
|
||||
}{
|
||||
"updates multiple images inside containers": {
|
||||
input: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx:1.2.1
|
||||
- image: nginx:2.1.2
|
||||
`,
|
||||
expectedOutput: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
spec:
|
||||
containers:
|
||||
- image: apache@12345
|
||||
- image: apache@12345
|
||||
`,
|
||||
filter: LegacyFilter{
|
||||
ImageTag: types.Image{
|
||||
Name: "nginx",
|
||||
NewName: "apache",
|
||||
Digest: "12345",
|
||||
},
|
||||
},
|
||||
},
|
||||
"updates inside both containers and initContainers": {
|
||||
input: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx:1.2.1
|
||||
- image: tomcat:1.2.3
|
||||
initContainers:
|
||||
- image: nginx:1.2.1
|
||||
- image: apache:1.2.3
|
||||
`,
|
||||
expectedOutput: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
spec:
|
||||
containers:
|
||||
- image: apache:3.2.1
|
||||
- image: tomcat:1.2.3
|
||||
initContainers:
|
||||
- image: apache:3.2.1
|
||||
- image: apache:1.2.3
|
||||
`,
|
||||
filter: LegacyFilter{
|
||||
ImageTag: types.Image{
|
||||
Name: "nginx",
|
||||
NewName: "apache",
|
||||
NewTag: "3.2.1",
|
||||
},
|
||||
},
|
||||
},
|
||||
"updates on multiple depths": {
|
||||
input: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx:1.2.1
|
||||
- image: tomcat:1.2.3
|
||||
template:
|
||||
spec:
|
||||
initContainers:
|
||||
- image: nginx:1.2.1
|
||||
- image: apache:1.2.3
|
||||
`,
|
||||
expectedOutput: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
spec:
|
||||
containers:
|
||||
- image: apache:3.2.1
|
||||
- image: tomcat:1.2.3
|
||||
template:
|
||||
spec:
|
||||
initContainers:
|
||||
- image: apache:3.2.1
|
||||
- image: apache:1.2.3
|
||||
`,
|
||||
filter: LegacyFilter{
|
||||
ImageTag: types.Image{
|
||||
Name: "nginx",
|
||||
NewName: "apache",
|
||||
NewTag: "3.2.1",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for tn, tc := range testCases {
|
||||
t.Run(tn, func(t *testing.T) {
|
||||
filter := tc.filter
|
||||
if !assert.Equal(t,
|
||||
strings.TrimSpace(tc.expectedOutput),
|
||||
strings.TrimSpace(filtertest.RunFilter(t, tc.input, filter))) {
|
||||
t.FailNow()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package imagetag
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/image"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
// imageTagUpdater is an implementation of the kio.Filter interface
|
||||
// that will update the value of the yaml node based on the provided
|
||||
// ImageTag if the current value matches the format of an image reference.
|
||||
type imageTagUpdater struct {
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
ImageTag types.Image `yaml:"imageTag,omitempty"`
|
||||
}
|
||||
|
||||
func (u imageTagUpdater) Filter(rn *yaml.RNode) (*yaml.RNode, error) {
|
||||
if err := yaml.ErrorIfInvalid(rn, yaml.ScalarNode); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
value := rn.YNode().Value
|
||||
|
||||
if !image.IsImageMatched(value, u.ImageTag.Name) {
|
||||
return rn, nil
|
||||
}
|
||||
|
||||
name, tag := image.Split(value)
|
||||
if u.ImageTag.NewName != "" {
|
||||
name = u.ImageTag.NewName
|
||||
}
|
||||
if u.ImageTag.NewTag != "" {
|
||||
tag = ":" + u.ImageTag.NewTag
|
||||
}
|
||||
if u.ImageTag.Digest != "" {
|
||||
tag = "@" + u.ImageTag.Digest
|
||||
}
|
||||
|
||||
return rn.Pipe(yaml.FieldSetter{StringValue: name + tag})
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package labels contains a kio.Filter implementation of the kustomize
|
||||
// labels transformer.
|
||||
package labels
|
||||
@@ -1,55 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package labels
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
)
|
||||
|
||||
func ExampleFilter() {
|
||||
fss := builtinconfig.MakeDefaultConfig().CommonLabels
|
||||
err := kio.Pipeline{
|
||||
Inputs: []kio.Reader{&kio.ByteReader{Reader: bytes.NewBufferString(`
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance
|
||||
`)}},
|
||||
Filters: []kio.Filter{Filter{
|
||||
Labels: map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
FsSlice: fss,
|
||||
}},
|
||||
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
|
||||
}.Execute()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// apiVersion: example.com/v1
|
||||
// kind: Foo
|
||||
// metadata:
|
||||
// name: instance
|
||||
// labels:
|
||||
// foo: bar
|
||||
// ---
|
||||
// apiVersion: example.com/v1
|
||||
// kind: Bar
|
||||
// metadata:
|
||||
// name: instance
|
||||
// labels:
|
||||
// foo: bar
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package labels
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/filters/filtersutil"
|
||||
"sigs.k8s.io/kustomize/api/filters/fsslice"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
type labelMap map[string]string
|
||||
|
||||
// Filter sets labels.
|
||||
type Filter struct {
|
||||
// Labels is the set of labels to apply to the inputs
|
||||
Labels labelMap `yaml:"labels,omitempty"`
|
||||
|
||||
// FsSlice identifies the label fields.
|
||||
FsSlice types.FsSlice
|
||||
}
|
||||
|
||||
var _ kio.Filter = Filter{}
|
||||
|
||||
func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||
keys := filtersutil.SortedMapKeys(f.Labels)
|
||||
_, err := kio.FilterAll(yaml.FilterFunc(
|
||||
func(node *yaml.RNode) (*yaml.RNode, error) {
|
||||
for _, k := range keys {
|
||||
if err := node.PipeE(fsslice.Filter{
|
||||
FsSlice: f.FsSlice,
|
||||
SetValue: fsslice.SetEntry(k, f.Labels[k], yaml.StringTag),
|
||||
CreateKind: yaml.MappingNode, // Labels are MappingNodes.
|
||||
CreateTag: "!!map",
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return node, nil
|
||||
})).Filter(nodes)
|
||||
return nodes, err
|
||||
}
|
||||
@@ -1,413 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package labels
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
filtertest_test "sigs.k8s.io/kustomize/api/testutils/filtertest"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
func TestLabels_Filter(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
input string
|
||||
expectedOutput string
|
||||
filter Filter
|
||||
}{
|
||||
"add": {
|
||||
input: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
labels:
|
||||
hero: batman
|
||||
fiend: riddler
|
||||
`,
|
||||
expectedOutput: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
labels:
|
||||
hero: batman
|
||||
fiend: riddler
|
||||
auto: ford
|
||||
bean: cannellini
|
||||
clown: emmett kelley
|
||||
dragon: smaug
|
||||
`,
|
||||
filter: Filter{
|
||||
Labels: labelMap{
|
||||
"clown": "emmett kelley",
|
||||
"auto": "ford",
|
||||
"dragon": "smaug",
|
||||
"bean": "cannellini",
|
||||
},
|
||||
FsSlice: []types.FieldSpec{
|
||||
{
|
||||
Path: "metadata/labels",
|
||||
CreateIfNotPresent: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"update": {
|
||||
input: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
labels:
|
||||
hero: batman
|
||||
fiend: riddler
|
||||
`,
|
||||
expectedOutput: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
labels:
|
||||
hero: superman
|
||||
fiend: luthor
|
||||
bean: cannellini
|
||||
clown: emmett kelley
|
||||
`,
|
||||
filter: Filter{
|
||||
Labels: labelMap{
|
||||
"clown": "emmett kelley",
|
||||
"hero": "superman",
|
||||
"fiend": "luthor",
|
||||
"bean": "cannellini",
|
||||
}, FsSlice: []types.FieldSpec{
|
||||
{
|
||||
Path: "metadata/labels",
|
||||
CreateIfNotPresent: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"data-fieldspecs": {
|
||||
input: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance
|
||||
`,
|
||||
expectedOutput: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
labels:
|
||||
sleater: kinney
|
||||
a:
|
||||
b:
|
||||
sleater: kinney
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance
|
||||
labels:
|
||||
sleater: kinney
|
||||
a:
|
||||
b:
|
||||
sleater: kinney
|
||||
`,
|
||||
filter: Filter{
|
||||
Labels: labelMap{
|
||||
"sleater": "kinney",
|
||||
},
|
||||
FsSlice: []types.FieldSpec{
|
||||
{
|
||||
Path: "metadata/labels",
|
||||
CreateIfNotPresent: true,
|
||||
},
|
||||
{
|
||||
Path: "a/b",
|
||||
CreateIfNotPresent: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"fieldSpecWithKind": {
|
||||
input: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
---
|
||||
apiVersion: example.com/v2
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance
|
||||
`,
|
||||
expectedOutput: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
labels:
|
||||
cheese: cheddar
|
||||
---
|
||||
apiVersion: example.com/v2
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance
|
||||
labels:
|
||||
cheese: cheddar
|
||||
a:
|
||||
b:
|
||||
cheese: cheddar
|
||||
`,
|
||||
filter: Filter{
|
||||
Labels: labelMap{
|
||||
"cheese": "cheddar",
|
||||
},
|
||||
FsSlice: []types.FieldSpec{
|
||||
{
|
||||
Path: "metadata/labels",
|
||||
CreateIfNotPresent: true,
|
||||
},
|
||||
{
|
||||
Gvk: resid.Gvk{
|
||||
Kind: "Bar",
|
||||
},
|
||||
Path: "a/b",
|
||||
CreateIfNotPresent: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"fieldSpecWithVersion": {
|
||||
input: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
---
|
||||
apiVersion: example.com/v2
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance
|
||||
`,
|
||||
expectedOutput: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
labels:
|
||||
cheese: cheddar
|
||||
a:
|
||||
b:
|
||||
cheese: cheddar
|
||||
---
|
||||
apiVersion: example.com/v2
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance
|
||||
labels:
|
||||
cheese: cheddar
|
||||
`,
|
||||
filter: Filter{
|
||||
Labels: labelMap{
|
||||
"cheese": "cheddar",
|
||||
},
|
||||
FsSlice: []types.FieldSpec{
|
||||
{
|
||||
Path: "metadata/labels",
|
||||
CreateIfNotPresent: true,
|
||||
},
|
||||
{
|
||||
Gvk: resid.Gvk{
|
||||
Version: "v1",
|
||||
},
|
||||
Path: "a/b",
|
||||
CreateIfNotPresent: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"fieldSpecWithVersionInConfigButNoGroupInData": {
|
||||
input: `
|
||||
apiVersion: v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
---
|
||||
apiVersion: v2
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance
|
||||
`,
|
||||
expectedOutput: `
|
||||
apiVersion: v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
labels:
|
||||
cheese: cheddar
|
||||
a:
|
||||
b:
|
||||
cheese: cheddar
|
||||
---
|
||||
apiVersion: v2
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance
|
||||
labels:
|
||||
cheese: cheddar
|
||||
`,
|
||||
filter: Filter{
|
||||
Labels: labelMap{
|
||||
"cheese": "cheddar",
|
||||
},
|
||||
FsSlice: []types.FieldSpec{
|
||||
{
|
||||
Path: "metadata/labels",
|
||||
CreateIfNotPresent: true,
|
||||
},
|
||||
{
|
||||
Gvk: resid.Gvk{
|
||||
Version: "v1",
|
||||
},
|
||||
Path: "a/b",
|
||||
CreateIfNotPresent: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"number": {
|
||||
input: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
labels:
|
||||
hero: batman
|
||||
fiend: riddler
|
||||
`,
|
||||
expectedOutput: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
labels:
|
||||
hero: batman
|
||||
fiend: riddler
|
||||
1: emmett kelley
|
||||
auto: "2"
|
||||
`,
|
||||
filter: Filter{
|
||||
Labels: labelMap{
|
||||
"1": "emmett kelley",
|
||||
"auto": "2",
|
||||
},
|
||||
FsSlice: []types.FieldSpec{
|
||||
{
|
||||
Path: "metadata/labels",
|
||||
CreateIfNotPresent: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// test quoting of values which are not considered strings in yaml 1.1
|
||||
"yaml_1_1_compatibility": {
|
||||
input: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
labels:
|
||||
hero: batman
|
||||
fiend: riddler
|
||||
`,
|
||||
expectedOutput: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
labels:
|
||||
hero: batman
|
||||
fiend: riddler
|
||||
a: "y"
|
||||
b: y1
|
||||
c: "yes"
|
||||
d: yes1
|
||||
e: "true"
|
||||
f: true1
|
||||
`,
|
||||
filter: Filter{
|
||||
Labels: labelMap{
|
||||
"a": "y",
|
||||
"b": "y1",
|
||||
"c": "yes",
|
||||
"d": "yes1",
|
||||
"e": "true",
|
||||
"f": "true1",
|
||||
},
|
||||
FsSlice: []types.FieldSpec{
|
||||
{
|
||||
Path: "metadata/labels",
|
||||
CreateIfNotPresent: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"null_labels": {
|
||||
input: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
labels: null
|
||||
`,
|
||||
expectedOutput: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
labels:
|
||||
a: a1
|
||||
`,
|
||||
filter: Filter{
|
||||
Labels: labelMap{
|
||||
"a": "a1",
|
||||
},
|
||||
FsSlice: []types.FieldSpec{
|
||||
{
|
||||
Path: "metadata/labels",
|
||||
CreateIfNotPresent: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for tn, tc := range testCases {
|
||||
t.Run(tn, func(t *testing.T) {
|
||||
if !assert.Equal(t,
|
||||
strings.TrimSpace(tc.expectedOutput),
|
||||
strings.TrimSpace(filtertest_test.RunFilter(t, tc.input, tc.filter))) {
|
||||
t.FailNow()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package namespace contains a kio.Filter implementation of the kustomize
|
||||
// namespace transformer.
|
||||
//
|
||||
// Special cases for known Kubernetes resources have been hardcoded in addition
|
||||
// to those defined by the FsSlice.
|
||||
package namespace
|
||||
@@ -1,50 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package namespace_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/filters/namespace"
|
||||
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
)
|
||||
|
||||
func ExampleFilter() {
|
||||
fss := builtinconfig.MakeDefaultConfig().NameSpace
|
||||
err := kio.Pipeline{
|
||||
Inputs: []kio.Reader{&kio.ByteReader{Reader: bytes.NewBufferString(`
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance
|
||||
namespace: bar
|
||||
`)}},
|
||||
Filters: []kio.Filter{namespace.Filter{Namespace: "app", FsSlice: fss}},
|
||||
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
|
||||
}.Execute()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// apiVersion: example.com/v1
|
||||
// kind: Foo
|
||||
// metadata:
|
||||
// name: instance
|
||||
// namespace: app
|
||||
// ---
|
||||
// apiVersion: example.com/v1
|
||||
// kind: Bar
|
||||
// metadata:
|
||||
// name: instance
|
||||
// namespace: app
|
||||
}
|
||||
@@ -1,167 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package namespace
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/filters/fsslice"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
type Filter struct {
|
||||
// Namespace is the namespace to apply to the inputs
|
||||
Namespace string `yaml:"namespace,omitempty"`
|
||||
|
||||
// FsSlice contains the FieldSpecs to locate the namespace field
|
||||
FsSlice types.FsSlice `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||
}
|
||||
|
||||
var _ kio.Filter = Filter{}
|
||||
|
||||
func (ns Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||
return kio.FilterAll(yaml.FilterFunc(ns.run)).Filter(nodes)
|
||||
}
|
||||
|
||||
// Run runs the filter on a single node rather than a slice
|
||||
func (ns Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
|
||||
// hacks for hardcoded types -- :(
|
||||
if err := ns.hacks(node); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Remove the fieldspecs that are for hardcoded fields. The fieldspecs
|
||||
// exist for backwards compatibility with other implementations
|
||||
// of this transformation.
|
||||
// This implementation of the namespace transformation
|
||||
// Does not use the fieldspecs for implementing cases which
|
||||
// require hardcoded logic.
|
||||
ns.FsSlice = ns.removeFieldSpecsForHacks(ns.FsSlice)
|
||||
|
||||
// transformations based on data -- :)
|
||||
err := node.PipeE(fsslice.Filter{
|
||||
FsSlice: ns.FsSlice,
|
||||
SetValue: fsslice.SetScalar(ns.Namespace),
|
||||
CreateKind: yaml.ScalarNode, // Namespace is a ScalarNode
|
||||
CreateTag: yaml.StringTag,
|
||||
})
|
||||
return node, err
|
||||
}
|
||||
|
||||
// hacks applies the namespace transforms that are hardcoded rather
|
||||
// than specified through FieldSpecs.
|
||||
func (ns Filter) hacks(obj *yaml.RNode) error {
|
||||
meta, err := obj.GetMeta()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ns.metaNamespaceHack(obj, meta); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ns.roleBindingHack(obj, meta)
|
||||
}
|
||||
|
||||
// metaNamespaceHack is a hack for implementing the namespace transform
|
||||
// for the metadata.namespace field on namespace scoped resources.
|
||||
// namespace scoped resources are determined by NOT being present
|
||||
// in a blacklist of cluster-scoped resource types (by apiVersion and kind).
|
||||
//
|
||||
// This hack should be updated to allow individual resources to specify
|
||||
// if they are cluster scoped through either an annotation on the resources,
|
||||
// or through inlined OpenAPI on the resource as a YAML comment.
|
||||
func (ns Filter) metaNamespaceHack(obj *yaml.RNode, meta yaml.ResourceMeta) error {
|
||||
gvk := fsslice.GetGVK(meta)
|
||||
if !gvk.IsNamespaceableKind() {
|
||||
return nil
|
||||
}
|
||||
f := fsslice.Filter{
|
||||
FsSlice: []types.FieldSpec{
|
||||
{Path: types.MetadataNamespacePath, CreateIfNotPresent: true},
|
||||
},
|
||||
SetValue: fsslice.SetScalar(ns.Namespace),
|
||||
CreateKind: yaml.ScalarNode, // Namespace is a ScalarNode
|
||||
}
|
||||
_, err := f.Filter(obj)
|
||||
return err
|
||||
}
|
||||
|
||||
// roleBindingHack is a hack for implementing the namespace transform
|
||||
// for RoleBinding and ClusterRoleBinding resource types.
|
||||
// RoleBinding and ClusterRoleBinding have namespace set on
|
||||
// elements of the "subjects" field if and only if the subject elements
|
||||
// "name" is "default". Otherwise the namespace is not set.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// kind: RoleBinding
|
||||
// subjects:
|
||||
// - name: "default" # this will have the namespace set
|
||||
// ...
|
||||
// - name: "something-else" # this will not have the namespace set
|
||||
// ...
|
||||
func (ns Filter) roleBindingHack(obj *yaml.RNode, meta yaml.ResourceMeta) error {
|
||||
if meta.Kind != roleBindingKind && meta.Kind != clusterRoleBindingKind {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Lookup the namespace field on all elements.
|
||||
// We should change the fieldspec so this isn't necessary.
|
||||
obj, err := obj.Pipe(yaml.Lookup(subjectsField))
|
||||
if err != nil || yaml.IsEmpty(obj) {
|
||||
return err
|
||||
}
|
||||
|
||||
// add the namespace to each "subject" with name: default
|
||||
err = obj.VisitElements(func(o *yaml.RNode) error {
|
||||
// copied from kunstruct based kustomize NamespaceTransformer plugin
|
||||
// The only case we need to force the namespace
|
||||
// if for the "service account". "default" is
|
||||
// kind of hardcoded here for right now.
|
||||
name, err := o.Pipe(
|
||||
yaml.Lookup("name"), yaml.Match("default"),
|
||||
)
|
||||
if err != nil || yaml.IsEmpty(name) {
|
||||
return err
|
||||
}
|
||||
|
||||
// set the namespace for the default account
|
||||
v := yaml.NewScalarRNode(ns.Namespace)
|
||||
return o.PipeE(
|
||||
yaml.LookupCreate(yaml.ScalarNode, "namespace"),
|
||||
yaml.FieldSetter{Value: v},
|
||||
)
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// removeFieldSpecsForHacks removes from the list fieldspecs that
|
||||
// have hardcoded implementations
|
||||
func (ns Filter) removeFieldSpecsForHacks(fs types.FsSlice) types.FsSlice {
|
||||
var val types.FsSlice
|
||||
for i := range fs {
|
||||
// implemented by metaNamespaceHack
|
||||
if fs[i].Path == types.MetadataNamespacePath {
|
||||
continue
|
||||
}
|
||||
// implemented by roleBindingHack
|
||||
if fs[i].Kind == roleBindingKind && fs[i].Path == subjectsField {
|
||||
continue
|
||||
}
|
||||
// implemented by roleBindingHack
|
||||
if fs[i].Kind == clusterRoleBindingKind && fs[i].Path == subjectsField {
|
||||
continue
|
||||
}
|
||||
val = append(val, fs[i])
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
const (
|
||||
subjectsField = "subjects"
|
||||
roleBindingKind = "RoleBinding"
|
||||
clusterRoleBindingKind = "ClusterRoleBinding"
|
||||
)
|
||||
@@ -1,311 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package namespace_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"sigs.k8s.io/kustomize/api/filters/namespace"
|
||||
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
|
||||
filtertest_test "sigs.k8s.io/kustomize/api/testutils/filtertest"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
var tests = []TestCase{
|
||||
{
|
||||
name: "add",
|
||||
input: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance
|
||||
`,
|
||||
expected: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
namespace: foo
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance
|
||||
namespace: foo
|
||||
`,
|
||||
filter: namespace.Filter{Namespace: "foo"},
|
||||
},
|
||||
|
||||
{
|
||||
name: "null_ns",
|
||||
input: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
namespace: null
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance
|
||||
namespace: null
|
||||
`,
|
||||
expected: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
namespace: foo
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance
|
||||
namespace: foo
|
||||
`,
|
||||
filter: namespace.Filter{Namespace: "foo"},
|
||||
},
|
||||
|
||||
{
|
||||
name: "add-recurse",
|
||||
input: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: Bar
|
||||
`,
|
||||
expected: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
namespace: foo
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: Bar
|
||||
metadata:
|
||||
namespace: foo
|
||||
`,
|
||||
filter: namespace.Filter{Namespace: "foo"},
|
||||
},
|
||||
|
||||
{
|
||||
name: "update",
|
||||
input: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
# update this namespace
|
||||
namespace: bar
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance
|
||||
namespace: bar
|
||||
`,
|
||||
expected: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
# update this namespace
|
||||
namespace: foo
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance
|
||||
namespace: foo
|
||||
`,
|
||||
filter: namespace.Filter{Namespace: "foo"},
|
||||
},
|
||||
|
||||
{
|
||||
name: "update-rolebinding",
|
||||
input: `
|
||||
apiVersion: example.com/v1
|
||||
kind: RoleBinding
|
||||
subjects:
|
||||
- name: default
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: RoleBinding
|
||||
subjects:
|
||||
- name: default
|
||||
namespace: foo
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: RoleBinding
|
||||
subjects:
|
||||
- name: something
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: RoleBinding
|
||||
subjects:
|
||||
- name: something
|
||||
namespace: foo
|
||||
`,
|
||||
expected: `
|
||||
apiVersion: example.com/v1
|
||||
kind: RoleBinding
|
||||
subjects:
|
||||
- name: default
|
||||
namespace: bar
|
||||
metadata:
|
||||
namespace: bar
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: RoleBinding
|
||||
subjects:
|
||||
- name: default
|
||||
namespace: bar
|
||||
metadata:
|
||||
namespace: bar
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: RoleBinding
|
||||
subjects:
|
||||
- name: something
|
||||
metadata:
|
||||
namespace: bar
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: RoleBinding
|
||||
subjects:
|
||||
- name: something
|
||||
namespace: foo
|
||||
metadata:
|
||||
namespace: bar
|
||||
`,
|
||||
filter: namespace.Filter{Namespace: "bar"},
|
||||
},
|
||||
|
||||
{
|
||||
name: "update-clusterrolebinding",
|
||||
input: `
|
||||
apiVersion: example.com/v1
|
||||
kind: ClusterRoleBinding
|
||||
subjects:
|
||||
- name: default
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: ClusterRoleBinding
|
||||
subjects:
|
||||
- name: default
|
||||
namespace: foo
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: ClusterRoleBinding
|
||||
subjects:
|
||||
- name: something
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: ClusterRoleBinding
|
||||
subjects:
|
||||
- name: something
|
||||
namespace: foo
|
||||
`,
|
||||
expected: `
|
||||
apiVersion: example.com/v1
|
||||
kind: ClusterRoleBinding
|
||||
subjects:
|
||||
- name: default
|
||||
namespace: bar
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: ClusterRoleBinding
|
||||
subjects:
|
||||
- name: default
|
||||
namespace: bar
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: ClusterRoleBinding
|
||||
subjects:
|
||||
- name: something
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: ClusterRoleBinding
|
||||
subjects:
|
||||
- name: something
|
||||
namespace: foo
|
||||
`,
|
||||
filter: namespace.Filter{Namespace: "bar"},
|
||||
},
|
||||
|
||||
{
|
||||
name: "data-fieldspecs",
|
||||
input: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance
|
||||
`,
|
||||
expected: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
namespace: foo
|
||||
a:
|
||||
b:
|
||||
c: foo
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance
|
||||
namespace: foo
|
||||
a:
|
||||
b:
|
||||
c: foo
|
||||
`,
|
||||
filter: namespace.Filter{Namespace: "foo"},
|
||||
fsslice: []types.FieldSpec{
|
||||
{
|
||||
Path: "a/b/c",
|
||||
CreateIfNotPresent: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
type TestCase struct {
|
||||
name string
|
||||
input string
|
||||
expected string
|
||||
filter namespace.Filter
|
||||
fsslice types.FsSlice
|
||||
}
|
||||
|
||||
var config = builtinconfig.MakeDefaultConfig()
|
||||
|
||||
func TestNamespace_Filter(t *testing.T) {
|
||||
for i := range tests {
|
||||
test := tests[i]
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
test.filter.FsSlice = append(config.NameSpace, test.fsslice...)
|
||||
if !assert.Equal(t,
|
||||
strings.TrimSpace(test.expected),
|
||||
strings.TrimSpace(
|
||||
filtertest_test.RunFilter(t, test.input, test.filter))) {
|
||||
t.FailNow()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package namespace contains a kio.Filter implementation of the kustomize
|
||||
// patchjson6902 transformer
|
||||
package patchjson6902
|
||||
@@ -1,55 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package patchjson6902
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
)
|
||||
|
||||
func ExampleFilter() {
|
||||
err := kio.Pipeline{
|
||||
Inputs: []kio.Reader{&kio.ByteReader{Reader: bytes.NewBufferString(`
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance
|
||||
namespace: bar
|
||||
`)}},
|
||||
Filters: []kio.Filter{
|
||||
Filter{
|
||||
Patch: `
|
||||
- op: replace
|
||||
path: /metadata/namespace
|
||||
value: "ns"
|
||||
`,
|
||||
},
|
||||
},
|
||||
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
|
||||
}.Execute()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// apiVersion: example.com/v1
|
||||
// kind: Foo
|
||||
// metadata:
|
||||
// name: instance
|
||||
// namespace: ns
|
||||
// ---
|
||||
// apiVersion: example.com/v1
|
||||
// kind: Bar
|
||||
// metadata:
|
||||
// name: instance
|
||||
// namespace: ns
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package patchjson6902
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
jsonpatch "github.com/evanphx/json-patch"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
k8syaml "sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
type Filter struct {
|
||||
Patch string
|
||||
|
||||
decodedPatch jsonpatch.Patch
|
||||
}
|
||||
|
||||
var _ kio.Filter = Filter{}
|
||||
|
||||
func (pf Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||
decodedPatch, err := pf.decodePatch()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pf.decodedPatch = decodedPatch
|
||||
return kio.FilterAll(yaml.FilterFunc(pf.run)).Filter(nodes)
|
||||
}
|
||||
|
||||
func (pf Filter) decodePatch() (jsonpatch.Patch, error) {
|
||||
patch := pf.Patch
|
||||
// If the patch doesn't look like a JSON6902 patch, we
|
||||
// try to parse it to json.
|
||||
if !strings.HasPrefix(pf.Patch, "[") {
|
||||
p, err := k8syaml.YAMLToJSON([]byte(patch))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
patch = string(p)
|
||||
}
|
||||
decodedPatch, err := jsonpatch.DecodePatch([]byte(patch))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return decodedPatch, nil
|
||||
}
|
||||
|
||||
func (pf Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
|
||||
// We don't actually use the kyaml library for manipulating the
|
||||
// yaml here. We just marshal it to json and rely on the
|
||||
// jsonpatch library to take care of applying the patch.
|
||||
// This means ordering might not be preserved with this filter.
|
||||
b, err := node.MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, err := pf.decodedPatch.Apply(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = node.UnmarshalJSON(res)
|
||||
return node, err
|
||||
}
|
||||
@@ -1,173 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package patchjson6902
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
filtertest "sigs.k8s.io/kustomize/api/testutils/filtertest"
|
||||
)
|
||||
|
||||
const input = `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: myDeploy
|
||||
spec:
|
||||
replica: 2
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
old-label: old-value
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx
|
||||
name: nginx
|
||||
`
|
||||
|
||||
func TestSomething(t *testing.T) {
|
||||
testCases := []struct {
|
||||
testName string
|
||||
input string
|
||||
filter Filter
|
||||
expectedOutput string
|
||||
}{
|
||||
{
|
||||
testName: "single operation, json",
|
||||
input: input,
|
||||
filter: Filter{
|
||||
Patch: `[
|
||||
{"op": "replace", "path": "/spec/replica", "value": 5}
|
||||
]`,
|
||||
},
|
||||
expectedOutput: `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: myDeploy
|
||||
spec:
|
||||
replica: 5
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
old-label: old-value
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx
|
||||
name: nginx
|
||||
`,
|
||||
},
|
||||
{
|
||||
testName: "multiple operations, json",
|
||||
input: input,
|
||||
filter: Filter{
|
||||
Patch: `[
|
||||
{"op": "replace", "path": "/spec/template/spec/containers/0/name", "value": "my-nginx"},
|
||||
{"op": "add", "path": "/spec/replica", "value": 999},
|
||||
{"op": "add", "path": "/spec/template/spec/containers/0/command", "value": ["arg1", "arg2", "arg3"]}
|
||||
]`,
|
||||
},
|
||||
expectedOutput: `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: myDeploy
|
||||
spec:
|
||||
replica: 999
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
old-label: old-value
|
||||
spec:
|
||||
containers:
|
||||
- command:
|
||||
- arg1
|
||||
- arg2
|
||||
- arg3
|
||||
image: nginx
|
||||
name: my-nginx
|
||||
`,
|
||||
},
|
||||
{
|
||||
testName: "single operation, yaml",
|
||||
input: input,
|
||||
filter: Filter{
|
||||
Patch: `
|
||||
- op: replace
|
||||
path: /spec/replica
|
||||
value: 5
|
||||
`,
|
||||
},
|
||||
expectedOutput: `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: myDeploy
|
||||
spec:
|
||||
replica: 5
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
old-label: old-value
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx
|
||||
name: nginx
|
||||
`,
|
||||
},
|
||||
{
|
||||
testName: "multiple operations, yaml",
|
||||
input: input,
|
||||
filter: Filter{
|
||||
Patch: `
|
||||
- op: replace
|
||||
path: /spec/template/spec/containers/0/name
|
||||
value: my-nginx
|
||||
- op: add
|
||||
path: /spec/replica
|
||||
value: 999
|
||||
- op: add
|
||||
path: /spec/template/spec/containers/0/command
|
||||
value:
|
||||
- arg1
|
||||
- arg2
|
||||
- arg3
|
||||
`,
|
||||
},
|
||||
expectedOutput: `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: myDeploy
|
||||
spec:
|
||||
replica: 999
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
old-label: old-value
|
||||
spec:
|
||||
containers:
|
||||
- command:
|
||||
- arg1
|
||||
- arg2
|
||||
- arg3
|
||||
image: nginx
|
||||
name: my-nginx
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.testName, func(t *testing.T) {
|
||||
if !assert.Equal(t,
|
||||
strings.TrimSpace(tc.expectedOutput),
|
||||
strings.TrimSpace(
|
||||
filtertest.RunFilter(t, tc.input, tc.filter))) {
|
||||
t.FailNow()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package patchstrategicmerge contains a kio.Filter implementation of the
|
||||
// kustomize strategic merge patch transformer.
|
||||
package patchstrategicmerge
|
||||
@@ -1,49 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package patchstrategicmerge
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
func ExampleFilter() {
|
||||
err := kio.Pipeline{
|
||||
Inputs: []kio.Reader{&kio.ByteReader{Reader: bytes.NewBufferString(`
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
spec:
|
||||
replicas: 3
|
||||
`)}},
|
||||
Filters: []kio.Filter{Filter{
|
||||
Patch: yaml.MustParse(`
|
||||
spec:
|
||||
template:
|
||||
containers:
|
||||
- image: nginx
|
||||
`),
|
||||
}},
|
||||
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
|
||||
}.Execute()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// apiVersion: example.com/v1
|
||||
// kind: Foo
|
||||
// metadata:
|
||||
// name: instance
|
||||
// spec:
|
||||
// replicas: 3
|
||||
// template:
|
||||
// containers:
|
||||
// - image: nginx
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package patchstrategicmerge
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml/merge2"
|
||||
)
|
||||
|
||||
type Filter struct {
|
||||
Patch *yaml.RNode
|
||||
}
|
||||
|
||||
var _ kio.Filter = Filter{}
|
||||
|
||||
func (pf Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||
return kio.FilterAll(yaml.FilterFunc(pf.run)).Filter(nodes)
|
||||
}
|
||||
|
||||
func (pf Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
|
||||
return merge2.Merge(pf.Patch, node)
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
package patchstrategicmerge
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
filtertest "sigs.k8s.io/kustomize/api/testutils/filtertest"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
func TestFilter(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
input string
|
||||
patch *yaml.RNode
|
||||
expected string
|
||||
}{
|
||||
"simple patch": {
|
||||
input: `
|
||||
apiVersion: apps/v1
|
||||
metadata:
|
||||
name: myDeploy
|
||||
kind: Deployment
|
||||
`,
|
||||
patch: yaml.MustParse(`
|
||||
metadata:
|
||||
name: yourDeploy
|
||||
`),
|
||||
expected: `
|
||||
apiVersion: apps/v1
|
||||
metadata:
|
||||
name: yourDeploy
|
||||
kind: Deployment
|
||||
`,
|
||||
},
|
||||
"nested patch": {
|
||||
input: `
|
||||
apiVersion: apps/v1
|
||||
metadata:
|
||||
name: myDeploy
|
||||
kind: Deployment
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
args:
|
||||
- abc
|
||||
`,
|
||||
patch: yaml.MustParse(`
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
args:
|
||||
- def
|
||||
`),
|
||||
expected: `
|
||||
apiVersion: apps/v1
|
||||
metadata:
|
||||
name: myDeploy
|
||||
kind: Deployment
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
args:
|
||||
- def
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
||||
for tn, tc := range testCases {
|
||||
t.Run(tn, func(t *testing.T) {
|
||||
f := Filter{
|
||||
Patch: tc.patch,
|
||||
}
|
||||
if !assert.Equal(t,
|
||||
strings.TrimSpace(tc.expected),
|
||||
strings.TrimSpace(
|
||||
filtertest.RunFilter(t, tc.input, f))) {
|
||||
t.FailNow()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package prefixsuffix contains a kio.Filter implementation of the kustomize
|
||||
// PrefixSuffixTransformer.
|
||||
package prefixsuffix
|
||||
@@ -1,47 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package prefixsuffix_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/filters/prefixsuffix"
|
||||
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
)
|
||||
|
||||
func ExampleFilter() {
|
||||
fss := builtinconfig.MakeDefaultConfig().NamePrefix
|
||||
err := kio.Pipeline{
|
||||
Inputs: []kio.Reader{&kio.ByteReader{Reader: bytes.NewBufferString(`
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance
|
||||
`)}},
|
||||
Filters: []kio.Filter{prefixsuffix.Filter{Prefix: "baz-", FsSlice: fss}},
|
||||
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
|
||||
}.Execute()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// apiVersion: example.com/v1
|
||||
// kind: Foo
|
||||
// metadata:
|
||||
// name: baz-instance
|
||||
// ---
|
||||
// apiVersion: example.com/v1
|
||||
// kind: Bar
|
||||
// metadata:
|
||||
// name: baz-instance
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package prefixsuffix
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/filters/fsslice"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
// Filter applies resource name prefix's and suffix's using the fieldSpecs
|
||||
type Filter struct {
|
||||
Prefix string `json:"prefix,omitempty" yaml:"prefix,omitempty"`
|
||||
Suffix string `json:"suffix,omitempty" yaml:"suffix,omitempty"`
|
||||
|
||||
FsSlice types.FsSlice `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||
}
|
||||
|
||||
var _ kio.Filter = Filter{}
|
||||
|
||||
func (ns Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||
return kio.FilterAll(yaml.FilterFunc(ns.run)).Filter(nodes)
|
||||
}
|
||||
|
||||
// Run runs the filter on a single node rather than a slice
|
||||
func (ns Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
|
||||
// transformations based on data -- :)
|
||||
err := node.PipeE(fsslice.Filter{
|
||||
FsSlice: ns.FsSlice,
|
||||
SetValue: ns.set,
|
||||
CreateKind: yaml.ScalarNode, // Name is a ScalarNode
|
||||
CreateTag: yaml.StringTag,
|
||||
})
|
||||
return node, err
|
||||
}
|
||||
|
||||
func (ns Filter) set(node *yaml.RNode) error {
|
||||
return fsslice.SetScalar(fmt.Sprintf(
|
||||
"%s%s%s", ns.Prefix, node.YNode().Value, ns.Suffix))(node)
|
||||
}
|
||||
@@ -1,167 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package prefixsuffix_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"sigs.k8s.io/kustomize/api/filters/prefixsuffix"
|
||||
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
|
||||
filtertest_test "sigs.k8s.io/kustomize/api/testutils/filtertest"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
var tests = []TestCase{
|
||||
{
|
||||
name: "prefix",
|
||||
input: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance
|
||||
`,
|
||||
expected: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: foo-instance
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: foo-instance
|
||||
`,
|
||||
filter: prefixsuffix.Filter{Prefix: "foo-"},
|
||||
},
|
||||
|
||||
{
|
||||
name: "suffix",
|
||||
input: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance
|
||||
`,
|
||||
expected: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance-foo
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance-foo
|
||||
`,
|
||||
filter: prefixsuffix.Filter{Suffix: "-foo"},
|
||||
},
|
||||
|
||||
{
|
||||
name: "prefix-suffix",
|
||||
input: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance
|
||||
`,
|
||||
expected: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: bar-instance-foo
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: bar-instance-foo
|
||||
`,
|
||||
filter: prefixsuffix.Filter{Prefix: "bar-", Suffix: "-foo"},
|
||||
},
|
||||
|
||||
{
|
||||
name: "data-fieldspecs",
|
||||
input: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
a:
|
||||
b:
|
||||
c: d
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance
|
||||
a:
|
||||
b:
|
||||
c: d
|
||||
`,
|
||||
expected: `
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: foo-instance
|
||||
a:
|
||||
b:
|
||||
c: foo-d
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: foo-instance
|
||||
a:
|
||||
b:
|
||||
c: foo-d
|
||||
`,
|
||||
filter: prefixsuffix.Filter{Prefix: "foo-"},
|
||||
fsslice: []types.FieldSpec{
|
||||
{
|
||||
Path: "a/b/c",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
type TestCase struct {
|
||||
name string
|
||||
input string
|
||||
expected string
|
||||
filter prefixsuffix.Filter
|
||||
fsslice types.FsSlice
|
||||
}
|
||||
|
||||
var config = builtinconfig.MakeDefaultConfig()
|
||||
|
||||
func TestFilter(t *testing.T) {
|
||||
for i := range tests {
|
||||
test := tests[i]
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
test.filter.FsSlice = append(config.NamePrefix, test.fsslice...)
|
||||
if !assert.Equal(t,
|
||||
strings.TrimSpace(test.expected),
|
||||
strings.TrimSpace(
|
||||
filtertest_test.RunFilter(t, test.input, test.filter))) {
|
||||
t.FailNow()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package replicacount contains a kio.Filter implementation of the kustomize
|
||||
// ReplicaCountTransformer.
|
||||
package replicacount
|
||||
@@ -1,64 +0,0 @@
|
||||
package replicacount
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
)
|
||||
|
||||
func ExampleFilter() {
|
||||
err := kio.Pipeline{
|
||||
Inputs: []kio.Reader{&kio.ByteReader{Reader: bytes.NewBufferString(`
|
||||
apiVersion: example.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: instance
|
||||
spec:
|
||||
template:
|
||||
replicas: 5
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
kind: Bar
|
||||
metadata:
|
||||
name: instance
|
||||
spec:
|
||||
template:
|
||||
replicas: 5
|
||||
`)}},
|
||||
Filters: []kio.Filter{Filter{
|
||||
Replica: types.Replica{
|
||||
Count: 42,
|
||||
Name: "instance",
|
||||
},
|
||||
FsSlice: types.FsSlice{
|
||||
{
|
||||
Path: "spec/template/replicas",
|
||||
},
|
||||
},
|
||||
}},
|
||||
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
|
||||
}.Execute()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// apiVersion: example.com/v1
|
||||
// kind: Foo
|
||||
// metadata:
|
||||
// name: instance
|
||||
// spec:
|
||||
// template:
|
||||
// replicas: 42
|
||||
// ---
|
||||
// apiVersion: example.com/v1
|
||||
// kind: Bar
|
||||
// metadata:
|
||||
// name: instance
|
||||
// spec:
|
||||
// template:
|
||||
// replicas: 42
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package replicacount
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/filters/fsslice"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
// Filter updates/sets replicas fields using the fieldSpecs
|
||||
type Filter struct {
|
||||
Replica types.Replica `json:"replica,omitempty" yaml:"replica,omitempty"`
|
||||
|
||||
// FsSlice contains the FieldSpecs to locate the namespace field
|
||||
FsSlice types.FsSlice `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||
}
|
||||
|
||||
var _ kio.Filter = Filter{}
|
||||
|
||||
func (rc Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||
return kio.FilterAll(yaml.FilterFunc(rc.run)).Filter(nodes)
|
||||
}
|
||||
|
||||
// run processes each node individually.
|
||||
func (rc Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
|
||||
meta, err := node.GetMeta()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// only update resources where the name matches the Replica name.
|
||||
if meta.Name != rc.Replica.Name {
|
||||
return node, nil
|
||||
}
|
||||
|
||||
err = node.PipeE(fsslice.Filter{
|
||||
FsSlice: rc.FsSlice,
|
||||
SetValue: rc.set,
|
||||
CreateKind: yaml.ScalarNode, // replicas is a ScalarNode
|
||||
CreateTag: yaml.IntTag,
|
||||
})
|
||||
return node, err
|
||||
}
|
||||
|
||||
func (rc Filter) set(node *yaml.RNode) error {
|
||||
return fsslice.SetScalar(strconv.FormatInt(rc.Replica.Count, 10))(node)
|
||||
}
|
||||
@@ -1,199 +0,0 @@
|
||||
package replicacount
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
|
||||
filtertest_test "sigs.k8s.io/kustomize/api/testutils/filtertest"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
func TestFilter(t *testing.T) {
|
||||
var config = builtinconfig.MakeDefaultConfig()
|
||||
|
||||
testCases := map[string]struct {
|
||||
input string
|
||||
expected string
|
||||
filter Filter
|
||||
fsslice types.FsSlice
|
||||
}{
|
||||
"update field": {
|
||||
input: `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: dep
|
||||
spec:
|
||||
replicas: 5
|
||||
`,
|
||||
expected: `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: dep
|
||||
spec:
|
||||
replicas: 42
|
||||
`,
|
||||
filter: Filter{
|
||||
Replica: types.Replica{
|
||||
Name: "dep",
|
||||
Count: 42,
|
||||
},
|
||||
},
|
||||
fsslice: types.FsSlice{
|
||||
{
|
||||
Path: "spec/replicas",
|
||||
},
|
||||
},
|
||||
},
|
||||
"add field": {
|
||||
input: `
|
||||
apiVersion: custom/v1
|
||||
kind: Custom
|
||||
metadata:
|
||||
name: cus
|
||||
spec:
|
||||
template:
|
||||
other: something
|
||||
`,
|
||||
expected: `
|
||||
apiVersion: custom/v1
|
||||
kind: Custom
|
||||
metadata:
|
||||
name: cus
|
||||
spec:
|
||||
template:
|
||||
other: something
|
||||
replicas: 42
|
||||
`,
|
||||
filter: Filter{
|
||||
Replica: types.Replica{
|
||||
Name: "cus",
|
||||
Count: 42,
|
||||
},
|
||||
},
|
||||
fsslice: types.FsSlice{
|
||||
{
|
||||
Path: "spec/template/replicas",
|
||||
CreateIfNotPresent: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"add_field_null": {
|
||||
input: `
|
||||
apiVersion: custom/v1
|
||||
kind: Custom
|
||||
metadata:
|
||||
name: cus
|
||||
spec:
|
||||
template:
|
||||
other: something
|
||||
replicas: null
|
||||
`,
|
||||
expected: `
|
||||
apiVersion: custom/v1
|
||||
kind: Custom
|
||||
metadata:
|
||||
name: cus
|
||||
spec:
|
||||
template:
|
||||
other: something
|
||||
replicas: 42
|
||||
`,
|
||||
filter: Filter{
|
||||
Replica: types.Replica{
|
||||
Name: "cus",
|
||||
Count: 42,
|
||||
},
|
||||
},
|
||||
fsslice: types.FsSlice{
|
||||
{
|
||||
Path: "spec/template/replicas",
|
||||
CreateIfNotPresent: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
"no update if CreateIfNotPresent is false": {
|
||||
input: `
|
||||
apiVersion: custom/v1
|
||||
kind: Custom
|
||||
metadata:
|
||||
name: cus
|
||||
spec:
|
||||
template:
|
||||
other: something
|
||||
`,
|
||||
expected: `
|
||||
apiVersion: custom/v1
|
||||
kind: Custom
|
||||
metadata:
|
||||
name: cus
|
||||
spec:
|
||||
template:
|
||||
other: something
|
||||
`,
|
||||
filter: Filter{
|
||||
Replica: types.Replica{
|
||||
Name: "cus",
|
||||
Count: 42,
|
||||
},
|
||||
},
|
||||
fsslice: types.FsSlice{
|
||||
{
|
||||
Path: "spec/template/replicas",
|
||||
},
|
||||
},
|
||||
},
|
||||
"update multiple fields": {
|
||||
input: `
|
||||
apiVersion: custom/v1
|
||||
kind: Custom
|
||||
metadata:
|
||||
name: cus
|
||||
spec:
|
||||
replicas: 5
|
||||
template:
|
||||
replicas: 5
|
||||
`,
|
||||
expected: `
|
||||
apiVersion: custom/v1
|
||||
kind: Custom
|
||||
metadata:
|
||||
name: cus
|
||||
spec:
|
||||
replicas: 42
|
||||
template:
|
||||
replicas: 42
|
||||
`,
|
||||
filter: Filter{
|
||||
Replica: types.Replica{
|
||||
Name: "cus",
|
||||
Count: 42,
|
||||
},
|
||||
},
|
||||
fsslice: types.FsSlice{
|
||||
{
|
||||
Path: "spec/template/replicas",
|
||||
},
|
||||
{
|
||||
Path: "spec/replicas",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for tn, tc := range testCases {
|
||||
t.Run(tn, func(t *testing.T) {
|
||||
tc.filter.FsSlice = append(config.Replicas, tc.fsslice...)
|
||||
if !assert.Equal(t,
|
||||
strings.TrimSpace(tc.expected),
|
||||
strings.TrimSpace(
|
||||
filtertest_test.RunFilter(t, tc.input, tc.filter))) {
|
||||
t.FailNow()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package valueadd
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/filesys"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
// An 'Add' operation aspiring to IETF RFC 6902 JSON.
|
||||
//
|
||||
// The filter tries to add a value to a node at a particular field path.
|
||||
//
|
||||
// Kinds of target fields:
|
||||
//
|
||||
// - Non-existent target field.
|
||||
//
|
||||
// The field will be added and the value inserted.
|
||||
//
|
||||
// - Existing field, scalar or map.
|
||||
//
|
||||
// E.g. 'spec/template/spec/containers/[name:nginx]/image'
|
||||
//
|
||||
// This behaves like an IETF RFC 6902 Replace operation would;
|
||||
// the existing value is replaced without complaint, even though
|
||||
// this is an Add operation. In contrast, a Replace operation
|
||||
// must fail (report an error) if the field doesn't exist.
|
||||
//
|
||||
// - Existing field, list (array)
|
||||
// Not supported yet.
|
||||
// TODO: Honor fields with RFC-6902-style array indices
|
||||
// TODO: like 'spec/template/spec/containers/2'
|
||||
// TODO: Modify kyaml/yaml/PathGetter to allow this.
|
||||
// The value will be inserted into the array at the given position,
|
||||
// shifting other contents. To instead replace an array entry, use
|
||||
// an implementation of an IETF RFC 6902 Replace operation.
|
||||
//
|
||||
// For the common case of a filepath in the field value, and a desire
|
||||
// to add the value to the filepath (rather than replace the filepath),
|
||||
// use a non-zero value of FilePathPosition (see below).
|
||||
type Filter struct {
|
||||
// Value is the value to add.
|
||||
//
|
||||
// Empty values are disallowed, i.e. this filter isn't intended
|
||||
// for use in erasing or removing fields. For that, use a filter
|
||||
// more aligned with the IETF RFC 6902 JSON Remove operation.
|
||||
//
|
||||
// At the time of writing, Value's value should be a simple string,
|
||||
// not a JSON document. This particular filter focuses on easing
|
||||
// injection of a single-sourced cloud project and/or cluster name
|
||||
// into various fields, especially namespace and various filepath
|
||||
// specifications.
|
||||
Value string
|
||||
|
||||
// FieldPath is a JSON-style path to the field intended to hold the value.
|
||||
FieldPath string
|
||||
|
||||
// FilePathPosition is a filepath field index.
|
||||
//
|
||||
// Call the value of this field _i_.
|
||||
//
|
||||
// If _i_ is zero, negative or unspecified, this field has no effect.
|
||||
//
|
||||
// If _i_ is > 0, then it's assumed that
|
||||
// - 'Value' is a string that can work as a directory or file name,
|
||||
// - the field value intended for replacement holds a filepath.
|
||||
//
|
||||
// The filepath is split into a string slice, the value is inserted
|
||||
// at position [i-1], shifting the rest of the path to the right.
|
||||
// A value of i==1 puts the new value at the start of the path.
|
||||
// This change never converts an absolute path to a relative path,
|
||||
// meaning adding a new field at position i==1 will preserve a
|
||||
// leading slash. E.g. if Value == 'PEACH'
|
||||
//
|
||||
// OLD : NEW : FilePathPosition
|
||||
// --------------------------------------------------------
|
||||
// {empty} : PEACH : irrelevant
|
||||
// / : /PEACH : irrelevant
|
||||
// pie : PEACH/pie : 1 (or less to prefix)
|
||||
// /pie : /PEACH/pie : 1 (or less to prefix)
|
||||
// raw : raw/PEACH : 2 (or more to postfix)
|
||||
// /raw : /raw/PEACH : 2 (or more to postfix)
|
||||
// a/nice/warm/pie : a/nice/warm/PEACH/pie : 4
|
||||
// /a/nice/warm/pie : /a/nice/warm/PEACH/pie : 4
|
||||
//
|
||||
// For robustness (liberal input, conservative output) FilePathPosition
|
||||
// values that that are too large to index the split filepath result in a
|
||||
// postfix rather than an error. So use 1 to prefix, 9999 to postfix.
|
||||
FilePathPosition int `json:"filePathPosition,omitempty" yaml:"filePathPosition,omitempty"`
|
||||
}
|
||||
|
||||
var _ kio.Filter = Filter{}
|
||||
|
||||
func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||
_, err := kio.FilterAll(yaml.FilterFunc(
|
||||
func(node *yaml.RNode) (*yaml.RNode, error) {
|
||||
fields := strings.Split(f.FieldPath, "/")
|
||||
// TODO: support SequenceNode.
|
||||
// Presumably here one could look for array indices (digits) at
|
||||
// the end of the field path (as described in IETF RFC 6902 JSON),
|
||||
// and if found, take it as a signal that this should be a
|
||||
// SequenceNode instead of a ScalarNode, and insert the value
|
||||
// into the proper slot, shifting every over.
|
||||
n, err := node.Pipe(yaml.LookupCreate(yaml.ScalarNode, fields...))
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
// TODO: allow more kinds
|
||||
if err := yaml.ErrorIfInvalid(n, yaml.ScalarNode); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newValue := f.Value
|
||||
if f.FilePathPosition > 0 {
|
||||
newValue = filesys.InsertPathPart(
|
||||
n.YNode().Value, f.FilePathPosition-1, newValue)
|
||||
}
|
||||
return n.Pipe(yaml.FieldSetter{StringValue: newValue})
|
||||
})).Filter(nodes)
|
||||
return nodes, err
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package valueadd
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
filtertest_test "sigs.k8s.io/kustomize/api/testutils/filtertest"
|
||||
)
|
||||
|
||||
const someResource = `
|
||||
kind: SomeKind
|
||||
spec:
|
||||
resourceRef:
|
||||
external: projects/whatever
|
||||
`
|
||||
|
||||
func TestValueAddFilter(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
input string
|
||||
expectedOutput string
|
||||
filter Filter
|
||||
}{
|
||||
"simpleAdd": {
|
||||
input: `
|
||||
kind: SomeKind
|
||||
`,
|
||||
expectedOutput: `
|
||||
kind: SomeKind
|
||||
spec:
|
||||
resourceRef:
|
||||
external: valueAdded
|
||||
`,
|
||||
filter: Filter{
|
||||
Value: "valueAdded",
|
||||
FieldPath: "spec/resourceRef/external",
|
||||
},
|
||||
},
|
||||
"replaceExisting": {
|
||||
input: someResource,
|
||||
expectedOutput: `
|
||||
kind: SomeKind
|
||||
spec:
|
||||
resourceRef:
|
||||
external: valueAdded
|
||||
`,
|
||||
filter: Filter{
|
||||
Value: "valueAdded",
|
||||
FieldPath: "spec/resourceRef/external",
|
||||
},
|
||||
},
|
||||
"prefixExisting": {
|
||||
input: someResource,
|
||||
expectedOutput: `
|
||||
kind: SomeKind
|
||||
spec:
|
||||
resourceRef:
|
||||
external: valueAdded/projects/whatever
|
||||
`,
|
||||
filter: Filter{
|
||||
Value: "valueAdded",
|
||||
FieldPath: "spec/resourceRef/external",
|
||||
FilePathPosition: 1,
|
||||
},
|
||||
},
|
||||
"postfixExisting": {
|
||||
input: someResource,
|
||||
expectedOutput: `
|
||||
kind: SomeKind
|
||||
spec:
|
||||
resourceRef:
|
||||
external: projects/whatever/valueAdded
|
||||
`,
|
||||
filter: Filter{
|
||||
Value: "valueAdded",
|
||||
FieldPath: "spec/resourceRef/external",
|
||||
FilePathPosition: 99,
|
||||
},
|
||||
},
|
||||
"placeInMiddleOfExisting": {
|
||||
input: someResource,
|
||||
expectedOutput: `
|
||||
kind: SomeKind
|
||||
spec:
|
||||
resourceRef:
|
||||
external: projects/valueAdded/whatever
|
||||
`,
|
||||
filter: Filter{
|
||||
Value: "valueAdded",
|
||||
FieldPath: "spec/resourceRef/external",
|
||||
FilePathPosition: 2,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for tn, tc := range testCases {
|
||||
t.Run(tn, func(t *testing.T) {
|
||||
filter := tc.filter
|
||||
if !assert.Equal(t,
|
||||
strings.TrimSpace(tc.expectedOutput),
|
||||
strings.TrimSpace(filtertest_test.RunFilter(t, tc.input, filter))) {
|
||||
t.FailNow()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
21
api/go.mod
21
api/go.mod
@@ -1,21 +0,0 @@
|
||||
module sigs.k8s.io/kustomize/api
|
||||
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/evanphx/json-patch v4.5.0+incompatible
|
||||
github.com/go-openapi/spec v0.19.5
|
||||
github.com/golangci/golangci-lint v1.21.0
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/stretchr/testify v1.4.0
|
||||
github.com/yujunz/go-getter v1.4.1-lite
|
||||
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff
|
||||
gopkg.in/yaml.v2 v2.2.8
|
||||
k8s.io/api v0.17.0
|
||||
k8s.io/apimachinery v0.17.0
|
||||
k8s.io/client-go v0.17.0
|
||||
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a
|
||||
sigs.k8s.io/kustomize/kyaml v0.1.11
|
||||
sigs.k8s.io/yaml v1.2.0
|
||||
)
|
||||
596
api/go.sum
596
api/go.sum
@@ -1,596 +0,0 @@
|
||||
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 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
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 h1:VlW4R6jmBIv3/u1JNlawEvJMM4J+dPORPaZasQee8Us=
|
||||
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 h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
|
||||
github.com/bombsimon/wsl v1.2.5 h1:9gTOkIwVtoDZywvX802SDHokeX4kW1cKnV8ZTVAPkRs=
|
||||
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 h1:H2pdYOb3KQ1/YsqVWoWNLQO+fusocsw354rqGTZtAgw=
|
||||
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 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/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-critic/go-critic v0.3.5-0.20190904082202-d79a9f0c64db h1:GYXWx7Vr3+zv833u+8IoXbNnQY0AdXsxAgI0kX7xcwA=
|
||||
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 h1:DI5mA3+eKdWeJ40nU4d6Wc26qmdG8RCi/btYq0TuRN0=
|
||||
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 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w=
|
||||
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 h1:JojxlmI6STnFVG9yOImLeGREv8W2ocNUM+iOhR6jE7g=
|
||||
github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4=
|
||||
github.com/go-toolsmith/astcopy v1.0.0 h1:OMgl1b1MEpjFQ1m5ztEO06rz5CUd3oBv9RF7+DyvdG8=
|
||||
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 h1:4zxD8j3JRFNyLN46lodQuqz3xdKSrur7U/sr0SDS/gQ=
|
||||
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 h1:A0vDDXt+vsvLEdbMFJAUBI/uTbRw1ffOPnxsILnFL6k=
|
||||
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 h1:alXE75TXgcmupDsMK1fRAy0YUzLzqPVvBKoyWV+KPXg=
|
||||
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 h1:4DFWWMXVfbcN5So1sBNW9+yeiMqLFGl1wFLTL5R0Tgg=
|
||||
github.com/go-toolsmith/pkgload v1.0.0/go.mod h1:5eFArkbO80v7Z0kdngIxsRXRMTaX4Ilcwuh3clNrQJc=
|
||||
github.com/go-toolsmith/strparse v1.0.0 h1:Vcw78DnpCAKlM20kSbAyO4mPfJn/lyYA4BJUDxe2Jb4=
|
||||
github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8=
|
||||
github.com/go-toolsmith/typep v1.0.0 h1:zKymWyA1TRYvqYrYDrfEMZULyrhcnGY3x7LDKU2XQaA=
|
||||
github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/gofrs/flock v0.0.0-20190320160742-5135e617513b h1:ekuhfTjngPhisSjOJ0QWKpPQE8/rbknHaes6WVJj5Hw=
|
||||
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 h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/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 h1:23T5iq8rbUYlhpt5DB4XJkc6BU31uODLD1o1gKvZmD0=
|
||||
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 h1:w8hkcTqaFpzKqonE9uMCefW1WDie15eSP/4MssdenaM=
|
||||
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 h1:YYWNAGTKWhKpcLLt7aSj/odlKrSrelQwlovBpDuf19w=
|
||||
github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6/go.mod h1:DbHgvLiFKX1Sh2T1w8Q/h4NAI8MHIpzCdnBUDTXU3I0=
|
||||
github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613 h1:9kfjN3AdxcbsZBf8NjltjWihK2QfBBBZuv91cMFfDHw=
|
||||
github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613/go.mod h1:SyvUF2NxV+sN8upjjeVYr5W7tyxaT1JVtvhKhOn2ii8=
|
||||
github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3 h1:pe9JHs3cHHDQgOFXJJdYkK6fLz2PWyYtP4hthoCMvs8=
|
||||
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 h1:J2XAy40+7yz70uaOiMbNnluTg7gyQhtGqLQncQh+4J8=
|
||||
github.com/golangci/gocyclo v0.0.0-20180528134321-2becd97e67ee/go.mod h1:ozx7R9SIwqmqf5pRP90DhR2Oay2UIjGuKheCBCNwAYU=
|
||||
github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a h1:iR3fYXUjHCR97qWS8ch1y9zPNsgXThGwjKPrYfqMPks=
|
||||
github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU=
|
||||
github.com/golangci/golangci-lint v1.21.0 h1:HxAxpR8Z0M8omihvQdsD3PF0qPjlqYqp2vMJzstoKeI=
|
||||
github.com/golangci/golangci-lint v1.21.0/go.mod h1:phxpHK52q7SE+5KpPnti4oZTdFCEsn/tKN+nFvCKXfk=
|
||||
github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc h1:gLLhTLMk2/SutryVJ6D4VZCU3CUqr8YloG7FPIBWFpI=
|
||||
github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc/go.mod h1:e5tpTHCfVze+7EpLEozzMB3eafxo2KT5veNg1k6byQU=
|
||||
github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 h1:MfyDlzVjl1hoaPzPD4Gpb/QgoRfSBR0jdhwGyAWwMSA=
|
||||
github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg=
|
||||
github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca h1:kNY3/svz5T29MYHubXix4aDDuE3RWHkPvopM/EDv/MA=
|
||||
github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o=
|
||||
github.com/golangci/misspell v0.0.0-20180809174111-950f5d19e770 h1:EL/O5HGrF7Jaq0yNhBLucz9hTuRzj2LdwGBOaENgxIk=
|
||||
github.com/golangci/misspell v0.0.0-20180809174111-950f5d19e770/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA=
|
||||
github.com/golangci/prealloc v0.0.0-20180630174525-215b22d4de21 h1:leSNB7iYzLYSSx3J/s5sVf4Drkc68W2wm4Ixh/mr0us=
|
||||
github.com/golangci/prealloc v0.0.0-20180630174525-215b22d4de21/go.mod h1:tf5+bzsHdTM0bsB7+8mt0GUMvjCgwLpTapNZHU8AajI=
|
||||
github.com/golangci/revgrep v0.0.0-20180526074752-d9c87f5ffaf0 h1:HVfrLniijszjS1aiNg8JbBMO2+E1WIQ+j/gL4SQqGPg=
|
||||
github.com/golangci/revgrep v0.0.0-20180526074752-d9c87f5ffaf0/go.mod h1:qOQCunEYvmd/TLamH+7LlVccLvUH5kZNhbCgTHoBbp4=
|
||||
github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 h1:zwtduBRr5SSWhqsYNgcuWO2kFlpdOZbP0+yRjmvPGys=
|
||||
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 h1:JVnpOZS+qxli+rgVl98ILOXVNbW+kb5wcxeGx8ShUIw=
|
||||
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/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo=
|
||||
github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I=
|
||||
github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0=
|
||||
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 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/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 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
|
||||
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 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||
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 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
|
||||
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 h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8=
|
||||
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/matoous/godox v0.0.0-20190911065817-5d6d842e92eb h1:RHba4YImhrUVQDHUCe2BNSOz4tVy2yGyXhvYDvxGgeE=
|
||||
github.com/matoous/godox v0.0.0-20190911065817-5d6d842e92eb/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s=
|
||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
|
||||
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 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||
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/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 h1:AREM5mwr4u1ORQBMvzfzBgpsctsbQikCVpvC+tX285E=
|
||||
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 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo=
|
||||
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 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
|
||||
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 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
||||
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/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/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 h1:BzRvVq1EHuIjxpijCEKpAxzKUUMurOQ4sknehIATRh8=
|
||||
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 h1:MZM7FHLqUHYI0Y/mQAt3d2aYa0SiNms/hFqC9qJYolM=
|
||||
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
|
||||
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041 h1:llrF3Fs4018ePo4+G/HV/uQUqEI1HMDjCeOf2V6puPc=
|
||||
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 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||
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 h1:gO6i5zugwzo1RVTvgvfwCOSVegNuvnNi6bAD1QCmkHs=
|
||||
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 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
|
||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
|
||||
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 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
||||
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 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=
|
||||
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/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e h1:RumXZ56IrCj4CL+g1b9OL/oH0QnsF976bC8xQFYUD5Q=
|
||||
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.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok=
|
||||
github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
||||
github.com/ultraware/funlen v0.0.2 h1:Av96YVBwwNSe4MLR7iI/BIa3VyI7/djnto/pK3Uxbdo=
|
||||
github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA=
|
||||
github.com/ultraware/whitespace v0.0.4 h1:If7Va4cM03mpgrNH9k49/VOicWpGoG70XPBFFODYDsg=
|
||||
github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA=
|
||||
github.com/uudashr/gocognit v0.0.0-20190926065955-1655d0de0517 h1:ChMKTho2hWKpks/nD/FL2KqM1wuVt62oJeiE8+eFpGs=
|
||||
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.4.1-lite h1:FhvNc94AXMZkfqUwfMKhnQEC9phkphSGdPTL7tIdhOM=
|
||||
github.com/yujunz/go-getter v1.4.1-lite/go.mod h1:sbmqxXjyLunH1PkF3n7zSlnVeMvmYUuIl9ZVs/7NyCc=
|
||||
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/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/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/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 h1:rOhMmluY6kLMhdnrivzec6lLgaVbMHMn2ISQXJeJ5EM=
|
||||
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c h1:Vco5b+cuG5NNfORVxZy6bYZQ7rsigisU1WQFkvQ0L5E=
|
||||
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 h1:XdBG6es/oFDr1HwaxkxgVve7NB281QhxgK/i4voubFs=
|
||||
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/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 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
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 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
|
||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2 h1:XZx7nhd5GMaZpmDaEHFVafUZC7ya0fuo7cSJ3UCKYmM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/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 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||
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 h1:WX1yoOaKQfddO/mLzdV4wptyWgoH/6hwLs7QHTixo0I=
|
||||
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc=
|
||||
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b h1:DxJ5nJdkhDlLok9K6qO+5290kphDJbHOQO1DFFFTeBo=
|
||||
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4=
|
||||
mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f h1:Cq7MalBHYACRd6EesksG1Q8EoIAKOsiZviGKbOLIej4=
|
||||
mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw=
|
||||
sigs.k8s.io/kustomize/kyaml v0.1.11 h1:/VvWxVIgH5gG1K4A7trgbyLgO3tRBiAWNhLFVU1HEmo=
|
||||
sigs.k8s.io/kustomize/kyaml v0.1.11/go.mod h1:72/rLkSi+L/pHM1oCjwrf3ClU+tH5kZQvvdLSqIHwWU=
|
||||
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
|
||||
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
|
||||
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 h1:JPJh2pk3+X4lXAkZIk2RuE/7/FoK9maXw+TNPJhVS/c=
|
||||
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
|
||||
@@ -1,50 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package image
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// IsImageMatched returns true if the value of t is identical to the
|
||||
// image name in the full image name and tag as given by s.
|
||||
func IsImageMatched(s, t string) bool {
|
||||
// Tag values are limited to [a-zA-Z0-9_.{}-].
|
||||
// Some tools like Bazel rules_k8s allow tag patterns with {} characters.
|
||||
// More info: https://github.com/bazelbuild/rules_k8s/pull/423
|
||||
pattern, _ := regexp.Compile("^" + t + "(@sha256)?(:[a-zA-Z0-9_.{}-]*)?$")
|
||||
return pattern.MatchString(s)
|
||||
}
|
||||
|
||||
// Split separates and returns the name and tag parts
|
||||
// from the image string using either colon `:` or at `@` separators.
|
||||
// Note that the returned tag keeps its separator.
|
||||
func Split(imageName string) (name string, tag string) {
|
||||
// check if image name contains a domain
|
||||
// if domain is present, ignore domain and check for `:`
|
||||
ic := -1
|
||||
if slashIndex := strings.Index(imageName, "/"); slashIndex < 0 {
|
||||
ic = strings.LastIndex(imageName, ":")
|
||||
} else {
|
||||
lastIc := strings.LastIndex(imageName[slashIndex:], ":")
|
||||
// set ic only if `:` is present
|
||||
if lastIc > 0 {
|
||||
ic = slashIndex + lastIc
|
||||
}
|
||||
}
|
||||
ia := strings.LastIndex(imageName, "@")
|
||||
if ic < 0 && ia < 0 {
|
||||
return imageName, ""
|
||||
}
|
||||
|
||||
i := ic
|
||||
if ia > 0 {
|
||||
i = ia
|
||||
}
|
||||
|
||||
name = imageName[:i]
|
||||
tag = imageName[i:]
|
||||
return
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package image
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestIsImageMatched(t *testing.T) {
|
||||
testCases := []struct {
|
||||
testName string
|
||||
value string
|
||||
name string
|
||||
isMatched bool
|
||||
}{
|
||||
{
|
||||
testName: "identical",
|
||||
value: "nginx",
|
||||
name: "nginx",
|
||||
isMatched: true,
|
||||
},
|
||||
{
|
||||
testName: "name is match",
|
||||
value: "nginx:12345",
|
||||
name: "nginx",
|
||||
isMatched: true,
|
||||
},
|
||||
{
|
||||
testName: "name is not a match",
|
||||
value: "apache:12345",
|
||||
name: "nginx",
|
||||
isMatched: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.testName, func(t *testing.T) {
|
||||
assert.Equal(t, tc.isMatched, IsImageMatched(tc.value, tc.name))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSplit(t *testing.T) {
|
||||
testCases := []struct {
|
||||
testName string
|
||||
value string
|
||||
name string
|
||||
tag string
|
||||
}{
|
||||
{
|
||||
testName: "no tag",
|
||||
value: "nginx",
|
||||
name: "nginx",
|
||||
tag: "",
|
||||
},
|
||||
{
|
||||
testName: "with tag",
|
||||
value: "nginx:1.2.3",
|
||||
name: "nginx",
|
||||
tag: ":1.2.3",
|
||||
},
|
||||
{
|
||||
testName: "with digest",
|
||||
value: "nginx@12345",
|
||||
name: "nginx",
|
||||
tag: "@12345",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.testName, func(t *testing.T) {
|
||||
name, tag := Split(tc.value)
|
||||
assert.Equal(t, tc.name, name)
|
||||
assert.Equal(t, tc.tag, tag)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,166 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package accumulator
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
resmaptest_test "sigs.k8s.io/kustomize/api/testutils/resmaptest"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
func TestRefVarTransformer(t *testing.T) {
|
||||
type given struct {
|
||||
varMap map[string]interface{}
|
||||
fs []types.FieldSpec
|
||||
res resmap.ResMap
|
||||
}
|
||||
type expected struct {
|
||||
res resmap.ResMap
|
||||
unused []string
|
||||
}
|
||||
testCases := []struct {
|
||||
description string
|
||||
given given
|
||||
expected expected
|
||||
errMessage string
|
||||
}{
|
||||
{
|
||||
description: "var replacement in map[string]",
|
||||
given: given{
|
||||
varMap: map[string]interface{}{
|
||||
"FOO": "replacementForFoo",
|
||||
"BAR": "replacementForBar",
|
||||
"BAZ": int64(5),
|
||||
"BOO": true,
|
||||
},
|
||||
fs: []types.FieldSpec{
|
||||
{Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/map"},
|
||||
{Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/slice"},
|
||||
{Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/interface"},
|
||||
{Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/nil"},
|
||||
{Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/num"},
|
||||
},
|
||||
res: resmaptest_test.NewRmBuilder(
|
||||
t, resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())).
|
||||
Add(map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm1",
|
||||
},
|
||||
"data": map[string]interface{}{
|
||||
"map": map[string]interface{}{
|
||||
"item1": "$(FOO)",
|
||||
"item2": "bla",
|
||||
"item3": "$(BAZ)",
|
||||
"item4": "$(BAZ)+$(BAZ)",
|
||||
"item5": "$(BOO)",
|
||||
"item6": "if $(BOO)",
|
||||
"item7": 2019,
|
||||
},
|
||||
"slice": []interface{}{
|
||||
"$(FOO)",
|
||||
"bla",
|
||||
"$(BAZ)",
|
||||
"$(BAZ)+$(BAZ)",
|
||||
"$(BOO)",
|
||||
"if $(BOO)",
|
||||
},
|
||||
"interface": "$(FOO)",
|
||||
"nil": nil,
|
||||
"num": 2019,
|
||||
}}).ResMap(),
|
||||
},
|
||||
expected: expected{
|
||||
res: resmaptest_test.NewRmBuilder(
|
||||
t, resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())).
|
||||
Add(map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm1",
|
||||
},
|
||||
"data": map[string]interface{}{
|
||||
"map": map[string]interface{}{
|
||||
"item1": "replacementForFoo",
|
||||
"item2": "bla",
|
||||
"item3": int64(5),
|
||||
"item4": "5+5",
|
||||
"item5": true,
|
||||
"item6": "if true",
|
||||
"item7": 2019,
|
||||
},
|
||||
"slice": []interface{}{
|
||||
"replacementForFoo",
|
||||
"bla",
|
||||
int64(5),
|
||||
"5+5",
|
||||
true,
|
||||
"if true",
|
||||
},
|
||||
"interface": "replacementForFoo",
|
||||
"nil": nil,
|
||||
"num": 2019,
|
||||
}}).ResMap(),
|
||||
unused: []string{"BAR"},
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "var replacement panic in map[string]",
|
||||
given: given{
|
||||
varMap: map[string]interface{}{},
|
||||
fs: []types.FieldSpec{
|
||||
{Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/slice"},
|
||||
},
|
||||
res: resmaptest_test.NewRmBuilder(
|
||||
t, resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())).
|
||||
Add(map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm1",
|
||||
},
|
||||
"data": map[string]interface{}{
|
||||
"slice": []interface{}{5}, // noticeably *not* a []string
|
||||
}}).ResMap(),
|
||||
},
|
||||
errMessage: "expected array of strings, found [5]",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.description, func(t *testing.T) {
|
||||
// arrange
|
||||
tr := newRefVarTransformer(tc.given.varMap, tc.given.fs)
|
||||
|
||||
// act
|
||||
err := tr.Transform(tc.given.res)
|
||||
|
||||
// assert
|
||||
if tc.errMessage != "" {
|
||||
if err == nil {
|
||||
t.Fatalf("missing expected error %v", tc.errMessage)
|
||||
} else if err.Error() != tc.errMessage {
|
||||
t.Fatalf("actual error doesn't match expected error: \nACTUAL: %v\nEXPECTED: %v", err.Error(), tc.errMessage)
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
a, e := tc.given.res, tc.expected.res
|
||||
if !reflect.DeepEqual(a, e) {
|
||||
err = e.ErrorIfNotEqualLists(a)
|
||||
t.Fatalf("actual doesn't match expected: \nACTUAL:\n%v\nEXPECTED:\n%v\nERR: %v", a, e, err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
FROM golang:1.11 AS build
|
||||
|
||||
ARG GO111MODULE=on
|
||||
|
||||
WORKDIR /go/src/sigs.k8s.io/kustomize/api/internal/crawl
|
||||
COPY . /go/src/sigs.k8s.io/kustomize//api/internal/crawl
|
||||
|
||||
RUN go mod download
|
||||
RUN CGO_ENABLED=0 go install -v ./cmd/crawler/crawler.go
|
||||
|
||||
FROM scratch
|
||||
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||
COPY --from=build /go/bin/crawler /
|
||||
ENTRYPOINT ["/crawler"]
|
||||
CMD []
|
||||
@@ -1,215 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/internal/crawl/utils"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/internal/crawl/crawler"
|
||||
"sigs.k8s.io/kustomize/api/internal/crawl/crawler/github"
|
||||
"sigs.k8s.io/kustomize/api/internal/crawl/doc"
|
||||
"sigs.k8s.io/kustomize/api/internal/crawl/httpclient"
|
||||
"sigs.k8s.io/kustomize/api/internal/crawl/index"
|
||||
|
||||
"github.com/gomodule/redigo/redis"
|
||||
)
|
||||
|
||||
const (
|
||||
githubAccessTokenVar = "GITHUB_ACCESS_TOKEN"
|
||||
redisCacheURL = "REDIS_CACHE_URL"
|
||||
redisKeyURL = "REDIS_KEY_URL"
|
||||
retryCount = 3
|
||||
)
|
||||
|
||||
type CrawlMode int
|
||||
|
||||
const (
|
||||
CrawlUnknown CrawlMode = iota
|
||||
// Crawl all the kustomization files in all the repositories of a Github user
|
||||
CrawlUser
|
||||
// Crawl all the kustomization files in a Github repo
|
||||
CrawlRepo
|
||||
// Crawl all the documents in the index
|
||||
CrawlIndex
|
||||
// Crawl all the kustomization files on Github
|
||||
CrawlGithub
|
||||
// Crawl all the documents in the index and crawling all the kustomization files on Github
|
||||
CrawlIndexAndGithub
|
||||
)
|
||||
|
||||
func NewCrawlMode(s string) CrawlMode {
|
||||
switch s {
|
||||
case "github-user":
|
||||
return CrawlUser
|
||||
case "github-repo":
|
||||
return CrawlRepo
|
||||
case "index+github":
|
||||
return CrawlIndexAndGithub
|
||||
case "index":
|
||||
return CrawlIndex
|
||||
case "github":
|
||||
return CrawlGithub
|
||||
default:
|
||||
return CrawlUnknown
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
indexNamePtr := flag.String(
|
||||
"index", "kustomize", "The name of the ElasticSearch index.")
|
||||
modePtr := flag.String("mode", "index+github",
|
||||
`The crawling mode, which can be one of [github-user, github-repo, index, github, index+github].
|
||||
* github-user: crawl all the kustomization files in all the repositories of a Github user (--github-user must be specified for this mode).
|
||||
* github-repo: crawl all the kustomization files in a Github repository (--github-repo must be specified for this mode).
|
||||
* index: crawl all the documents in the index.
|
||||
* gihub: crawl all the kustomization files on Github.
|
||||
* index+github: crawl all the documents in the index and crawling all the kustomization files on Github.`)
|
||||
githubUserPtr := flag.String("github-user", "",
|
||||
"A github user name (e.g., kubernetes-sigs). This flag is required for the `github-user` mode.")
|
||||
githubRepoPtr := flag.String("github-repo", "",
|
||||
"A github repository name (e.g., kubernetes-sigs/kustomize). This flag is required for the `github-repo` mode.")
|
||||
flag.Parse()
|
||||
|
||||
githubToken := os.Getenv(githubAccessTokenVar)
|
||||
if githubToken == "" {
|
||||
log.Printf("Must set the variable '%s' to make github requests.\n",
|
||||
githubAccessTokenVar)
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
idx, err := index.NewKustomizeIndex(ctx, *indexNamePtr)
|
||||
if err != nil {
|
||||
log.Printf("Could not create an index: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
cacheURL := os.Getenv(redisCacheURL)
|
||||
cache, err := redis.DialURL(cacheURL)
|
||||
clientCache := &http.Client{}
|
||||
if err != nil {
|
||||
log.Printf("Error: redis could not make a connection: %v\n", err)
|
||||
} else {
|
||||
clientCache = httpclient.NewClient(cache)
|
||||
}
|
||||
|
||||
// docConverter takes in a plain document and processes it for the index.
|
||||
docConverter := func(d *doc.Document) (crawler.CrawledDocument, error) {
|
||||
kdoc := doc.KustomizationDocument{
|
||||
Document: *d,
|
||||
}
|
||||
|
||||
err := kdoc.ParseYAML()
|
||||
return &kdoc, err
|
||||
}
|
||||
|
||||
// Index updates the value in the index.
|
||||
indexFunc := func(cdoc crawler.CrawledDocument, mode index.Mode) error {
|
||||
switch d := cdoc.(type) {
|
||||
case *doc.KustomizationDocument:
|
||||
switch mode {
|
||||
case index.Delete:
|
||||
log.Printf("Deleting: %v", d)
|
||||
return idx.Delete(d.ID())
|
||||
default:
|
||||
log.Printf("Inserting: %v", d)
|
||||
return idx.Put(d.ID(), d)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("type %T not supported", d)
|
||||
}
|
||||
}
|
||||
|
||||
// seen tracks the IDs of all the documents in the index and their corresponding file types.
|
||||
// This helps avoid indexing a given document multiple times.
|
||||
seen := utils.NewSeenMap()
|
||||
|
||||
mode := NewCrawlMode(*modePtr)
|
||||
|
||||
ghCrawlerConstructor := func(user, repo string) crawler.Crawler {
|
||||
if user != "" {
|
||||
return github.NewCrawler(githubToken, retryCount, clientCache,
|
||||
github.QueryWith(
|
||||
github.Filename("kustomization.yaml"),
|
||||
github.Filename("kustomization.yml"),
|
||||
github.Filename("kustomization"),
|
||||
github.User(user)),
|
||||
)
|
||||
} else if repo != "" {
|
||||
return github.NewCrawler(githubToken, retryCount, clientCache,
|
||||
github.QueryWith(
|
||||
github.Filename("kustomization.yaml"),
|
||||
github.Filename("kustomization.yml"),
|
||||
github.Filename("kustomization"),
|
||||
github.Repo(repo)),
|
||||
)
|
||||
} else {
|
||||
return github.NewCrawler(githubToken, retryCount, clientCache,
|
||||
github.QueryWith(
|
||||
github.Filename("kustomization.yaml"),
|
||||
github.Filename("kustomization.yml"),
|
||||
github.Filename("kustomization")),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
seedDocs := make(crawler.CrawlSeed, 0)
|
||||
|
||||
// get all the documents in the index
|
||||
getSeedDocsFunc := func() {
|
||||
query := []byte(`{ "query":{ "match_all":{} } }`)
|
||||
it := idx.IterateQuery(query, 10000, 60*time.Second)
|
||||
for it.Next() {
|
||||
for _, hit := range it.Value().Hits.Hits {
|
||||
seedDocs = append(seedDocs, hit.Document.Document.Copy())
|
||||
}
|
||||
}
|
||||
if err := it.Err(); err != nil {
|
||||
log.Fatalf("getSeedDocsFunc Error iterating: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
switch mode {
|
||||
case CrawlIndexAndGithub:
|
||||
getSeedDocsFunc()
|
||||
crawlers := []crawler.Crawler{ghCrawlerConstructor("", "")}
|
||||
crawler.CrawlFromSeed(ctx, seedDocs, crawlers, docConverter, indexFunc, seen)
|
||||
crawler.CrawlGithub(ctx, crawlers, docConverter, indexFunc, seen)
|
||||
case CrawlIndex:
|
||||
getSeedDocsFunc()
|
||||
crawlers := []crawler.Crawler{ghCrawlerConstructor("", "")}
|
||||
crawler.CrawlFromSeed(ctx, seedDocs, crawlers, docConverter, indexFunc, seen)
|
||||
case CrawlGithub:
|
||||
crawlers := []crawler.Crawler{ghCrawlerConstructor("", "")}
|
||||
// add all the documents in the index into seen.
|
||||
// this greatly reduces the time overhead of CrawlGithub.
|
||||
getSeedDocsFunc()
|
||||
for _, d := range seedDocs {
|
||||
seen[d.ID()] = d.FileType
|
||||
}
|
||||
crawler.CrawlGithub(ctx, crawlers, docConverter, indexFunc, seen)
|
||||
case CrawlUser:
|
||||
if *githubUserPtr == "" {
|
||||
flag.Usage()
|
||||
log.Fatalf("Please specify a github user with the github-user flag!")
|
||||
}
|
||||
crawlers := []crawler.Crawler{ghCrawlerConstructor(*githubUserPtr, "")}
|
||||
crawler.CrawlGithub(ctx, crawlers, docConverter, indexFunc, seen)
|
||||
case CrawlRepo:
|
||||
if *githubRepoPtr == "" {
|
||||
flag.Usage()
|
||||
log.Fatalf("Please specify a github repository with the github-repo flag!")
|
||||
}
|
||||
crawlers := []crawler.Crawler{ghCrawlerConstructor("", *githubRepoPtr)}
|
||||
crawler.CrawlGithub(ctx, crawlers, docConverter, indexFunc, seen)
|
||||
case CrawlUnknown:
|
||||
flag.Usage()
|
||||
log.Fatalf("The --mode flag must be one of [github-user, github-repo, index, github, index+github].")
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
FROM golang:1.11 AS build
|
||||
|
||||
ARG GO111MODULE=on
|
||||
|
||||
WORKDIR /go/src/sigs.k8s.io/kustomize/api/internal/crawl
|
||||
COPY . /go/src/sigs.k8s.io/kustomize/api/internal/crawl
|
||||
|
||||
RUN go mod download
|
||||
RUN CGO_ENABLED=0 go install ./cmd/kustomize_stats
|
||||
|
||||
FROM scratch
|
||||
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||
COPY --from=build /go/bin/kustomize_stats /
|
||||
ENTRYPOINT ["/kustomize_stats"]
|
||||
@@ -1,249 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/internal/crawl/doc"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/internal/crawl/index"
|
||||
)
|
||||
|
||||
// iterateArr adds each item in arr into countMap.
|
||||
func iterateArr(arr []string, countMap map[string]int) {
|
||||
for _, item := range arr {
|
||||
if _, ok := countMap[item]; !ok {
|
||||
countMap[item] = 1
|
||||
} else {
|
||||
countMap[item]++
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// SortMapKeyByValueInt takes a map as its input, sorts its keys according to their values
|
||||
// in the map, and outputs the sorted keys as a slice.
|
||||
func SortMapKeyByValueInt(m map[string]int) []string {
|
||||
keys := make([]string, 0, len(m))
|
||||
for key := range m {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
// sort keys according to their values in the map m
|
||||
sort.Slice(keys, func(i, j int) bool { return m[keys[i]] > m[keys[j]] })
|
||||
return keys
|
||||
}
|
||||
|
||||
// SortMapKeyByValue takes a map as its input, sorts its keys according to their values
|
||||
// in the map, and outputs the sorted keys as a slice.
|
||||
func SortMapKeyByValueLen(m map[string][]string) []string {
|
||||
keys := make([]string, 0, len(m))
|
||||
for key := range m {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
// sort keys according to their values in the map m
|
||||
sort.Slice(keys, func(i, j int) bool { return len(m[keys[i]]) > len(m[keys[j]]) })
|
||||
return keys
|
||||
}
|
||||
|
||||
func GeneratorOrTransformerStats(docs []*doc.KustomizationDocument) {
|
||||
n := len(docs)
|
||||
if n == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
fileType := docs[0].FileType
|
||||
fmt.Printf("There are totally %d %s files.\n", n, fileType)
|
||||
|
||||
GitRepositorySummary(docs, fileType)
|
||||
|
||||
// key of kindToUrls: a string in the KustomizationDocument.Kinds field
|
||||
// value of kindToUrls: a slice of string urls defining a given kind.
|
||||
kindToUrls := make(map[string][]string)
|
||||
|
||||
for _, d := range docs {
|
||||
url := fmt.Sprintf("%s/blob/%s/%s", d.RepositoryURL, d.DefaultBranch, d.FilePath)
|
||||
for _, kind := range d.Kinds {
|
||||
if _, ok := kindToUrls[kind]; !ok {
|
||||
kindToUrls[kind] = []string{url}
|
||||
} else {
|
||||
kindToUrls[kind] = append(kindToUrls[kind], url)
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Printf("There are totally %d kinds of %s\n", len(kindToUrls), fileType)
|
||||
sortedKeys := SortMapKeyByValueLen(kindToUrls)
|
||||
for _, k := range sortedKeys {
|
||||
sort.Strings(kindToUrls[k])
|
||||
fmt.Printf("%s kind %s appears %d times\n", fileType, k, len(kindToUrls[k]))
|
||||
for _, url := range kindToUrls[k] {
|
||||
fmt.Printf("%s\n", url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GitRepositorySummary counts the distribution of docs:
|
||||
// 1) how many git repositories are these docs from?
|
||||
// 2) how many docs are from each git repository?
|
||||
func GitRepositorySummary(docs []*doc.KustomizationDocument, fileType string) {
|
||||
m := make(map[string]int)
|
||||
for _, d := range docs {
|
||||
if _, ok := m[d.RepositoryURL]; ok {
|
||||
m[d.RepositoryURL]++
|
||||
} else {
|
||||
m[d.RepositoryURL] = 1
|
||||
}
|
||||
}
|
||||
sortedKeys := SortMapKeyByValueInt(m)
|
||||
topN := 10
|
||||
i := 0
|
||||
for _, k := range sortedKeys {
|
||||
if i >= topN {
|
||||
break
|
||||
}
|
||||
fmt.Printf("%d %s are from %s\n", m[k], fileType, k)
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
topKindsPtr := flag.Int(
|
||||
"kinds", -1,
|
||||
`the number of kubernetes object kinds to be listed according to their popularities.
|
||||
By default, all the kinds will be listed.
|
||||
If you only want to list the 10 most popular kinds, set the flag to 10.`)
|
||||
topIdentifiersPtr := flag.Int(
|
||||
"identifiers", -1,
|
||||
`the number of identifiers to be listed according to their popularities.
|
||||
By default, all the identifiers will be listed.
|
||||
If you only want to list the 10 most popular identifiers, set the flag to 10.`)
|
||||
topKustomizeFeaturesPtr := flag.Int(
|
||||
"kustomize-features", -1,
|
||||
`the number of kustomize features to be listed according to their popularities.
|
||||
By default, all the features will be listed.
|
||||
If you only want to list the 10 most popular features, set the flag to 10.`)
|
||||
indexNamePtr := flag.String(
|
||||
"index", "kustomize", "The name of the ElasticSearch index.")
|
||||
flag.Parse()
|
||||
|
||||
ctx := context.Background()
|
||||
idx, err := index.NewKustomizeIndex(ctx, *indexNamePtr)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not create an index: %v\n", err)
|
||||
}
|
||||
|
||||
// count tracks the number of documents in the index
|
||||
count := 0
|
||||
|
||||
// kustomizationFilecount tracks the number of kustomization files in the index
|
||||
kustomizationFilecount := 0
|
||||
|
||||
kindsMap := make(map[string]int)
|
||||
identifiersMap := make(map[string]int)
|
||||
kustomizeIdentifiersMap := make(map[string]int)
|
||||
|
||||
// ids tracks the unique IDs of the documents in the index
|
||||
ids := make(map[string]struct{})
|
||||
|
||||
// generatorFiles include all the non-kustomization files whose FileType is generator
|
||||
generatorFiles := make([]*doc.KustomizationDocument, 0)
|
||||
|
||||
// transformersFiles include all the non-kustomization files whose FileType is transformer
|
||||
transformersFiles := make([]*doc.KustomizationDocument, 0)
|
||||
|
||||
checksums := make(map[string]int)
|
||||
|
||||
// get all the documents in the index
|
||||
query := []byte(`{ "query":{ "match_all":{} } }`)
|
||||
it := idx.IterateQuery(query, 10000, 60*time.Second)
|
||||
for it.Next() {
|
||||
for _, hit := range it.Value().Hits.Hits {
|
||||
sum := fmt.Sprintf("%x", sha256.Sum256([]byte(hit.Document.DocumentData)))
|
||||
if _, ok := checksums[sum]; ok {
|
||||
checksums[sum]++
|
||||
} else {
|
||||
checksums[sum] = 1
|
||||
}
|
||||
|
||||
// check whether there is any duplicate IDs in the index
|
||||
if _, ok := ids[hit.ID]; !ok {
|
||||
ids[hit.ID] = struct{}{}
|
||||
} else {
|
||||
log.Printf("Found duplicate ID (%s)\n", hit.ID)
|
||||
}
|
||||
|
||||
count++
|
||||
iterateArr(hit.Document.Kinds, kindsMap)
|
||||
iterateArr(hit.Document.Identifiers, identifiersMap)
|
||||
|
||||
if doc.IsKustomizationFile(hit.Document.FilePath) {
|
||||
kustomizationFilecount++
|
||||
iterateArr(hit.Document.Identifiers, kustomizeIdentifiersMap)
|
||||
|
||||
} else {
|
||||
switch hit.Document.FileType {
|
||||
case "generator":
|
||||
generatorFiles = append(generatorFiles, hit.Document.Copy())
|
||||
case "transformer":
|
||||
transformersFiles = append(transformersFiles, hit.Document.Copy())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := it.Err(); err != nil {
|
||||
log.Fatalf("Error iterating: %v\n", err)
|
||||
}
|
||||
|
||||
sortedKindsMapKeys := SortMapKeyByValueInt(kindsMap)
|
||||
sortedIdentifiersMapKeys := SortMapKeyByValueInt(identifiersMap)
|
||||
sortedKustomizeIdentifiersMapKeys := SortMapKeyByValueInt(kustomizeIdentifiersMap)
|
||||
|
||||
fmt.Printf(`The count of unique document IDs in the kustomize index: %d
|
||||
There are %d documents in the kustomize index.
|
||||
%d kinds of kubernetes objects are customized:`, len(ids), count, len(kindsMap))
|
||||
fmt.Printf("\n")
|
||||
|
||||
kindCount := 0
|
||||
for _, key := range sortedKindsMapKeys {
|
||||
if *topKindsPtr < 0 || (*topKindsPtr >= 0 && kindCount < *topKindsPtr) {
|
||||
fmt.Printf("\tkind `%s` is customimzed in %d documents\n", key, kindsMap[key])
|
||||
kindCount++
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("%d kinds of identifiers are found:\n", len(identifiersMap))
|
||||
identifierCount := 0
|
||||
for _, key := range sortedIdentifiersMapKeys {
|
||||
if *topIdentifiersPtr < 0 || (*topIdentifiersPtr >= 0 && identifierCount < *topIdentifiersPtr) {
|
||||
fmt.Printf("\tidentifier `%s` appears in %d documents\n", key, identifiersMap[key])
|
||||
identifierCount++
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf(`There are %d kustomization files in the kustomize index.
|
||||
%d kinds of kustomize features are found:`, kustomizationFilecount, len(kustomizeIdentifiersMap))
|
||||
fmt.Printf("\n")
|
||||
kustomizeFeatureCount := 0
|
||||
for _, key := range sortedKustomizeIdentifiersMapKeys {
|
||||
if *topKustomizeFeaturesPtr < 0 || (*topKustomizeFeaturesPtr >= 0 && kustomizeFeatureCount < *topKustomizeFeaturesPtr) {
|
||||
fmt.Printf("\tfeature `%s` is used in %d documents\n", key, kustomizeIdentifiersMap[key])
|
||||
kustomizeFeatureCount++
|
||||
}
|
||||
}
|
||||
|
||||
GeneratorOrTransformerStats(generatorFiles)
|
||||
GeneratorOrTransformerStats(transformersFiles)
|
||||
|
||||
fmt.Printf("There are total %d checksums of document contents\n", len(checksums))
|
||||
sortedChecksums := SortMapKeyByValueInt(checksums)
|
||||
sortedChecksums = sortedChecksums[:20]
|
||||
fmt.Printf("The top 20 checksums are:\n")
|
||||
for _, key := range sortedChecksums {
|
||||
fmt.Printf("checksum %s apprears %d\n", key, checksums[key])
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
This binary takes as its input a json file including GKE logs (which can be
|
||||
[exported](https://cloud.google.com/logging/docs/export/configure_export_v2) into
|
||||
[Cloud Storage](https://cloud.google.com/storage/docs/)),
|
||||
and extracts the `textPayload` field of each log entry.
|
||||
|
||||
Here is an log entry example:
|
||||
|
||||
{"insertId":"1sxuh4jg5lw6w10","labels":{"compute.googleapis.com/resource_name":"gke-crawler2-default-pool-5e55ea05-gzgv","container.googleapis.com/namespace_name":"default","container.googleapis.com/pod_name":"kustomize-stats-5bczg","container.googleapis.com/stream":"stdout"},"logName":"projects/haiyanmeng-gke-dev/logs/kustomize-stats","receiveTimestamp":"2020-01-06T23:33:07.012831742Z","resource":{"labels":{"cluster_name":"crawler2","container_name":"kustomize-stats","instance_id":"8183086081854184383","namespace_id":"default","pod_id":"kustomize-stats-5bczg","project_id":"haiyanmeng-gke-dev","zone":"us-central1-a"},"type":"container"},"severity":"INFO","textPayload":"The kustomize index already exists\n","timestamp":"2020-01-06T23:32:46.628930547Z"}
|
||||
@@ -1,7 +0,0 @@
|
||||
wget <log-file-url> -O log
|
||||
go build .
|
||||
./log-parser log >out
|
||||
cat out | grep "kind \`" | cut -d\` -f2 | tail -n 50
|
||||
cat out | grep "kind \`" | awk '{print $6}' | tail -n 50
|
||||
cat out | grep "feature \`" | grep -v "\`resources\`" | grep -v -e "\`apiVersion\`" | grep -v -e "\`apiversion\`" | cut -d\` -f2
|
||||
cat out | grep "feature \`" | grep -v "\`resources\`" | grep -v -e "\`apiVersion\`" | grep -v -e "\`apiversion\`" | awk '{print $6}'
|
||||
@@ -1,49 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) != 2 {
|
||||
log.Fatalf("The usage of the command is: \n\t%s <log-file.json>", os.Args[0])
|
||||
}
|
||||
|
||||
file, err := os.Open(os.Args[1])
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
closeFile := func(file *os.File) {
|
||||
if err := file.Close(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
defer closeFile(file)
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
|
||||
var entry interface{}
|
||||
if err := json.Unmarshal([]byte(line), &entry); err != nil {
|
||||
log.Printf("failed to unmarshal a log entry: %s\n", line)
|
||||
}
|
||||
|
||||
m := entry.(map[string]interface{})
|
||||
if payload, ok := m["textPayload"]; ok {
|
||||
// use fmt.Printf here instead of log.Printf to avoid the time and code location info the log package provides
|
||||
fmt.Printf("%s", payload)
|
||||
} else {
|
||||
log.Printf("the log entry does not have the `textPayload` field: %s\n", line)
|
||||
}
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
github_api_secret.txt
|
||||
@@ -1,2 +0,0 @@
|
||||
<ADD YOUR GITHUB PERSONAL ACCESS TOKEN HERE WITHOUT A TRAILING NEWLINE>
|
||||
Run: printf "<your-token>" > github_api_secret.txt
|
||||
@@ -1,53 +0,0 @@
|
||||
The crawler job can run in one of the following mode:
|
||||
|
||||
# Crawling all the documents in the index and crawling all the kustomization files on Github
|
||||
|
||||
This is the default setting of the crawler job. The `command` and `args` field
|
||||
of the container should be:
|
||||
|
||||
```
|
||||
command: ["/crawler"]
|
||||
```
|
||||
|
||||
Or
|
||||
|
||||
```
|
||||
command: ["/crawler"]
|
||||
args: ["--mode=index+github"]
|
||||
```
|
||||
|
||||
# Crawling all the documents in the index
|
||||
|
||||
The `command` and `args` field of the container should be:
|
||||
|
||||
```
|
||||
command: ["/crawler"]
|
||||
args: ["--mode=index"]
|
||||
```
|
||||
|
||||
# Crawling all the kustomization files on Github
|
||||
|
||||
The `command` and `args` field of the container should be:
|
||||
|
||||
```
|
||||
command: ["/crawler"]
|
||||
args: ["--mode=github"]
|
||||
```
|
||||
|
||||
# Crawling all the kustomization files in a Github repo
|
||||
|
||||
The `command` and `args` field of the container should be like:
|
||||
|
||||
```
|
||||
command: ["/crawler"]
|
||||
args: ["--mode=github-repo", "--github-repo=kubernetes-sigs/kustomize"]
|
||||
```
|
||||
|
||||
# Crawling all the kustomization files in all the repositories of a Github user
|
||||
|
||||
The `command` and `args` field of the container should be like:
|
||||
|
||||
```
|
||||
command: ["/crawler"]
|
||||
args: ["--github-user", "--github-user=kubernetes-sigs"]
|
||||
```
|
||||
@@ -1,20 +0,0 @@
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: kustomize-stats
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
restartPolicy: OnFailure
|
||||
containers:
|
||||
- name: kustomize-stats
|
||||
image: gcr.io/haiyanmeng-gke-dev/kustomize_stats:v1
|
||||
imagePullPolicy: Always
|
||||
command: ["/kustomize_stats"]
|
||||
args: ["--index=kustomize", "--kinds=51", "--identifiers=50", "--kustomize-features=50"]
|
||||
env:
|
||||
- name: ELASTICSEARCH_URL
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: elasticsearch-config
|
||||
key: es-url
|
||||
@@ -1,3 +0,0 @@
|
||||
resources:
|
||||
- ../base
|
||||
- job.yaml
|
||||
@@ -1,23 +0,0 @@
|
||||
# ESBackup depends on ESCluster, and is depended by ESSnapshot.
|
||||
# Creating `esbackup/kustomize-backbup` will create the `kustomize-backup` snapshot repository.
|
||||
# Deleting `esbackup/kustomize-backbup` will delete the `kustomize-backup` snapshot repository.
|
||||
# Deleting `esbackup/kustomize-backbup` will NOT delete the snapshots in the `kustomize-backup` snapshot repository, instead makes all the snapshots in the repository inaccessible.
|
||||
# Deleting `esbackup/kustomize-backbup` will NOT delete the essnapshot objects depending on it, but will cause those essnapshot objects to be reconciled, which update the status of the essnapshot objects to reflect the fact that the esbackup object is missing.
|
||||
# If you delete the `kustomize-backup` snapshot repository directly without deleting `esbackup/kustomize-backbup`, the ESBackup object will not recreate the snapshot repository.
|
||||
apiVersion: elasticsearch.cloud.google.com/v1alpha1
|
||||
kind: ESBackup
|
||||
metadata:
|
||||
name: kustomize-backup
|
||||
spec:
|
||||
storage:
|
||||
gcs:
|
||||
# the bucket must exist for the snapshot repository to be created successfully.
|
||||
bucket: kustomize-backup
|
||||
# the path does not need to exist.
|
||||
# If the path does not exist, the controller will create the folder in the GCS bucket.
|
||||
# If the path already exists and includes snapshots, these snapshots can be used.
|
||||
path: kustomize
|
||||
secret:
|
||||
name: kustomizesa
|
||||
escluster:
|
||||
name: esbasic
|
||||
@@ -1,51 +0,0 @@
|
||||
# ESCluster is depended by ESBackup and ESRestore.
|
||||
apiVersion: elasticsearch.cloud.google.com/v1alpha1
|
||||
kind: ESCluster
|
||||
metadata:
|
||||
name: esbasic
|
||||
spec:
|
||||
plugin:
|
||||
pluginList:
|
||||
- repository-gcs
|
||||
- ingest-user-agent
|
||||
- ingest-geoip
|
||||
# To set `gcpserviceaccount`,
|
||||
# First, create and download a GCP service account into a json file, named `sakey.json` following the instruction:
|
||||
# https://www.elastic.co/guide/en/elasticsearch/plugins/6.5/repository-gcs-usage.html#repository-gcs-using-service-account
|
||||
# Second, create a secret for the service account using the following command:
|
||||
# $ kubectl create secret generic kustomizesa --from-file=./sakey.json
|
||||
gcpserviceaccount:
|
||||
name: kustomizesa
|
||||
config:
|
||||
env:
|
||||
example: test
|
||||
nodegroups:
|
||||
- name: di
|
||||
replicas: 2
|
||||
data: true
|
||||
ingest: true
|
||||
config:
|
||||
jvm:
|
||||
- Djava.net.preferIPv4Stack=true
|
||||
- Xms2g
|
||||
- Xmx2g
|
||||
es:
|
||||
path.repo: '["/tmp/es_backup_basic"]'
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
- topologyKey: kubernetes.io/hostname
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
es/nodegroup: di
|
||||
resources:
|
||||
requests:
|
||||
memory: 3Gi
|
||||
limits:
|
||||
memory: 3Gi
|
||||
- name: m
|
||||
replicas: 2
|
||||
master: true
|
||||
config:
|
||||
es:
|
||||
path.repo: '["/tmp/es_backup_basic"]'
|
||||
@@ -1,19 +0,0 @@
|
||||
# ESRestore depends on both ESCluster and ESSnapshot.
|
||||
# Creating `esrestore/kustomize-restore` will restore the `kuostmize` index in the `kustomize-snapshot` snapshot to a new index named `kusotmize-restore`.
|
||||
# Deleting `esrestore/kustomize-restore` will not delete the restored index.
|
||||
# Deleting `esrestore/kustomize-restore` should happen before deleting `essnapshot/kustomize-snapshot`.
|
||||
# After the restore is complete, if the `kusotmize-restore` index is deleted manually, the ESRestore object will NOT restore the `kustomize` index to it again.
|
||||
# The correct way of using ESRestore is: create a ESRestore object to restore the index; delete the ESRestore object after the restore is complete.
|
||||
apiVersion: elasticsearch.cloud.google.com/v1alpha1
|
||||
kind: ESRestore
|
||||
metadata:
|
||||
name: kustomize-restore
|
||||
spec:
|
||||
include_global_state: true
|
||||
ignore_unavailable: true
|
||||
rename_pattern: kustomize
|
||||
rename_replacement: kustomize-restore
|
||||
essnapshot:
|
||||
name: kustomize-snapshot
|
||||
escluster:
|
||||
name: esbasic
|
||||
@@ -1,23 +0,0 @@
|
||||
# ESSnapshot depends on ESBackup, and is depended by ESRestore.
|
||||
# Creating `essnapshot/kustomize-snapshot` will create a snapshot named `kustomize-snapshot` in the `kustomize-backup` snapshot repository.
|
||||
# After being created, the `kustomize-snapshot` snapshot will not be automatically updated when the `kuostomize` index is updated.
|
||||
# If you delete `essnapshot/kustomize-snapshot` and recreate it, the new snapshot will capture the current status of the `kustomize` index.
|
||||
# Deleting `essnapshot/kustomize-snapshot` will delete the snapshot.
|
||||
# Deleting `essnapshot/kustomize-snapshot` should happen before deleting `esbackup/kustomize-backup`.
|
||||
# If the `kustomize-snapshot` snapshot is deleted directly without deleting `essnapshot/kustomize-snapshot`, the ESSnapshot object will recreate the snapshot.
|
||||
# The correct way of using ESSnapshot is: create an ESSnapshot object to create a snapshot, keep the ESSnapshot object until the snapshot is no longer needed.
|
||||
# To update the snapshot to capture the latest version of the index, you can either:
|
||||
# 1) delete the snapshot, and wait for the ESSnapshot object to recreate the snapshot;
|
||||
# 2) delete the ESSnapshot object, and recreate the ESSnapshot object.
|
||||
apiVersion: elasticsearch.cloud.google.com/v1alpha1
|
||||
kind: ESSnapshot
|
||||
metadata:
|
||||
name: kustomize-snapshot
|
||||
spec:
|
||||
# indices are optional. If not specified all indices are selected.
|
||||
indices:
|
||||
- kustomize
|
||||
include_global_state: true
|
||||
ignore_unavailable: true
|
||||
esbackup:
|
||||
name: kustomize-backup
|
||||
@@ -1,16 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: elasticsearch
|
||||
spec:
|
||||
selector:
|
||||
custom-resource: v1alpha1.ESCluster
|
||||
custom-resource-name: esbasic
|
||||
custom-resource-namespace: default
|
||||
es/data: "true"
|
||||
using: escluster.Cluster
|
||||
ports:
|
||||
- protocol: "TCP"
|
||||
port: 9200
|
||||
type: LoadBalancer
|
||||
loadBalancerIP: ""
|
||||
@@ -1,344 +0,0 @@
|
||||
// Package crawler provides helper methods and defines an interface for lauching
|
||||
// source repository crawlers that retrieve files from a source and forwards
|
||||
// to a channel for indexing and retrieval.
|
||||
package crawler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/internal/crawl/utils"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/internal/crawl/index"
|
||||
|
||||
_ "github.com/gomodule/redigo/redis"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/internal/crawl/doc"
|
||||
)
|
||||
|
||||
var (
|
||||
logger = log.New(os.Stdout, "Crawler: ", log.LstdFlags|log.LUTC|log.Llongfile)
|
||||
)
|
||||
|
||||
// Crawler forwards documents from source repositories to index and store them
|
||||
// for searching. Each crawler is responsible for querying it's source of
|
||||
// information, and forwarding files that have not been seen before or that need
|
||||
// updating.
|
||||
type Crawler interface {
|
||||
// Crawl returns when it is done processing. This method does not take
|
||||
// ownership of the channel. The channel is write only, and it
|
||||
// designates where the crawler should forward the documents.
|
||||
Crawl(ctx context.Context, output chan<- CrawledDocument, seen utils.SeenMap) error
|
||||
|
||||
// Get the document data given the FilePath, Repo, and Ref/Tag/Branch.
|
||||
FetchDocument(context.Context, *doc.Document) error
|
||||
// Write to the document what the created time is.
|
||||
SetCreated(context.Context, *doc.Document) error
|
||||
|
||||
SetDefaultBranch(*doc.Document)
|
||||
|
||||
Match(*doc.Document) bool
|
||||
}
|
||||
|
||||
type CrawledDocument interface {
|
||||
ID() string
|
||||
GetDocument() *doc.Document
|
||||
// Get all the Documents directly referred in a Document.
|
||||
// For a Document representing a non-kustomization file, an empty slice will be returned.
|
||||
// For a Document representing a kustomization file:
|
||||
// the `includeResources` parameter determines whether the documents referred in the `resources` field are returned or not;
|
||||
// the `includeTransformers` parameter determines whether the documents referred in the `transformers` field are returned or not;
|
||||
// the `includeGenerators` parameter determines whether the documents referred in the `generators` field are returned or not.
|
||||
GetResources(includeResources, includeTransformers, includeGenerators bool) ([]*doc.Document, error)
|
||||
WasCached() bool
|
||||
}
|
||||
|
||||
type CrawlSeed []*doc.Document
|
||||
|
||||
type IndexFunc func(CrawledDocument, index.Mode) error
|
||||
type Converter func(*doc.Document) (CrawledDocument, error)
|
||||
|
||||
func logIfErr(err error) {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
logger.Println("error: ", err)
|
||||
}
|
||||
|
||||
func findMatch(d *doc.Document, crawlers []Crawler) Crawler {
|
||||
for _, crawl := range crawlers {
|
||||
if crawl.Match(d) {
|
||||
return crawl
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func addBranches(cdoc CrawledDocument, match Crawler, indx IndexFunc,
|
||||
seen utils.SeenMap, stack *CrawlSeed) {
|
||||
|
||||
seen.Set(cdoc.ID(), cdoc.GetDocument().FileType)
|
||||
|
||||
match.SetDefaultBranch(cdoc.GetDocument())
|
||||
|
||||
// Insert into index
|
||||
if err := indx(cdoc, index.InsertOrUpdate); err != nil {
|
||||
logger.Printf("Failed to insert or update doc(%s): %v",
|
||||
cdoc.GetDocument().Path(), err)
|
||||
return
|
||||
}
|
||||
|
||||
deps, err := cdoc.GetResources(true, true, true)
|
||||
if err != nil {
|
||||
logger.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, dep := range deps {
|
||||
if seen.Seen(dep.ID()) && seen.Value(dep.ID()) == dep.FileType {
|
||||
continue
|
||||
}
|
||||
*stack = append(*stack, dep)
|
||||
}
|
||||
}
|
||||
|
||||
func doCrawl(ctx context.Context, docsPtr *CrawlSeed, crawlers []Crawler, conv Converter, indx IndexFunc,
|
||||
seen utils.SeenMap, stack *CrawlSeed, refreshDoc bool, updateFileType bool) {
|
||||
|
||||
UpdatedDocCount := 0
|
||||
seenDocCount := 0
|
||||
cachedDocCount := 0
|
||||
findMatchErrCount := 0
|
||||
FetchDocumentErrCount := 0
|
||||
SetCreatedErrCount := 0
|
||||
convErrCount := 0
|
||||
deleteDocCount := 0
|
||||
crawledDocCount := 0
|
||||
|
||||
// During the execution of the for loop, more Documents may be added into (*docsPtr).
|
||||
for len(*docsPtr) > 0 {
|
||||
// get the last Document in (*docPtr), which will be crawled in this iteration.
|
||||
tail := (*docsPtr)[len(*docsPtr)-1]
|
||||
|
||||
// remove the last Document in (*docPtr)
|
||||
*docsPtr = (*docsPtr)[:(len(*docsPtr) - 1)]
|
||||
|
||||
crawledDocCount++
|
||||
logger.Printf("Crawling doc %d: %s", crawledDocCount, tail.Path())
|
||||
|
||||
if seen.Seen(tail.ID()) {
|
||||
if !updateFileType || seen.Value(tail.ID()) == tail.FileType {
|
||||
logger.Printf("this doc has been seen before")
|
||||
seenDocCount++
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if tail.WasCached() {
|
||||
logger.Printf("doc(%s) is cached already", tail.Path())
|
||||
cachedDocCount++
|
||||
continue
|
||||
}
|
||||
|
||||
match := findMatch(tail, crawlers)
|
||||
if match == nil {
|
||||
logIfErr(fmt.Errorf("%v could not match any crawler", tail))
|
||||
findMatchErrCount++
|
||||
continue
|
||||
}
|
||||
|
||||
if tail.User == "" {
|
||||
tail.User = doc.UserName(tail.RepositoryURL)
|
||||
}
|
||||
|
||||
// If the Document represents a kustomization root, FetchDcoument will change
|
||||
// the `filePath` field of the Document by adding `kustomization.yaml` or
|
||||
// `kustomization.yml` or `kustomization` into the the field.
|
||||
// Therefore, it is necessary to add the ID of the Document into seen before
|
||||
// calling FetchDocument. Otherwise, the binary may enter into an infinite loop
|
||||
// if a kustomization file points to its kustmozation root in its `resources` or
|
||||
// `bases` field.
|
||||
seen.Set(tail.ID(), tail.FileType)
|
||||
|
||||
if refreshDoc || tail.DefaultBranch == "" {
|
||||
match.SetDefaultBranch(tail)
|
||||
}
|
||||
|
||||
if refreshDoc || tail.DocumentData == "" {
|
||||
if err := match.FetchDocument(ctx, tail); err != nil {
|
||||
logger.Printf("FetchDocument failed on doc(%s): %v", tail.Path(), err)
|
||||
FetchDocumentErrCount++
|
||||
// delete the document from the index
|
||||
cdoc := &doc.KustomizationDocument{
|
||||
Document: *tail,
|
||||
}
|
||||
seen.Set(cdoc.ID(), tail.FileType)
|
||||
if err := indx(cdoc, index.Delete); err != nil {
|
||||
logger.Printf("Failed to delete doc(%s): %v", cdoc.Path(), err)
|
||||
}
|
||||
deleteDocCount++
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if refreshDoc || tail.CreationTime == nil {
|
||||
if err := match.SetCreated(ctx, tail); err != nil {
|
||||
logger.Printf("SetCreated failed on doc(%s): %v", tail.Path(), err)
|
||||
SetCreatedErrCount++
|
||||
}
|
||||
}
|
||||
|
||||
cdoc, err := conv(tail)
|
||||
// If conv returns an error, cdoc can still be added into the index so that
|
||||
// cdoc.Document can be searched.
|
||||
if err != nil {
|
||||
logger.Printf("conv failed on doc(%s): %v", tail.Path(), err)
|
||||
convErrCount++
|
||||
}
|
||||
|
||||
UpdatedDocCount++
|
||||
addBranches(cdoc, match, indx, seen, stack)
|
||||
}
|
||||
logger.Printf("Summary of doCrawl:\n")
|
||||
logger.Printf("\t%d documents were updated\n", UpdatedDocCount)
|
||||
logger.Printf("\t%d documents were seen by the crawler already and skipped\n", seenDocCount)
|
||||
logger.Printf("\t%d documents were cached already and skipped\n", cachedDocCount)
|
||||
logger.Printf("\t%d documents didn't have a matching crawler and skipped\n", findMatchErrCount)
|
||||
logger.Printf("\t%d documents cannot be fetched, %d out of them are deleted\n",
|
||||
FetchDocumentErrCount, deleteDocCount)
|
||||
logger.Printf("\t%d documents cannot update its creation time but still were inserted or updated in the index\n", SetCreatedErrCount)
|
||||
logger.Printf("\t%d documents cannot be converted but still were inserted or updated in the index\n", convErrCount)
|
||||
}
|
||||
|
||||
// CrawlFromSeed updates all the documents in seed, and crawls all the new
|
||||
// documents referred in the seed.
|
||||
func CrawlFromSeed(ctx context.Context, seed CrawlSeed, crawlers []Crawler,
|
||||
conv Converter, indx IndexFunc, seen utils.SeenMap) {
|
||||
|
||||
// stack tracks the documents directly referred in other documents.
|
||||
stack := make(CrawlSeed, 0)
|
||||
|
||||
// Exploit seed to update bulk of corpus.
|
||||
logger.Printf("updating %d documents from seed\n", len(seed))
|
||||
// each unique document in seed will be crawled once.
|
||||
doCrawl(ctx, &seed, crawlers, conv, indx, seen, &stack, true, false)
|
||||
|
||||
// Traverse any new documents added while updating corpus.
|
||||
logger.Printf("crawling %d new documents found in the seed\n", len(stack))
|
||||
// While crawling each document in stack, the documents directly referred in the document
|
||||
// will be added into stack.
|
||||
// After this statement is done, stack will become empty.
|
||||
doCrawl(ctx, &stack, crawlers, conv, indx, seen, &stack, false, true)
|
||||
}
|
||||
|
||||
// CrawlGithubRunner is a blocking function and only returns once all of the
|
||||
// crawlers are finished with execution.
|
||||
//
|
||||
// This function uses the output channel to forward kustomization documents
|
||||
// from a list of crawlers. The output is to be consumed by a database/search
|
||||
// indexer for later retrieval.
|
||||
//
|
||||
// The return value is an array of errors in which each index represents the
|
||||
// index of the crawler that emitted the error. Although the errors themselves
|
||||
// can be nil, the array will always be exactly the size of the crawlers array.
|
||||
//
|
||||
// CrawlGithubRunner takes in a seed, which represents the documents stored in an
|
||||
// index somewhere. The document data is not required to be populated. If there
|
||||
// are many documents, this is preferable. The order of iteration over the seed
|
||||
// is not guaranteed, but the CrawlGithub does guarantee that every element
|
||||
// from the seed will be processed before any other documents from the
|
||||
// crawlers.
|
||||
func CrawlGithubRunner(ctx context.Context, output chan<- CrawledDocument,
|
||||
crawlers []Crawler, seen utils.SeenMap) []error {
|
||||
|
||||
errs := make([]error, len(crawlers))
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
for i, crawler := range crawlers {
|
||||
// Crawler implementations get their own channels to prevent a
|
||||
// crawler from closing the main output channel.
|
||||
docs := make(chan CrawledDocument)
|
||||
wg.Add(2)
|
||||
|
||||
// Forward all of the documents from this crawler's channel to
|
||||
// the main output channel.
|
||||
go func(docs <-chan CrawledDocument) {
|
||||
defer wg.Done()
|
||||
for d := range docs {
|
||||
output <- d
|
||||
}
|
||||
}(docs)
|
||||
|
||||
// Run this crawler and capture its returned error.
|
||||
go func(idx int, crawler Crawler,
|
||||
docs chan<- CrawledDocument) {
|
||||
|
||||
defer func() {
|
||||
wg.Done()
|
||||
if r := recover(); r != nil {
|
||||
errs[idx] = fmt.Errorf(
|
||||
"%+v panicked: %v, additional error %v",
|
||||
crawler, r, errs[idx],
|
||||
)
|
||||
}
|
||||
}()
|
||||
defer close(docs)
|
||||
errs[idx] = crawler.Crawl(ctx, docs, seen)
|
||||
}(i, crawler, docs) // Copies the index and the crawler
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
return errs
|
||||
}
|
||||
|
||||
// CrawlGithub crawls all the kustomization files on Github.
|
||||
func CrawlGithub(ctx context.Context, crawlers []Crawler, conv Converter,
|
||||
indx IndexFunc, seen utils.SeenMap) {
|
||||
// stack tracks the documents directly referred in other documents.
|
||||
stack := make(CrawlSeed, 0)
|
||||
|
||||
// ch is channel where all the crawlers sends the crawled documents to.
|
||||
ch := make(chan CrawledDocument, 1<<10)
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
docCount := 0
|
||||
for cdoc := range ch {
|
||||
docCount++
|
||||
logger.Printf("Processing doc %d found on Github", docCount)
|
||||
// all the docs here are kustomization files found by querying Github, and
|
||||
// their `FileType` fields all should be empty.
|
||||
if seen.Seen(cdoc.ID()) {
|
||||
logger.Printf("the doc has been seen before")
|
||||
continue
|
||||
}
|
||||
match := findMatch(cdoc.GetDocument(), crawlers)
|
||||
if match == nil {
|
||||
logIfErr(fmt.Errorf(
|
||||
"%v could not match any crawler", cdoc))
|
||||
continue
|
||||
}
|
||||
addBranches(cdoc, match, indx, seen, &stack)
|
||||
}
|
||||
}()
|
||||
|
||||
logger.Println("processing the documents found from crawling github")
|
||||
if errs := CrawlGithubRunner(ctx, ch, crawlers, seen); errs != nil {
|
||||
for _, err := range errs {
|
||||
logIfErr(err)
|
||||
}
|
||||
}
|
||||
close(ch)
|
||||
wg.Wait()
|
||||
|
||||
// Handle deps of newly discovered documents.
|
||||
logger.Printf("crawling the %d new documents referred by other documents",
|
||||
len(stack))
|
||||
doCrawl(ctx, &stack, crawlers, conv, indx, seen, &stack, false, true)
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
package doc
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/internal/git"
|
||||
)
|
||||
|
||||
type Document struct {
|
||||
RepositoryURL string `json:"repositoryUrl,omitempty"`
|
||||
// User makes it easy to aggregate data in the user level instead
|
||||
// of the repository level
|
||||
User string `json:"user,omitempty"`
|
||||
FilePath string `json:"filePath,omitempty"`
|
||||
DefaultBranch string `json:"defaultBranch,omitempty"`
|
||||
DocumentData string `json:"document,omitempty"`
|
||||
CreationTime *time.Time `json:"creationTime,omitempty"`
|
||||
IsSame bool `json:"-"`
|
||||
// FileType can be one of the following:
|
||||
// "generator", "transformer", "resource", "".
|
||||
FileType string `json:"fileType,omitempty"`
|
||||
}
|
||||
|
||||
// Implements the CrawlerDocument interface.
|
||||
func (doc *Document) GetDocument() *Document {
|
||||
return doc
|
||||
}
|
||||
|
||||
func (doc *Document) Copy() *Document {
|
||||
return &Document{
|
||||
RepositoryURL: doc.RepositoryURL,
|
||||
User: doc.User,
|
||||
FilePath: doc.FilePath,
|
||||
DefaultBranch: doc.DefaultBranch,
|
||||
DocumentData: doc.DocumentData,
|
||||
CreationTime: doc.CreationTime,
|
||||
IsSame: doc.IsSame,
|
||||
FileType: doc.FileType,
|
||||
}
|
||||
}
|
||||
|
||||
func (doc *Document) Path() string {
|
||||
return fmt.Sprintf("repoURL: %s filePath: %s branch: %s",
|
||||
doc.RepositoryURL, doc.FilePath, doc.DefaultBranch)
|
||||
}
|
||||
|
||||
// Implements the CrawlerDocument interface.
|
||||
func (doc *Document) WasCached() bool {
|
||||
return doc.IsSame
|
||||
}
|
||||
|
||||
func (doc *Document) FromRelativePath(newFile string) (Document, error) {
|
||||
repoSpec, err := git.NewRepoSpecFromUrl(newFile)
|
||||
if err == nil {
|
||||
return Document{
|
||||
RepositoryURL: repoSpec.Host + path.Clean(repoSpec.OrgRepo),
|
||||
FilePath: path.Clean(repoSpec.Path),
|
||||
DefaultBranch: repoSpec.Ref,
|
||||
User: UserName(repoSpec.Host + path.Clean(repoSpec.OrgRepo)),
|
||||
}, nil
|
||||
}
|
||||
// else document is probably relative path.
|
||||
|
||||
ret := Document{
|
||||
RepositoryURL: doc.RepositoryURL,
|
||||
DefaultBranch: doc.DefaultBranch,
|
||||
User: UserName(doc.RepositoryURL),
|
||||
}
|
||||
ogDir, _ := path.Split(doc.FilePath)
|
||||
|
||||
cleaned := path.Clean(newFile)
|
||||
if !path.IsAbs(cleaned) {
|
||||
cleaned = path.Clean(ogDir + "/" + cleaned)
|
||||
}
|
||||
|
||||
ret.FilePath = cleaned
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (doc *Document) ID() string {
|
||||
sum := sha256.Sum256([]byte(strings.Join(
|
||||
[]string{
|
||||
doc.RepositoryURL,
|
||||
doc.DefaultBranch,
|
||||
doc.FilePath,
|
||||
},
|
||||
"---|---")))
|
||||
return fmt.Sprintf("%x", sum)
|
||||
}
|
||||
|
||||
func (doc *Document) RepositoryFullName() string {
|
||||
url := TrimUrl(doc.RepositoryURL)
|
||||
sections := strings.Split(url, "/")
|
||||
l := len(sections)
|
||||
if l < 2 {
|
||||
return url
|
||||
}
|
||||
return path.Join(sections[l-2], sections[l-1])
|
||||
}
|
||||
|
||||
// TrimUrl removes all the trailing slashes and the "git@github.com:" prefix (if exists).
|
||||
func TrimUrl(s string) string {
|
||||
url := strings.TrimRight(s, "/")
|
||||
|
||||
gitPrefix := "git@github.com:"
|
||||
if strings.HasPrefix(url, gitPrefix) {
|
||||
url = url[len(gitPrefix):]
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
func UserName(repositoryURL string) string {
|
||||
url := TrimUrl(repositoryURL)
|
||||
sections := strings.Split(url, "/")
|
||||
l := len(sections)
|
||||
if l < 2 {
|
||||
return url
|
||||
}
|
||||
return sections[l-2]
|
||||
}
|
||||
@@ -1,150 +0,0 @@
|
||||
package doc
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFromRelativePath(t *testing.T) {
|
||||
type Case struct {
|
||||
RelativePath string
|
||||
Expected Document
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
BaseDoc Document
|
||||
Cases []Case
|
||||
}{
|
||||
{
|
||||
BaseDoc: Document{
|
||||
RepositoryURL: "example.com/repo",
|
||||
FilePath: "path/to/file/kustomization.yaml",
|
||||
DefaultBranch: "master",
|
||||
},
|
||||
Cases: []Case{
|
||||
{
|
||||
RelativePath: "../other/file/resource.yaml",
|
||||
Expected: Document{
|
||||
RepositoryURL: "example.com/repo",
|
||||
FilePath: "path/to/other/file/resource.yaml",
|
||||
DefaultBranch: "master",
|
||||
User: "example.com",
|
||||
},
|
||||
},
|
||||
{
|
||||
RelativePath: "../file/../../something/../to/other/file/patch.yaml",
|
||||
Expected: Document{
|
||||
RepositoryURL: "example.com/repo",
|
||||
FilePath: "path/to/other/file/patch.yaml",
|
||||
DefaultBranch: "master",
|
||||
User: "example.com",
|
||||
},
|
||||
},
|
||||
{
|
||||
RelativePath: "service.yaml",
|
||||
Expected: Document{
|
||||
RepositoryURL: "example.com/repo",
|
||||
FilePath: "path/to/file/service.yaml",
|
||||
DefaultBranch: "master",
|
||||
User: "example.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
for _, c := range tc.Cases {
|
||||
rd, err := tc.BaseDoc.FromRelativePath(c.RelativePath)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(rd, c.Expected) {
|
||||
t.Errorf("document mismatch expected %v, got %v", c.Expected, rd)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDocument_RepositoryFullName(t *testing.T) {
|
||||
testCases := []struct {
|
||||
doc Document
|
||||
expectedRepositoryFullName string
|
||||
}{
|
||||
{
|
||||
doc: Document{
|
||||
RepositoryURL: "https://github.com/user/repo",
|
||||
},
|
||||
expectedRepositoryFullName: "user/repo",
|
||||
},
|
||||
{
|
||||
doc: Document{
|
||||
RepositoryURL: "https://github.com//user/repo////",
|
||||
},
|
||||
expectedRepositoryFullName: "user/repo",
|
||||
},
|
||||
{
|
||||
doc: Document{
|
||||
RepositoryURL: "repo/",
|
||||
},
|
||||
expectedRepositoryFullName: "repo",
|
||||
},
|
||||
{
|
||||
doc: Document{
|
||||
RepositoryURL: "",
|
||||
},
|
||||
expectedRepositoryFullName: "",
|
||||
},
|
||||
{
|
||||
doc: Document{
|
||||
RepositoryURL: "git@github.com:user/repo",
|
||||
},
|
||||
expectedRepositoryFullName: "user/repo",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
returnedRepositoryFullName := tc.doc.RepositoryFullName()
|
||||
if returnedRepositoryFullName != tc.expectedRepositoryFullName {
|
||||
t.Errorf("RepositoryFullName expected %s, got %s",
|
||||
tc.expectedRepositoryFullName,
|
||||
returnedRepositoryFullName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDocument_UserName(t *testing.T) {
|
||||
testCases := []struct {
|
||||
repositoryURL string
|
||||
expectedUserName string
|
||||
}{
|
||||
{
|
||||
repositoryURL: "https://github.com/user/repo",
|
||||
expectedUserName: "user",
|
||||
},
|
||||
{
|
||||
repositoryURL: "https://github.com//user/repo////",
|
||||
expectedUserName: "user",
|
||||
},
|
||||
{
|
||||
repositoryURL: "repo/",
|
||||
expectedUserName: "repo",
|
||||
},
|
||||
{
|
||||
repositoryURL: "",
|
||||
expectedUserName: "",
|
||||
},
|
||||
{
|
||||
repositoryURL: "git@github.com:user/repo",
|
||||
expectedUserName: "user",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
returnedUserName := UserName(tc.repositoryURL)
|
||||
if returnedUserName != tc.expectedUserName {
|
||||
t.Errorf("UserName expected %s, got %s",
|
||||
tc.expectedUserName, returnedUserName)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package doc
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/internal/crawl/utils"
|
||||
)
|
||||
|
||||
// UniqueDocuments make sure a Document with a given ID appears only once
|
||||
type UniqueDocuments struct {
|
||||
docs []*Document
|
||||
docIDs utils.SeenMap
|
||||
}
|
||||
|
||||
func NewUniqueDocuments() UniqueDocuments {
|
||||
return UniqueDocuments{
|
||||
docs: []*Document{},
|
||||
docIDs: utils.NewSeenMap(),
|
||||
}
|
||||
}
|
||||
|
||||
func (uds *UniqueDocuments) Add(d *Document) {
|
||||
if uds.docIDs.Seen(d.ID()) {
|
||||
return
|
||||
}
|
||||
uds.docs = append(uds.docs, d)
|
||||
uds.docIDs.Set(d.ID(), "")
|
||||
}
|
||||
|
||||
func (uds *UniqueDocuments) AddDocuments(docs []*Document) {
|
||||
for _, d := range docs {
|
||||
uds.Add(d)
|
||||
}
|
||||
}
|
||||
|
||||
func (uds *UniqueDocuments) Documents() []*Document {
|
||||
return uds.docs
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
module sigs.k8s.io/kustomize/api/internal/crawl
|
||||
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/elastic/go-elasticsearch/v6 v6.8.5
|
||||
github.com/gomodule/redigo v2.0.0+incompatible
|
||||
github.com/gorilla/mux v1.7.3
|
||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79
|
||||
github.com/rs/cors v1.7.0
|
||||
sigs.k8s.io/kustomize/api v0.0.0
|
||||
sigs.k8s.io/yaml v1.2.0
|
||||
)
|
||||
|
||||
replace sigs.k8s.io/kustomize/api v0.0.0 => ../../../api
|
||||
@@ -1,523 +0,0 @@
|
||||
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/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/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 h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=
|
||||
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/elastic/go-elasticsearch/v6 v6.8.5 h1:U2HtkBseC1FNBmDr0TR2tKltL6FxoY+niDAlj5M8TK8=
|
||||
github.com/elastic/go-elasticsearch/v6 v6.8.5/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox93HoX8utj1kxD9aFUcI=
|
||||
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 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
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/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/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/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/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/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/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/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/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0=
|
||||
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
|
||||
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/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/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
|
||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
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/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
|
||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/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/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo=
|
||||
github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I=
|
||||
github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0=
|
||||
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 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
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/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
|
||||
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 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0=
|
||||
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/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 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo=
|
||||
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 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
|
||||
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/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/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/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
|
||||
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
||||
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/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/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/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/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.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok=
|
||||
github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
||||
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/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.4.1-lite h1:FhvNc94AXMZkfqUwfMKhnQEC9phkphSGdPTL7tIdhOM=
|
||||
github.com/yujunz/go-getter v1.4.1-lite/go.mod h1:sbmqxXjyLunH1PkF3n7zSlnVeMvmYUuIl9ZVs/7NyCc=
|
||||
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/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/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/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 h1:rOhMmluY6kLMhdnrivzec6lLgaVbMHMn2ISQXJeJ5EM=
|
||||
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c h1:Vco5b+cuG5NNfORVxZy6bYZQ7rsigisU1WQFkvQ0L5E=
|
||||
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/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 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
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 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||
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 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/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/kyaml v0.1.11/go.mod h1:72/rLkSi+L/pHM1oCjwrf3ClU+tH5kZQvvdLSqIHwWU=
|
||||
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
|
||||
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
|
||||
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=
|
||||
@@ -1,411 +0,0 @@
|
||||
Find out the largest value of the `creationTime` field:
|
||||
```
|
||||
curl -s -X POST "${ElasticSearchURL}:9200/${INDEXNAME}/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"aggs" : {
|
||||
"max_creationTime" : { "max" : { "field" : "creationTime" } }
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Find out the smallest value of the `creationTime` field:
|
||||
```
|
||||
curl -s -X POST "${ElasticSearchURL}:9200/${INDEXNAME}/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"aggs" : {
|
||||
"min_creationTime" : { "min" : { "field" : "creationTime" } }
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Find out the smallest value of the `creationTime` field of all the kustomization files:
|
||||
```
|
||||
curl -s -X POST "${ElasticSearchURL}:9200/${INDEXNAME}/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"filter": [
|
||||
{ "regexp": { "filePath": "(.*/)?kustomization((.yaml)?|(.yml)?)(/)*" }}
|
||||
]
|
||||
}
|
||||
},
|
||||
"aggs" : {
|
||||
"min_creationTime" : { "min" : { "field" : "creationTime" } }
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Find out the smallest value of the `creationTime` field of all kustomize resource files:
|
||||
```
|
||||
curl -s -X POST "${ElasticSearchURL}:9200/${INDEXNAME}/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"must_not": {
|
||||
"regexp": { "filePath": "(.*/)?kustomization((.yaml)?|(.yml)?)(/)*" }
|
||||
},
|
||||
"filter": [
|
||||
{ "regexp": { "fileType": "resource" }}
|
||||
]
|
||||
}
|
||||
},
|
||||
"aggs" : {
|
||||
"min_creationTime" : { "min" : { "field" : "creationTime" } }
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Find out the smallest value of the `creationTime` field of all kustomize generator files:
|
||||
```
|
||||
curl -s -X POST "${ElasticSearchURL}:9200/${INDEXNAME}/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"must_not": {
|
||||
"regexp": { "filePath": "(.*/)?kustomization((.yaml)?|(.yml)?)(/)*" }
|
||||
},
|
||||
"filter": [
|
||||
{ "regexp": { "fileType": "generator" }}
|
||||
]
|
||||
}
|
||||
},
|
||||
"aggs" : {
|
||||
"min_creationTime" : { "min" : { "field" : "creationTime" } }
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Find out the smallest value of the `creationTime` field of all kustomize transformer files:
|
||||
```
|
||||
curl -s -X POST "${ElasticSearchURL}:9200/${INDEXNAME}/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"must_not": {
|
||||
"regexp": { "filePath": "(.*/)?kustomization((.yaml)?|(.yml)?)(/)*" }
|
||||
},
|
||||
"filter": [
|
||||
{ "regexp": { "fileType": "transformer" }}
|
||||
]
|
||||
}
|
||||
},
|
||||
"aggs" : {
|
||||
"min_creationTime" : { "min" : { "field" : "creationTime" } }
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Query all the documents whose `creationTime` <= `2016-07-29T17:38:26.000Z`:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"range": {
|
||||
"creationTime": {
|
||||
"lte": "2016-07-29T17:38:26.000Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Query all the documents whose `creationTime` falls within the specific range:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"range": {
|
||||
"creationTime": {
|
||||
"gte": "2016-07-29T17:38:26.000Z",
|
||||
"lte": "2016-08-29T17:38:26.000Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Query all the kustomization files whose `creationTime` falls within the specific range:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"size": 20,
|
||||
"query": {
|
||||
"bool": {
|
||||
"filter": {
|
||||
"regexp": { "filePath": "(.*/)?kustomization((.yaml)?|(.yml)?)(/)*" }
|
||||
},
|
||||
"must": {
|
||||
"range": {
|
||||
"creationTime": {
|
||||
"gte": "2017-09-24T15:49:57.000Z",
|
||||
"lte": "2017-09-24T15:49:57.000Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Aggregate how many new kustomization files were added into Github each month:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"filter": [
|
||||
{ "regexp": { "filePath": "(.*/)?kustomization((.yaml)?|(.yml)?)(/)*" }}
|
||||
]
|
||||
}
|
||||
},
|
||||
"aggs" : {
|
||||
"newFiles_over_time" : {
|
||||
"date_histogram" : {
|
||||
"field" : "creationTime",
|
||||
"interval" : "month"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Aggregate how many new kustomize resource files were added into Github each month:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"must_not": [
|
||||
{ "regexp": { "filePath": "(.*/)?kustomization((.yaml)?|(.yml)?)(/)*" }}
|
||||
],
|
||||
"filter": [
|
||||
{ "regexp": { "fileType": "resource" }}
|
||||
]
|
||||
}
|
||||
},
|
||||
"aggs" : {
|
||||
"newFiles_over_time" : {
|
||||
"date_histogram" : {
|
||||
"field" : "creationTime",
|
||||
"interval" : "month"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Aggregate how many new kustomize generator files were added into Github each month:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"must_not": [
|
||||
{ "regexp": { "filePath": "(.*/)?kustomization((.yaml)?|(.yml)?)(/)*" }}
|
||||
],
|
||||
"filter": [
|
||||
{ "regexp": { "fileType": "generator" }}
|
||||
]
|
||||
}
|
||||
},
|
||||
"aggs" : {
|
||||
"newFiles_over_time" : {
|
||||
"date_histogram" : {
|
||||
"field" : "creationTime",
|
||||
"interval" : "month"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Aggregate how many new kustomize transformer files were added into Github each month:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"must_not": [
|
||||
{ "regexp": { "filePath": "(.*/)?kustomization((.yaml)?|(.yml)?)(/)*" }}
|
||||
],
|
||||
"filter": [
|
||||
{ "regexp": { "fileType": "transformer" }}
|
||||
]
|
||||
}
|
||||
},
|
||||
"aggs" : {
|
||||
"newFiles_over_time" : {
|
||||
"date_histogram" : {
|
||||
"field" : "creationTime",
|
||||
"interval" : "month"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Aggregate how many new kustomization files were added into Github each year:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"filter": [
|
||||
{ "regexp": { "filePath": "(.*/)?kustomization((.yaml)?|(.yml)?)(/)*" }}
|
||||
]
|
||||
}
|
||||
},
|
||||
"aggs" : {
|
||||
"newFiles_over_time" : {
|
||||
"date_histogram" : {
|
||||
"field" : "creationTime",
|
||||
"interval" : "year"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Aggregate how many new kustomize resource files were added into Github each year:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"must_not": [
|
||||
{ "regexp": { "filePath": "(.*/)?kustomization((.yaml)?|(.yml)?)(/)*" }}
|
||||
],
|
||||
"filter": [
|
||||
{ "regexp": { "fileType": "resource" }}
|
||||
]
|
||||
}
|
||||
},
|
||||
"aggs" : {
|
||||
"newFiles_over_time" : {
|
||||
"date_histogram" : {
|
||||
"field" : "creationTime",
|
||||
"interval" : "year"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Aggregate how many new kustomize generator files were added into Github each year:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"must_not": [
|
||||
{ "regexp": { "filePath": "(.*/)?kustomization((.yaml)?|(.yml)?)(/)*" }}
|
||||
],
|
||||
"filter": [
|
||||
{ "regexp": { "fileType": "generator" }}
|
||||
]
|
||||
}
|
||||
},
|
||||
"aggs" : {
|
||||
"newFiles_over_time" : {
|
||||
"date_histogram" : {
|
||||
"field" : "creationTime",
|
||||
"interval" : "year"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Aggregate how many new kustomize transformer files were added into Github each year:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"must_not": [
|
||||
{ "regexp": { "filePath": "(.*/)?kustomization((.yaml)?|(.yml)?)(/)*" }}
|
||||
],
|
||||
"filter": [
|
||||
{ "regexp": { "fileType": "transformer" }}
|
||||
]
|
||||
}
|
||||
},
|
||||
"aggs" : {
|
||||
"newFiles_over_time" : {
|
||||
"date_histogram" : {
|
||||
"field" : "creationTime",
|
||||
"interval" : "year"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Find the generator files created within the given time range:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"filter": [
|
||||
{ "regexp": { "fileType": "generator" }}
|
||||
],
|
||||
"must_not": {
|
||||
"regexp": { "filePath": "(.*/)?kustomization((.yaml)?|(.yml)?)(/)*" }
|
||||
},
|
||||
"must": {
|
||||
"range": {
|
||||
"creationTime": {
|
||||
"gte": "2019-04-26T16:40:02.000Z",
|
||||
"lte": "2019-04-26T16:40:02.000Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Find the transformer files created within the given time range:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"filter": [
|
||||
{ "regexp": { "fileType": "transformer" }}
|
||||
],
|
||||
"must_not": {
|
||||
"regexp": { "filePath": "(.*/)?kustomization((.yaml)?|(.yml)?)(/)*" }
|
||||
},
|
||||
"must": {
|
||||
"range": {
|
||||
"creationTime": {
|
||||
"gte": "2019-04-26T16:40:02.000Z",
|
||||
"lte": "2019-04-26T16:40:02.000Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
@@ -1,32 +0,0 @@
|
||||
Count distinct values of the `defaultBranch` field:
|
||||
```
|
||||
curl -s -X POST "${ElasticSearchURL}:9200/${INDEXNAME}/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"aggs" : {
|
||||
"defaultBranch_count" : {
|
||||
"cardinality" : {
|
||||
"field" : "defaultBranch",
|
||||
"precision_threshold": 40000
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
List all the github branches where kustomization files and kustomize resource files live,
|
||||
and how many kustomization files and kustomize resource files live in each branch:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"aggs" : {
|
||||
"defaultBranch" : {
|
||||
"terms" : {
|
||||
"field" : "defaultBranch",
|
||||
"size": 41
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
@@ -1,55 +0,0 @@
|
||||
Count the documents whose `document` field is empty (The reason why the `document` field
|
||||
of a document is empty is because of empty documents):
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"size": 10000,
|
||||
"query": {
|
||||
"bool": {
|
||||
"must_not": {
|
||||
"exists": {
|
||||
"field": "document"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Find all the documents having the `creationTime` field set:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"exists": {
|
||||
"field": "creationTime"
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Find all the documents whose `creationTime` field is not set:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"size": 10000,
|
||||
"query": {
|
||||
"bool": {
|
||||
"must_not": {
|
||||
"exists": {
|
||||
"field": "creationTime"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
The following fields of a document in the kustomize index are always non-empty:
|
||||
`repositoryUrl`, `filePath`, `defaultBranch`.
|
||||
|
||||
The following fields of a document in the kustomize index may be empty:
|
||||
`kinds`, `identifiers`, `values`.
|
||||
@@ -1,301 +0,0 @@
|
||||
Find all the documents having the `fileType` field set:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"exists": {
|
||||
"field": "fileType"
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Find all the documents whose `fileType` field is not set:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"size": 10000,
|
||||
"query": {
|
||||
"bool": {
|
||||
"must_not": {
|
||||
"exists": {
|
||||
"field": "fileType"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Search for all the documents whose `fileType` field is `resource`:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"filter": [
|
||||
{ "regexp": { "fileType": "resource" }}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Search for all the kustomization files whose `fileType` field is `resource`:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"filter": [
|
||||
{ "regexp": { "filePath": "(.*/)?kustomization((.yaml)?|(.yml)?)(/)*" }},
|
||||
{ "regexp": { "fileType": "resource" }}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Search for all the kustomize resource files:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"filter": [
|
||||
{ "regexp": { "fileType": "resource" }}
|
||||
],
|
||||
"must_not": {
|
||||
"regexp": { "filePath": "(.*/)?kustomization((.yaml)?|(.yml)?)(/)*" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Search all the kustomization files including a `generators` field:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"size": 10000,
|
||||
"query": {
|
||||
"bool": {
|
||||
"must": {
|
||||
"match" : {
|
||||
"identifiers" : {
|
||||
"query" : "generators"
|
||||
}
|
||||
}
|
||||
},
|
||||
"filter": {
|
||||
"regexp": { "filePath": "(.*/)?kustomization((.yaml)?|(.yml)?)(/)*" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Search for all the documents whose `fileType` field is `generator`:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"filter": [
|
||||
{ "regexp": { "fileType": "generator" }}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Search for all the kustomization files whose `fileType` field is `generator`:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"filter": [
|
||||
{ "regexp": { "filePath": "(.*/)?kustomization((.yaml)?|(.yml)?)(/)*" }},
|
||||
{ "regexp": { "fileType": "generator" }}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Search for all the kustomize generator files:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"filter": [
|
||||
{ "regexp": { "fileType": "generator" }}
|
||||
],
|
||||
"must_not": {
|
||||
"regexp": { "filePath": "(.*/)?kustomization((.yaml)?|(.yml)?)(/)*" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Search all the kustomization files including a `transformers` field:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"size": 10000,
|
||||
"query": {
|
||||
"bool": {
|
||||
"must": {
|
||||
"match" : {
|
||||
"identifiers" : {
|
||||
"query" : "transformers"
|
||||
}
|
||||
}
|
||||
},
|
||||
"filter": {
|
||||
"regexp": { "filePath": "(.*/)?kustomization((.yaml)?|(.yml)?)(/)*" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Search for all the documents whose `fileType` field is `transformer`:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"filter": [
|
||||
{ "regexp": { "fileType": "transformer" }}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Search for all the kustomization files whose `fileType` field is `transformer`:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"filter": [
|
||||
{ "regexp": { "filePath": "(.*/)?kustomization((.yaml)?|(.yml)?)(/)*" }},
|
||||
{ "regexp": { "fileType": "transformer" }}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Search for all the kustomize transformer files:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"filter": [
|
||||
{ "regexp": { "fileType": "transformer" }}
|
||||
],
|
||||
"must_not": {
|
||||
"regexp": { "filePath": "(.*/)?kustomization((.yaml)?|(.yml)?)(/)*" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Count distinct values of the `fileType` field:
|
||||
```
|
||||
curl -s -X POST "${ElasticSearchURL}:9200/${INDEXNAME}/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"aggs" : {
|
||||
"fileType_count" : {
|
||||
"cardinality" : {
|
||||
"field" : "fileType",
|
||||
"precision_threshold": 40000
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
List all the values of the `fileType` field and the frequency of each value:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"aggs" : {
|
||||
"fileType" : {
|
||||
"terms" : {
|
||||
"field" : "fileType"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
|
||||
For all the kustomization files in the index, list all the values of the
|
||||
`fileType` field and the frequency of each value:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"filter": [
|
||||
{ "regexp": { "filePath": "(.*/)?kustomization((.yaml)?|(.yml)?)(/)*" }}
|
||||
]
|
||||
}
|
||||
},
|
||||
"aggs" : {
|
||||
"fileType" : {
|
||||
"terms" : {
|
||||
"field" : "fileType"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
For all the non-kustomization files in the index, list all the values of the
|
||||
`fileType` field and the frequency of each value:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"must_not": {
|
||||
"regexp": { "filePath": "(.*/)?kustomization((.yaml)?|(.yml)?)(/)*" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"aggs" : {
|
||||
"fileType" : {
|
||||
"terms" : {
|
||||
"field" : "fileType"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
@@ -1,29 +0,0 @@
|
||||
Find all the generator files whose `kinds` field includes `ChartRenderer`, and
|
||||
only output certain fields of each document:
|
||||
```
|
||||
curl -s -X GET "${ElasticSearchURL}:9200/${INDEXNAME}/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"size": 200,
|
||||
"_source": {
|
||||
"includes": ["kinds", "repositoryUrl", "defaultBranch", "filePath"]
|
||||
},
|
||||
"query": {
|
||||
"bool": {
|
||||
"filter": [
|
||||
{ "regexp": { "fileType": "generator" }}
|
||||
],
|
||||
"must_not": {
|
||||
"regexp": { "filePath": "(.*/)?kustomization((.yaml)?|(.yml)?)(/)*" }
|
||||
},
|
||||
"must": {
|
||||
"match" : {
|
||||
"kinds" : {
|
||||
"query" : "ChartRenderer"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user