mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-16 11:28:16 +00:00
Compare commits
1 Commits
api/v0.3.2
...
release-pl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
18bd5d9dea |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -5,9 +5,6 @@
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
.idea
|
||||
*.iml
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
|
||||
@@ -4,38 +4,25 @@ run:
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
- bodyclose
|
||||
- deadcode
|
||||
- depguard
|
||||
- dupl
|
||||
- goconst
|
||||
- gocyclo
|
||||
- gofmt
|
||||
- goimports
|
||||
- golint
|
||||
- gosec
|
||||
- gosimple
|
||||
- govet
|
||||
- ineffassign
|
||||
- interfacer
|
||||
- lll
|
||||
- misspell
|
||||
- nakedret
|
||||
- staticcheck
|
||||
- structcheck
|
||||
# stylecheck demands that acronyms not be treated as words
|
||||
# in camelCase, so JsonOp become JSONOp, etc. Yuck.
|
||||
# - stylecheck
|
||||
- typecheck
|
||||
- unconvert
|
||||
- unused
|
||||
- unparam
|
||||
- varcheck
|
||||
|
||||
linters-settings:
|
||||
dupl:
|
||||
threshold: 400
|
||||
lll:
|
||||
threshold: 400
|
||||
lll:
|
||||
line-length: 170
|
||||
gocyclo:
|
||||
min-complexity: 15
|
||||
11
.travis.yml
11
.travis.yml
@@ -1,10 +1,7 @@
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
# TODO: Speed up the slowness of the osx travis runs
|
||||
# Maybe cache brew installs?
|
||||
#
|
||||
# TODO: Uncomment when some gets the tests running on Windows.
|
||||
# TODO: Uncomment when tests running on Windows.
|
||||
# - windows
|
||||
|
||||
addons:
|
||||
@@ -23,7 +20,7 @@ git:
|
||||
language: go
|
||||
|
||||
go:
|
||||
- "1.13"
|
||||
- "1.12"
|
||||
|
||||
go_import_path: sigs.k8s.io/kustomize
|
||||
|
||||
@@ -34,9 +31,7 @@ before_install:
|
||||
install: true
|
||||
|
||||
script:
|
||||
- make verify-kustomize
|
||||
- ./travis/kyaml-pre-commit.sh
|
||||
- ./travis/check-go-mod.sh
|
||||
- ./travis/pre-commit.sh
|
||||
|
||||
# TBD. Suppressing for now.
|
||||
notifications:
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
261
Makefile
261
Makefile
@@ -1,250 +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 \
|
||||
test-examples-kustomize-against-latest
|
||||
all: test build
|
||||
|
||||
# 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 api/go.mod
|
||||
$(MYGOBIN)/golangci-lint-kustomize:
|
||||
( \
|
||||
set -e; \
|
||||
export GOBIN=$$(mktemp -d) \
|
||||
cd api; \
|
||||
GO111MODULE=on go install github.com/golangci/golangci-lint/cmd/golangci-lint; \
|
||||
mv $$GOBIN/golangci-lint $(MYGOBIN)/golangci-lint-kustomize \
|
||||
)
|
||||
test: generate-code test-lint test-go
|
||||
|
||||
# Version pinned by api/go.mod
|
||||
$(MYGOBIN)/mdrip:
|
||||
cd api; \
|
||||
go install github.com/monopole/mdrip
|
||||
test-go:
|
||||
go test -v ./...
|
||||
|
||||
# Version pinned by api/go.mod
|
||||
$(MYGOBIN)/stringer:
|
||||
cd api; \
|
||||
go install golang.org/x/tools/cmd/stringer
|
||||
test-lint:
|
||||
golangci-lint run ./...
|
||||
|
||||
# Version pinned by api/go.mod
|
||||
$(MYGOBIN)/goimports:
|
||||
cd api; \
|
||||
go install golang.org/x/tools/cmd/goimports
|
||||
generate-code:
|
||||
./plugin/generateBuiltins.sh $(GOPATH)
|
||||
|
||||
# To pin pluginator, use this recipe instead:
|
||||
# cd api;
|
||||
# go install sigs.k8s.io/kustomize/pluginator/v2
|
||||
$(MYGOBIN)/pluginator:
|
||||
cd pluginator; \
|
||||
go install .
|
||||
build:
|
||||
go build -o $(BIN_NAME) cmd/kustomize/main.go
|
||||
|
||||
# Install kustomize from whatever is checked out.
|
||||
$(MYGOBIN)/kustomize:
|
||||
cd kustomize; \
|
||||
go install .
|
||||
install:
|
||||
go install $(PWD)/cmd/kustomize
|
||||
|
||||
.PHONY: install-tools
|
||||
install-tools: \
|
||||
$(MYGOBIN)/goimports \
|
||||
$(MYGOBIN)/golangci-lint-kustomize \
|
||||
$(MYGOBIN)/mdrip \
|
||||
$(MYGOBIN)/pluginator \
|
||||
$(MYGOBIN)/stringer
|
||||
cover:
|
||||
# The plugin directory eludes coverage, and is therefore omitted
|
||||
go test ./pkg/... ./k8sdeps/... ./internal/... -coverprofile=$(COVER_FILE) && \
|
||||
go tool cover -html=$(COVER_FILE)
|
||||
|
||||
### 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
|
||||
clean:
|
||||
go clean
|
||||
rm -f $(BIN_NAME)
|
||||
rm -f $(COVER_FILE)
|
||||
|
||||
_builtinplugins = \
|
||||
AnnotationsTransformer.go \
|
||||
ConfigMapGenerator.go \
|
||||
HashTransformer.go \
|
||||
ImageTagTransformer.go \
|
||||
InventoryTransformer.go \
|
||||
LabelTransformer.go \
|
||||
LegacyOrderTransformer.go \
|
||||
NamespaceTransformer.go \
|
||||
PatchJson6902Transformer.go \
|
||||
PatchStrategicMergeTransformer.go \
|
||||
PatchTransformer.go \
|
||||
PrefixSuffixTransformer.go \
|
||||
ReplicaCountTransformer.go \
|
||||
SecretGenerator.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)/InventoryTransformer.go: $(pSrc)/inventorytransformer/InventoryTransformer.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
|
||||
|
||||
# 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 ./...
|
||||
|
||||
.PHONY: test-unit-kustomize-api
|
||||
test-unit-kustomize-api: $(builtinplugins)
|
||||
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
|
||||
|
||||
.PHONY:
|
||||
test-examples-kustomize-against-HEAD: $(MYGOBIN)/kustomize $(MYGOBIN)/mdrip
|
||||
./hack/testExamplesAgainstKustomize.sh HEAD
|
||||
|
||||
.PHONY:
|
||||
test-examples-kustomize-against-latest: $(MYGOBIN)/mdrip
|
||||
( \
|
||||
set -e; \
|
||||
/bin/rm -f $(MYGOBIN)/kustomize; \
|
||||
echo "Installing kustomize from latest."; \
|
||||
GO111MODULE=on go install sigs.k8s.io/kustomize/kustomize/v3; \
|
||||
./hack/testExamplesAgainstKustomize.sh latest; \
|
||||
echo "Reinstalling kustomize from HEAD."; \
|
||||
cd kustomize; go install .; \
|
||||
)
|
||||
|
||||
# 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; \
|
||||
)
|
||||
|
||||
# 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 binary.
|
||||
$(MYGOBIN)/helm:
|
||||
( \
|
||||
set -e; \
|
||||
d=$(shell mktemp -d); cd $$d; \
|
||||
wget https://storage.googleapis.com/kubernetes-helm/helm-v2.13.1-linux-amd64.tar.gz; \
|
||||
tar -xvzf helm-v2.13.1-linux-amd64.tar.gz; \
|
||||
mv linux-amd64/helm $(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
|
||||
|
||||
.PHONY: nuke
|
||||
nuke: clean
|
||||
sudo rm -rf $(shell go env GOPATH)/pkg/mod/sigs.k8s.io
|
||||
.PHONY: test build install clean generate-code test-go test-lint cover
|
||||
|
||||
14
README.md
14
README.md
@@ -28,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].
|
||||
|
||||
@@ -167,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/
|
||||
@@ -175,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,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,30 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package filesys
|
||||
|
||||
import "path/filepath"
|
||||
|
||||
// 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:]
|
||||
}
|
||||
@@ -1,205 +0,0 @@
|
||||
package filesys_test
|
||||
|
||||
import (
|
||||
"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: "/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 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
18
api/go.mod
18
api/go.mod
@@ -1,18 +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.4
|
||||
github.com/golangci/golangci-lint v1.21.0
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||
github.com/pkg/errors v0.8.1
|
||||
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff
|
||||
gopkg.in/yaml.v2 v2.2.4
|
||||
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/yaml v1.1.0
|
||||
)
|
||||
@@ -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,207 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"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 "":
|
||||
return CrawlIndexAndGithub
|
||||
case "index":
|
||||
return CrawlIndex
|
||||
case "github":
|
||||
return CrawlGithub
|
||||
default:
|
||||
return CrawlUnknown
|
||||
}
|
||||
}
|
||||
|
||||
func Usage() {
|
||||
fmt.Printf("Usage: %s [mode] [githubUser|githubRepo]\n", os.Args[0])
|
||||
fmt.Printf("\tmode can be one of [github-user, github-repo, index, github]\n")
|
||||
fmt.Printf("%s: crawl all the documents in the index and crawling all the kustomization files on Github\n", os.Args[0])
|
||||
fmt.Printf("%s index: crawl all the documents in the index\n", os.Args[0])
|
||||
fmt.Printf("%s gihub: crawl all the kustomization files on Github\n", os.Args[0])
|
||||
fmt.Printf("%s github-user <github-user>: Crawl all the kustomization files in all the repositories of a Github user\n", os.Args[0])
|
||||
fmt.Printf("\tFor example, %s github-user kubernetes-sigs\n", os.Args[0])
|
||||
fmt.Printf("%s github-repo <github-repo>: Crawl all the kustomization files in a Github repo\n", os.Args[0])
|
||||
fmt.Printf("\tFor example, %s github-repo kubernetes-sigs/kustomize\n", os.Args[0])
|
||||
}
|
||||
|
||||
func main() {
|
||||
githubToken := os.Getenv(githubAccessTokenVar)
|
||||
if githubToken == "" {
|
||||
fmt.Printf("Must set the variable '%s' to make github requests.\n",
|
||||
githubAccessTokenVar)
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
idx, err := index.NewKustomizeIndex(ctx)
|
||||
if err != nil {
|
||||
fmt.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 {
|
||||
fmt.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:
|
||||
fmt.Println("Deleting: ", d)
|
||||
return idx.Delete(d.ID())
|
||||
default:
|
||||
fmt.Println("Inserting: ", 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.
|
||||
// This helps avoid indexing a given document multiple times.
|
||||
seen := make(map[string]struct{})
|
||||
|
||||
var mode CrawlMode
|
||||
if len(os.Args) == 1 {
|
||||
mode = CrawlIndexAndGithub
|
||||
} else {
|
||||
mode = NewCrawlMode(os.Args[1])
|
||||
}
|
||||
|
||||
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.Copy())
|
||||
}
|
||||
}
|
||||
if err := it.Err(); err != nil {
|
||||
fmt.Printf("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("", "")}
|
||||
crawler.CrawlGithub(ctx, crawlers, docConverter, indexFunc, seen)
|
||||
case CrawlUser:
|
||||
if len(os.Args) < 3 {
|
||||
Usage()
|
||||
log.Fatalf("Please specify a github user!")
|
||||
}
|
||||
crawlers := []crawler.Crawler{ghCrawlerConstructor(os.Args[2], "")}
|
||||
crawler.CrawlGithub(ctx, crawlers, docConverter, indexFunc, seen)
|
||||
case CrawlRepo:
|
||||
if len(os.Args) < 3 {
|
||||
Usage()
|
||||
log.Fatalf("Please specify a github repo!")
|
||||
}
|
||||
crawlers := []crawler.Crawler{ghCrawlerConstructor("", os.Args[2])}
|
||||
crawler.CrawlGithub(ctx, crawlers, docConverter, indexFunc, seen)
|
||||
case CrawlUnknown:
|
||||
Usage()
|
||||
log.Fatalf("The crawler mode must be one of [github-user, github-repo, 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,150 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/internal/crawl/index"
|
||||
"sigs.k8s.io/kustomize/api/konfig"
|
||||
)
|
||||
|
||||
// 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]++
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// isKustomizationFile determines whether a file path is a kustomization file
|
||||
func isKustomizationFile(path string) bool {
|
||||
basename := filepath.Base(path)
|
||||
for _, name := range konfig.RecognizedKustomizationFileNames() {
|
||||
if basename == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 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 SortMapKeyByValue(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
|
||||
}
|
||||
|
||||
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.`)
|
||||
flag.Parse()
|
||||
|
||||
ctx := context.Background()
|
||||
idx, err := index.NewKustomizeIndex(ctx)
|
||||
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{})
|
||||
|
||||
// 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 {
|
||||
// check whether there is any duplicate IDs in the index
|
||||
if _, ok := ids[hit.ID]; !ok {
|
||||
ids[hit.ID] = struct{}{}
|
||||
} else {
|
||||
fmt.Printf("Found duplicate ID (%s)\n", hit.ID)
|
||||
}
|
||||
|
||||
count++
|
||||
iterateArr(hit.Document.Kinds, kindsMap)
|
||||
iterateArr(hit.Document.Identifiers, identifiersMap)
|
||||
|
||||
if isKustomizationFile(hit.Document.FilePath) {
|
||||
kustomizationFilecount++
|
||||
iterateArr(hit.Document.Identifiers, kustomizeIdentifiersMap)
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := it.Err(); err != nil {
|
||||
fmt.Printf("Error iterating: %v\n", err)
|
||||
}
|
||||
|
||||
sortedKindsMapKeys := SortMapKeyByValue(kindsMap)
|
||||
sortedIdentifiersMapKeys := SortMapKeyByValue(identifiersMap)
|
||||
sortedKustomizeIdentifiersMapKeys := SortMapKeyByValue(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++
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,48 +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 {
|
||||
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,2 +0,0 @@
|
||||
<ADD YOUR GITHUB PERSONAL ACCESS TOKEN HERE WITHOUT A TRAILING NEWLINE>
|
||||
Run: printf "<your-token>" > github_api_secret.txt
|
||||
@@ -1,54 +0,0 @@
|
||||
There are three ways of running the crawler job.
|
||||
|
||||
# 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"]
|
||||
args: []
|
||||
```
|
||||
|
||||
Or
|
||||
|
||||
```
|
||||
command: ["/crawler"]
|
||||
args: [""]
|
||||
```
|
||||
|
||||
# Crawling all the documents in the index
|
||||
|
||||
The `command` and `args` field of the container should be:
|
||||
|
||||
```
|
||||
command: ["/crawler"]
|
||||
args: ["index"]
|
||||
```
|
||||
|
||||
# Crawling all the kustomization files on Github
|
||||
|
||||
The `command` and `args` field of the container should be:
|
||||
|
||||
```
|
||||
command: ["/crawler"]
|
||||
args: ["github"]
|
||||
```
|
||||
|
||||
# Crawling all the kustomization files in a Github repo
|
||||
|
||||
The `command` and `args` field of the container should be like:
|
||||
|
||||
```
|
||||
command: ["/crawler"]
|
||||
args: ["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", "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: ["--kinds=50", "--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,43 +0,0 @@
|
||||
apiVersion: elasticsearch.cloud.google.com/v1alpha1
|
||||
kind: ESCluster
|
||||
metadata:
|
||||
name: esbasic
|
||||
spec:
|
||||
plugin:
|
||||
pluginList:
|
||||
- repository-gcs
|
||||
- ingest-user-agent
|
||||
- ingest-geoip
|
||||
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,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,304 +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/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) 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
|
||||
|
||||
Match(*doc.Document) bool
|
||||
}
|
||||
|
||||
type CrawledDocument interface {
|
||||
ID() string
|
||||
GetDocument() *doc.Document
|
||||
// Get all the Documents directly referred in a Document.
|
||||
GetResources() ([]*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 map[string]struct{}, stack *CrawlSeed) {
|
||||
|
||||
seen[cdoc.ID()] = struct{}{}
|
||||
|
||||
// Insert into index
|
||||
if err := indx(cdoc, index.InsertOrUpdate); err != nil {
|
||||
logger.Printf("Failed to insert or update %s %s: %v",
|
||||
cdoc.GetDocument().RepositoryURL, cdoc.GetDocument().FilePath, err)
|
||||
return
|
||||
}
|
||||
|
||||
deps, err := cdoc.GetResources()
|
||||
if err != nil {
|
||||
logger.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, dep := range deps {
|
||||
if _, ok := seen[dep.ID()]; ok {
|
||||
continue
|
||||
}
|
||||
*stack = append(*stack, dep)
|
||||
}
|
||||
}
|
||||
|
||||
func doCrawl(ctx context.Context, docsPtr *CrawlSeed, crawlers []Crawler, conv Converter, indx IndexFunc,
|
||||
seen map[string]struct{}, stack *CrawlSeed) {
|
||||
|
||||
UpdatedDocCount := 0
|
||||
seenDocCount := 0
|
||||
cachedDocCount := 0
|
||||
findMatchErrCount := 0
|
||||
FetchDocumentErrCount := 0
|
||||
SetCreatedErrCount := 0
|
||||
convErrCount := 0
|
||||
deleteDocCount := 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)]
|
||||
|
||||
if _, ok := seen[tail.ID()]; ok {
|
||||
seenDocCount++
|
||||
continue
|
||||
}
|
||||
|
||||
if tail.WasCached() {
|
||||
logger.Printf("%s %s is cached already", tail.RepositoryURL, tail.FilePath)
|
||||
cachedDocCount++
|
||||
continue
|
||||
}
|
||||
|
||||
match := findMatch(tail, crawlers)
|
||||
if match == nil {
|
||||
logIfErr(fmt.Errorf("%v could not match any crawler", tail))
|
||||
findMatchErrCount++
|
||||
continue
|
||||
}
|
||||
|
||||
logger.Println("Crawling ", tail.RepositoryURL, tail.FilePath)
|
||||
if err := match.FetchDocument(ctx, tail); err != nil {
|
||||
logger.Printf("FetchDocument failed on %s %s: %v",
|
||||
tail.RepositoryURL, tail.FilePath, err)
|
||||
FetchDocumentErrCount++
|
||||
// delete the document from the index
|
||||
cdoc := &doc.KustomizationDocument{
|
||||
Document: *tail,
|
||||
}
|
||||
seen[cdoc.ID()] = struct{}{}
|
||||
if err := indx(cdoc, index.Delete); err != nil {
|
||||
logger.Printf("Failed to delete %s %s: %v",
|
||||
cdoc.RepositoryURL, cdoc.FilePath, err)
|
||||
}
|
||||
deleteDocCount++
|
||||
continue
|
||||
}
|
||||
|
||||
if err := match.SetCreated(ctx, tail); err != nil {
|
||||
logger.Printf("SetCreated failed on %s %s: %v",
|
||||
tail.RepositoryURL, tail.FilePath, 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 %s %s: %v",
|
||||
tail.RepositoryURL, tail.FilePath, 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 map[string]struct{}) {
|
||||
|
||||
// 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)
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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) []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)
|
||||
}(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 map[string]struct{}) {
|
||||
// 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()
|
||||
for cdoc := range ch {
|
||||
if _, ok := seen[cdoc.ID()]; ok {
|
||||
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); 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)
|
||||
}
|
||||
@@ -1,415 +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/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/purell v1.0.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/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/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
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/bombsimon/wsl v1.2.5/go.mod h1:43lEF/i0kpXbLCeDXL9LMT8c92HyBywXb0AsgMHYngM=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
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/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/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
|
||||
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/go-critic/go-critic v0.3.5-0.20190904082202-d79a9f0c64db/go.mod h1:+sE8vrLDS2M0pZkBk0wy6+nLdKexVDrl/jBqQOTDThA=
|
||||
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/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
|
||||
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.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
|
||||
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
|
||||
github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
|
||||
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
|
||||
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-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.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/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-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
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.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-ps v0.0.0-20190716172923-621e5597135b/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk=
|
||||
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/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/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/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/securego/gosec v0.0.0-20191002120514-e680875ea14d/go.mod h1:w5+eXa0mYznDkHaMCXA4XYffjlH+cy1oyKbfzJXa2Do=
|
||||
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/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/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.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/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/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/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
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-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-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-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-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-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI=
|
||||
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-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/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-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-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=
|
||||
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/api v0.3.1 h1:oqMIXvS6tFEUVuKIRUKDa05eC4Hh+cb9JYg8Zhp2d24=
|
||||
sigs.k8s.io/kustomize/api v0.3.1/go.mod h1:A+ATnlHqzictQfQC1q3KB/T6MSr0UWQsrrLxMWkge2E=
|
||||
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=
|
||||
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
|
||||
@@ -1,180 +0,0 @@
|
||||
Find out the largest value of the `creationTime` field:
|
||||
```
|
||||
curl -X POST "${ElasticSearchURL}:9200/kustomize/_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 -X POST "${ElasticSearchURL}:9200/kustomize/_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 -X POST "${ElasticSearchURL}:9200/kustomize/_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 -X POST "${ElasticSearchURL}:9200/kustomize/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"must_not": {
|
||||
"regexp": { "filePath": ".*/kustomization((.yaml)?|(.yml)?)/*" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"aggs" : {
|
||||
"min_creationTime" : { "min" : { "field" : "creationTime" } }
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Query all the documents whose `creationTime` <= `2016-07-29T17:38:26.000Z`:
|
||||
```
|
||||
curl -X GET "${ElasticSearchURL}:9200/kustomize/_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 -X GET "${ElasticSearchURL}:9200/kustomize/_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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Aggregate how many new kustomization files were added into Github each month:
|
||||
```
|
||||
curl -X GET "${ElasticSearchURL}:9200/kustomize/_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 -X GET "${ElasticSearchURL}:9200/kustomize/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"must_not": [
|
||||
{ "regexp": { "filePath": ".*/kustomization((.yaml)?|(.yml)?)/*" }}
|
||||
]
|
||||
}
|
||||
},
|
||||
"aggs" : {
|
||||
"newFiles_over_time" : {
|
||||
"date_histogram" : {
|
||||
"field" : "creationTime",
|
||||
"interval" : "month"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Aggregate how many new kustomization files were added into Github each year:
|
||||
```
|
||||
curl -X GET "${ElasticSearchURL}:9200/kustomize/_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 -X GET "${ElasticSearchURL}:9200/kustomize/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"must_not": [
|
||||
{ "regexp": { "filePath": ".*/kustomization((.yaml)?|(.yml)?)/*" }}
|
||||
]
|
||||
}
|
||||
},
|
||||
"aggs" : {
|
||||
"newFiles_over_time" : {
|
||||
"date_histogram" : {
|
||||
"field" : "creationTime",
|
||||
"interval" : "year"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
@@ -1,32 +0,0 @@
|
||||
Count distinct values of the `defaultBranch` field:
|
||||
```
|
||||
curl -X POST "${ElasticSearchURL}:9200/kustomize/_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 -X GET "${ElasticSearchURL}:9200/kustomize/_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 -X GET "${ElasticSearchURL}:9200/kustomize/_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 -X GET "${ElasticSearchURL}:9200/kustomize/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"exists": {
|
||||
"field": "creationTime"
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Find all the documents whose `creationTime` field is not set:
|
||||
```
|
||||
curl -X GET "${ElasticSearchURL}:9200/kustomize/_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,66 +0,0 @@
|
||||
Count the documents in the index whose `repositoryUrl` field starts with
|
||||
`https://github.com/`:
|
||||
```
|
||||
curl -X GET "${ElasticSearchURL}:9200/kustomize/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"filter": [
|
||||
{ "regexp": { "repositoryUrl": "https://github.com/.*" }}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Count the documents in the index whose `repositoryUrl` field does not start with
|
||||
`https://github.com/`:
|
||||
```
|
||||
curl -X GET "${ElasticSearchURL}:9200/kustomize/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"must_not": [
|
||||
{ "regexp": { "repositoryUrl": "https://github.com/.*" }}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Search all the documents matching the given `repositoryUrl` and `filePath`, and return
|
||||
a version for each search hit:
|
||||
```
|
||||
curl -X GET "${ElasticSearchURL}:9200/kustomize/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"size": 10000,
|
||||
"version": true,
|
||||
"query": {
|
||||
"bool": {
|
||||
"filter": [
|
||||
{ "regexp": { "repositoryUrl": "git@github.com:talos-systems/talos-controller-manager" }},
|
||||
{ "regexp": { "filePath": "hack/config.*" }}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Search all the documents whose filePath ends with one of these following three filenames:
|
||||
`kustomization.yaml`, `kustomization.yml`, `kustomization`:
|
||||
```
|
||||
curl -X GET "${ElasticSearchURL}:9200/kustomize/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"filter": [
|
||||
{ "regexp": { "filePath": ".*/kustomization((.yaml)?|(.yml)?)/*" }}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
@@ -1,19 +0,0 @@
|
||||
Check the health status of an ElasticSearch cluster:
|
||||
```
|
||||
curl -X GET "${ElasticSearchURL}:9200/_cat/health?v&pretty"
|
||||
```
|
||||
|
||||
Check the indices in an ElasticSearch cluster:
|
||||
```
|
||||
curl "${ElasticSearchURL}:9200/_cat/indices?v"
|
||||
```
|
||||
|
||||
Get the mapping of the index:
|
||||
```
|
||||
curl -X GET "${ElasticSearchURL}:9200/kustomize/_mapping?pretty"
|
||||
```
|
||||
|
||||
Delete the kustomize index from the ElasticSearch cluster (**Use this command with caution**):
|
||||
```
|
||||
curl -X DELETE "${ElasticSearchURL}:9200/kustomize?pretty"
|
||||
```
|
||||
@@ -1,125 +0,0 @@
|
||||
Count distinct values of the `repositoryUrl` field:
|
||||
```
|
||||
curl -X POST "${ElasticSearchURL}:9200/kustomize/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"aggs" : {
|
||||
"repositoryUrl_count" : {
|
||||
"cardinality" : {
|
||||
"field" : "repositoryUrl",
|
||||
"precision_threshold": 40000
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Count how many Github repositories include kustomization files:
|
||||
```
|
||||
curl -X POST "${ElasticSearchURL}:9200/kustomize/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"filter": [
|
||||
{ "regexp": { "filePath": ".*/kustomization((.yaml)?|(.yml)?)/*" }}
|
||||
]
|
||||
}
|
||||
},
|
||||
"aggs" : {
|
||||
"repositoryUrl_count" : {
|
||||
"cardinality" : {
|
||||
"field" : "repositoryUrl",
|
||||
"precision_threshold": 40000
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Count how many Github repositories include kustomize resource files:
|
||||
```
|
||||
curl -X POST "${ElasticSearchURL}:9200/kustomize/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"must_not": {
|
||||
"regexp": { "filePath": ".*/kustomization((.yaml)?|(.yml)?)/*" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"aggs" : {
|
||||
"repositoryUrl_count" : {
|
||||
"cardinality" : {
|
||||
"field" : "repositoryUrl",
|
||||
"precision_threshold": 40000
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
List all the github repositories including kustomization files and kustomize resource files,
|
||||
and how many kustomization files and kustomize resource files each github repository includes
|
||||
(the github repository including the most kustomization files is listed first):
|
||||
```
|
||||
curl -X GET "${ElasticSearchURL}:9200/kustomize/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"aggs" : {
|
||||
"repositoryUrl" : {
|
||||
"terms" : {
|
||||
"field" : "repositoryUrl",
|
||||
"size": 2082
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
List the top 20 Github repositories including the most amount of kustomization files:
|
||||
```
|
||||
curl -X GET "${ElasticSearchURL}:9200/kustomize/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"filter": [
|
||||
{ "regexp": { "filePath": ".*/kustomization((.yaml)?|(.yml)?)/*" }}
|
||||
]
|
||||
}
|
||||
},
|
||||
"aggs" : {
|
||||
"repositoryUrl" : {
|
||||
"terms" : {
|
||||
"field" : "repositoryUrl",
|
||||
"size": 20
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
List the top 20 Github repositories including the most amount of kustomize resource files:
|
||||
```
|
||||
curl -X GET "${ElasticSearchURL}:9200/kustomize/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"must_not": {
|
||||
"regexp": { "filePath": ".*/kustomization((.yaml)?|(.yml)?)/*" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"aggs" : {
|
||||
"repositoryUrl" : {
|
||||
"terms" : {
|
||||
"field" : "repositoryUrl",
|
||||
"size": 20
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
@@ -1,148 +0,0 @@
|
||||
Search for all the kustomize resource files including a Deployment object:
|
||||
```
|
||||
curl -X GET "${ElasticSearchURL}:9200/kustomize/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"match" : {
|
||||
"kinds" : {
|
||||
"query" : "Deployment"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Search for all the kustomize resource files including a Deployment object, but only
|
||||
including the `kinds` field in the result:
|
||||
```
|
||||
curl -X GET "${ElasticSearchURL}:9200/kustomize/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"_source": {
|
||||
"includes": ["kinds"]
|
||||
},
|
||||
"query": {
|
||||
"match" : {
|
||||
"kinds" : {
|
||||
"query" : "Deployment"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Search for all the kustomize resource files including both a Deployment object and
|
||||
a Service object:
|
||||
```
|
||||
curl -X GET "${ElasticSearchURL}:9200/kustomize/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"match" : {
|
||||
"kinds" : {
|
||||
"query" : "Deployment Service",
|
||||
"operator" : "and"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Count the number of documents including Deployment and the number of documents
|
||||
including Service:
|
||||
```
|
||||
curl -X GET "${ElasticSearchURL}:9200/kustomize/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"size": 0,
|
||||
"aggs" : {
|
||||
"messages" : {
|
||||
"filters" : {
|
||||
"filters" : {
|
||||
"Deployment" : { "match" : { "kinds" : "Deployment" }},
|
||||
"Service" : { "match" : { "kinds" : "Service" }}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Search for all the kustomization files involving CRDs:
|
||||
```
|
||||
curl -X GET "${ElasticSearchURL}:9200/kustomize/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"size": 10000,
|
||||
"query": {
|
||||
"match" : {
|
||||
"identifiers" : {
|
||||
"query" : "crds"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Search for all the kustomization files defining configMapGenerator:
|
||||
```
|
||||
curl -X GET "${ElasticSearchURL}:9200/kustomize/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"size": 10000,
|
||||
"query": {
|
||||
"match" : {
|
||||
"identifiers" : {
|
||||
"query" : "configMapGenerator"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Search for all the documents having a `kind` field:
|
||||
```
|
||||
curl -X GET "${ElasticSearchURL}:9200/kustomize/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"filter": [
|
||||
{ "match" : { "identifiers" : { "query" : "kind" }}}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Search for all the kuostmization files having a `kind` field:
|
||||
```
|
||||
curl -X GET "${ElasticSearchURL}:9200/kustomize/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"filter": [
|
||||
{ "regexp": { "filePath": ".*/kustomization((.yaml)?|(.yml)?)" }},
|
||||
{ "match" : { "identifiers" : { "query" : "kind" }}}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
Search for all the kustomization files defining the `generatorOptions:disableNameSuffixHash` feature:
|
||||
```
|
||||
curl -X GET "${ElasticSearchURL}:9200/kustomize/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"match" : {
|
||||
"identifiers" : {
|
||||
"query" : "generatorOptions:disableNameSuffixHash"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'
|
||||
```
|
||||
5895
api/internal/crawl/ui/package-lock.json
generated
5895
api/internal/crawl/ui/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"name": "kustomize-search",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build --prod --aot",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^8.2.14",
|
||||
"@angular/cdk": "~8.2.3",
|
||||
"@angular/common": "^8.2.14",
|
||||
"@angular/compiler": "^8.2.14",
|
||||
"@angular/core": "^8.2.14",
|
||||
"@angular/forms": "^8.2.14",
|
||||
"@angular/http": "^7.2.15",
|
||||
"@angular/material": "^8.2.3",
|
||||
"@angular/platform-browser": "^8.2.14",
|
||||
"@angular/platform-browser-dynamic": "^8.2.14",
|
||||
"@angular/router": "^8.2.14",
|
||||
"angular-google-charts": "^0.1.6",
|
||||
"chart.js": "^2.9.3",
|
||||
"core-js": "^3.5.0",
|
||||
"hammerjs": "^2.0.8",
|
||||
"rxjs": "~6.5.3",
|
||||
"serialize-javascript": "^2.1.2",
|
||||
"tslib": "^1.10.0",
|
||||
"zone.js": "~0.10.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^0.803.20",
|
||||
"@angular/cli": "^8.3.20",
|
||||
"@angular/compiler-cli": "^8.2.14",
|
||||
"@angular/language-service": "^8.2.14",
|
||||
"@types/jasmine": "^3.5.0",
|
||||
"@types/jasminewd2": "^2.0.8",
|
||||
"@types/node": "~12.12.17",
|
||||
"codelyzer": "^5.2.0",
|
||||
"jasmine-core": "~3.5.0",
|
||||
"jasmine-spec-reporter": "~4.2.1",
|
||||
"karma": "~4.4.1",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-coverage-istanbul-reporter": "^2.1.1",
|
||||
"karma-jasmine": "~2.0.1",
|
||||
"karma-jasmine-html-reporter": "^1.4.2",
|
||||
"protractor": "~5.4.2",
|
||||
"ts-node": "~8.5.4",
|
||||
"tslint": "~5.20.1",
|
||||
"typescript": "~3.7.3"
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package builtinconfig provides legacy methods for
|
||||
// configuring builtin plugins from a common config file.
|
||||
// As a user, its best to configure plugins individually
|
||||
// with plugin config files specified in the `transformers:`
|
||||
// or `generators:` field, than to use this legacy
|
||||
// configuration technique.
|
||||
package builtinconfig
|
||||
@@ -1,42 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package builtinconfig
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/ifc"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// loadDefaultConfig returns a TranformerConfig
|
||||
// object from a list of files.
|
||||
func loadDefaultConfig(
|
||||
ldr ifc.Loader, paths []string) (*TransformerConfig, error) {
|
||||
result := &TransformerConfig{}
|
||||
for _, path := range paths {
|
||||
data, err := ldr.Load(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t, err := makeTransformerConfigFromBytes(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result, err = result.Merge(t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// makeTransformerConfigFromBytes returns a TransformerConfig object from bytes
|
||||
func makeTransformerConfigFromBytes(data []byte) (*TransformerConfig, error) {
|
||||
var t TransformerConfig
|
||||
err := yaml.Unmarshal(data, &t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t.sortFields()
|
||||
return &t, nil
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package builtinconfig
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/filesys"
|
||||
"sigs.k8s.io/kustomize/api/loader"
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
func TestLoadDefaultConfigsFromFiles(t *testing.T) {
|
||||
fSys := filesys.MakeFsInMemory()
|
||||
err := fSys.WriteFile("config.yaml", []byte(`
|
||||
namePrefix:
|
||||
- path: nameprefix/path
|
||||
kind: SomeKind
|
||||
`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ldr, err := loader.NewLoader(
|
||||
loader.RestrictionRootOnly, filesys.Separator, fSys)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tCfg, err := loadDefaultConfig(ldr, []string{"config.yaml"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expected := &TransformerConfig{
|
||||
NamePrefix: []types.FieldSpec{
|
||||
{
|
||||
Gvk: resid.Gvk{Kind: "SomeKind"},
|
||||
Path: "nameprefix/path",
|
||||
},
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(tCfg, expected) {
|
||||
t.Fatalf("expected %v\n but go6t %v\n", expected, tCfg)
|
||||
}
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package builtinconfig
|
||||
|
||||
import (
|
||||
"log"
|
||||
"sort"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/ifc"
|
||||
"sigs.k8s.io/kustomize/api/konfig/builtinpluginconsts"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
// TransformerConfig holds the data needed to perform transformations.
|
||||
type TransformerConfig struct {
|
||||
NamePrefix types.FsSlice `json:"namePrefix,omitempty" yaml:"namePrefix,omitempty"`
|
||||
NameSuffix types.FsSlice `json:"nameSuffix,omitempty" yaml:"nameSuffix,omitempty"`
|
||||
NameSpace types.FsSlice `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
CommonLabels types.FsSlice `json:"commonLabels,omitempty" yaml:"commonLabels,omitempty"`
|
||||
CommonAnnotations types.FsSlice `json:"commonAnnotations,omitempty" yaml:"commonAnnotations,omitempty"`
|
||||
NameReference nbrSlice `json:"nameReference,omitempty" yaml:"nameReference,omitempty"`
|
||||
VarReference types.FsSlice `json:"varReference,omitempty" yaml:"varReference,omitempty"`
|
||||
Images types.FsSlice `json:"images,omitempty" yaml:"images,omitempty"`
|
||||
Replicas types.FsSlice `json:"replicas,omitempty" yaml:"replicas,omitempty"`
|
||||
}
|
||||
|
||||
// MakeEmptyConfig returns an empty TransformerConfig object
|
||||
func MakeEmptyConfig() *TransformerConfig {
|
||||
return &TransformerConfig{}
|
||||
}
|
||||
|
||||
// MakeDefaultConfig returns a default TransformerConfig.
|
||||
func MakeDefaultConfig() *TransformerConfig {
|
||||
c, err := makeTransformerConfigFromBytes(
|
||||
builtinpluginconsts.GetDefaultFieldSpecs())
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to make default transformconfig: %v", err)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// MakeTransformerConfig returns a merger of custom config,
|
||||
// if any, with default config.
|
||||
func MakeTransformerConfig(
|
||||
ldr ifc.Loader, paths []string) (*TransformerConfig, error) {
|
||||
t1 := MakeDefaultConfig()
|
||||
if len(paths) == 0 {
|
||||
return t1, nil
|
||||
}
|
||||
t2, err := loadDefaultConfig(ldr, paths)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return t1.Merge(t2)
|
||||
}
|
||||
|
||||
// sortFields provides determinism in logging, tests, etc.
|
||||
func (t *TransformerConfig) sortFields() {
|
||||
sort.Sort(t.NamePrefix)
|
||||
sort.Sort(t.NameSpace)
|
||||
sort.Sort(t.CommonLabels)
|
||||
sort.Sort(t.CommonAnnotations)
|
||||
sort.Sort(t.NameReference)
|
||||
sort.Sort(t.VarReference)
|
||||
sort.Sort(t.Images)
|
||||
sort.Sort(t.Replicas)
|
||||
}
|
||||
|
||||
// AddPrefixFieldSpec adds a FieldSpec to NamePrefix
|
||||
func (t *TransformerConfig) AddPrefixFieldSpec(fs types.FieldSpec) (err error) {
|
||||
t.NamePrefix, err = t.NamePrefix.MergeOne(fs)
|
||||
return err
|
||||
}
|
||||
|
||||
// AddSuffixFieldSpec adds a FieldSpec to NameSuffix
|
||||
func (t *TransformerConfig) AddSuffixFieldSpec(fs types.FieldSpec) (err error) {
|
||||
t.NameSuffix, err = t.NameSuffix.MergeOne(fs)
|
||||
return err
|
||||
}
|
||||
|
||||
// AddLabelFieldSpec adds a FieldSpec to CommonLabels
|
||||
func (t *TransformerConfig) AddLabelFieldSpec(fs types.FieldSpec) (err error) {
|
||||
t.CommonLabels, err = t.CommonLabels.MergeOne(fs)
|
||||
return err
|
||||
}
|
||||
|
||||
// AddAnnotationFieldSpec adds a FieldSpec to CommonAnnotations
|
||||
func (t *TransformerConfig) AddAnnotationFieldSpec(fs types.FieldSpec) (err error) {
|
||||
t.CommonAnnotations, err = t.CommonAnnotations.MergeOne(fs)
|
||||
return err
|
||||
}
|
||||
|
||||
// AddNamereferenceFieldSpec adds a NameBackReferences to NameReference
|
||||
func (t *TransformerConfig) AddNamereferenceFieldSpec(
|
||||
nbrs NameBackReferences) (err error) {
|
||||
t.NameReference, err = t.NameReference.mergeOne(nbrs)
|
||||
return err
|
||||
}
|
||||
|
||||
// Merge merges two TransformerConfigs objects into
|
||||
// a new TransformerConfig object
|
||||
func (t *TransformerConfig) Merge(input *TransformerConfig) (
|
||||
merged *TransformerConfig, err error) {
|
||||
if input == nil {
|
||||
return t, nil
|
||||
}
|
||||
merged = &TransformerConfig{}
|
||||
merged.NamePrefix, err = t.NamePrefix.MergeAll(input.NamePrefix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
merged.NameSuffix, err = t.NameSuffix.MergeAll(input.NameSuffix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
merged.NameSpace, err = t.NameSpace.MergeAll(input.NameSpace)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
merged.CommonAnnotations, err = t.CommonAnnotations.MergeAll(
|
||||
input.CommonAnnotations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
merged.CommonLabels, err = t.CommonLabels.MergeAll(input.CommonLabels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
merged.VarReference, err = t.VarReference.MergeAll(input.VarReference)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
merged.NameReference, err = t.NameReference.mergeAll(input.NameReference)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
merged.Images, err = t.Images.MergeAll(input.Images)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
merged.Replicas, err = t.Replicas.MergeAll(input.Replicas)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
merged.sortFields()
|
||||
return merged, nil
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
// Code generated by "stringer -type=BuiltinPluginType"; DO NOT EDIT.
|
||||
|
||||
package builtinhelpers
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[Unknown-0]
|
||||
_ = x[AnnotationsTransformer-1]
|
||||
_ = x[ConfigMapGenerator-2]
|
||||
_ = x[HashTransformer-3]
|
||||
_ = x[ImageTagTransformer-4]
|
||||
_ = x[InventoryTransformer-5]
|
||||
_ = x[LabelTransformer-6]
|
||||
_ = x[LegacyOrderTransformer-7]
|
||||
_ = x[NamespaceTransformer-8]
|
||||
_ = x[PatchJson6902Transformer-9]
|
||||
_ = x[PatchStrategicMergeTransformer-10]
|
||||
_ = x[PatchTransformer-11]
|
||||
_ = x[PrefixSuffixTransformer-12]
|
||||
_ = x[ReplicaCountTransformer-13]
|
||||
_ = x[SecretGenerator-14]
|
||||
}
|
||||
|
||||
const _BuiltinPluginType_name = "UnknownAnnotationsTransformerConfigMapGeneratorHashTransformerImageTagTransformerInventoryTransformerLabelTransformerLegacyOrderTransformerNamespaceTransformerPatchJson6902TransformerPatchStrategicMergeTransformerPatchTransformerPrefixSuffixTransformerReplicaCountTransformerSecretGenerator"
|
||||
|
||||
var _BuiltinPluginType_index = [...]uint16{0, 7, 29, 47, 62, 81, 101, 117, 139, 159, 183, 213, 229, 252, 275, 290}
|
||||
|
||||
func (i BuiltinPluginType) String() string {
|
||||
if i < 0 || i >= BuiltinPluginType(len(_BuiltinPluginType_index)-1) {
|
||||
return "BuiltinPluginType(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _BuiltinPluginType_name[_BuiltinPluginType_index[i]:_BuiltinPluginType_index[i+1]]
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package loader_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/filesys"
|
||||
. "sigs.k8s.io/kustomize/api/internal/plugins/loader"
|
||||
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
|
||||
"sigs.k8s.io/kustomize/api/konfig"
|
||||
"sigs.k8s.io/kustomize/api/loader"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
|
||||
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
|
||||
)
|
||||
|
||||
const (
|
||||
//nolint:gosec
|
||||
secretGenerator = `
|
||||
apiVersion: builtin
|
||||
kind: SecretGenerator
|
||||
metadata:
|
||||
name: secretGenerator
|
||||
name: mySecret
|
||||
behavior: merge
|
||||
envFiles:
|
||||
- a.env
|
||||
- b.env
|
||||
valueFiles:
|
||||
- longsecret.txt
|
||||
literals:
|
||||
- FRUIT=apple
|
||||
- VEGETABLE=carrot
|
||||
`
|
||||
someServiceGenerator = `
|
||||
apiVersion: someteam.example.com/v1
|
||||
kind: SomeServiceGenerator
|
||||
metadata:
|
||||
name: myServiceGenerator
|
||||
service: my-service
|
||||
port: "12345"
|
||||
`
|
||||
)
|
||||
|
||||
func TestLoader(t *testing.T) {
|
||||
th := kusttest_test.MakeEnhancedHarness(t).
|
||||
BuildGoPlugin("builtin", "", "SecretGenerator").
|
||||
BuildGoPlugin("someteam.example.com", "v1", "SomeServiceGenerator")
|
||||
defer th.Reset()
|
||||
rmF := resmap.NewFactory(resource.NewFactory(
|
||||
kunstruct.NewKunstructuredFactoryImpl()), nil)
|
||||
fLdr, err := loader.NewLoader(
|
||||
loader.RestrictionRootOnly,
|
||||
filesys.Separator, filesys.MakeFsInMemory())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
c, err := konfig.EnabledPluginConfig()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pLdr := NewLoader(c, rmF)
|
||||
if pLdr == nil {
|
||||
t.Fatal("expect non-nil loader")
|
||||
}
|
||||
m, err := rmF.NewResMapFromBytes([]byte(
|
||||
someServiceGenerator + "---\n" + secretGenerator))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = pLdr.LoadGenerators(
|
||||
fLdr, valtest_test.MakeFakeValidator(), m)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package target
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/kustomize/api/konfig"
|
||||
)
|
||||
|
||||
type errMissingKustomization struct {
|
||||
path string
|
||||
}
|
||||
|
||||
func (e *errMissingKustomization) Error() string {
|
||||
return fmt.Sprintf(
|
||||
"unable to find one of %v in directory '%s'",
|
||||
commaOr(quoted(konfig.RecognizedKustomizationFileNames())),
|
||||
e.path)
|
||||
}
|
||||
|
||||
func IsMissingKustomizationFileError(err error) bool {
|
||||
_, ok := err.(*errMissingKustomization)
|
||||
if ok {
|
||||
return true
|
||||
}
|
||||
_, ok = errors.Cause(err).(*errMissingKustomization)
|
||||
return ok
|
||||
}
|
||||
|
||||
func NewErrMissingKustomization(p string) *errMissingKustomization {
|
||||
return &errMissingKustomization{path: p}
|
||||
}
|
||||
|
||||
func quoted(l []string) []string {
|
||||
r := make([]string, len(l))
|
||||
for i, v := range l {
|
||||
r[i] = "'" + v + "'"
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func commaOr(q []string) string {
|
||||
return strings.Join(q[:len(q)-1], ", ") + " or " + q[len(q)-1]
|
||||
}
|
||||
@@ -1,179 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package target_test
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/filesys"
|
||||
"sigs.k8s.io/kustomize/api/ifc"
|
||||
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
|
||||
)
|
||||
|
||||
// KustTarget is primarily tested in the krusty package with
|
||||
// high level tests.
|
||||
|
||||
func TestMakeCustomizedResMap(t *testing.T) {
|
||||
fSys := filesys.MakeFsInMemory()
|
||||
th := kusttest_test.MakeHarnessWithFs(t, fSys)
|
||||
th.WriteK("/whatever", `
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
namePrefix: foo-
|
||||
nameSuffix: -bar
|
||||
namespace: ns1
|
||||
commonLabels:
|
||||
app: nginx
|
||||
commonAnnotations:
|
||||
note: This is a test annotation
|
||||
resources:
|
||||
- deployment.yaml
|
||||
- namespace.yaml
|
||||
generatorOptions:
|
||||
disableNameSuffixHash: false
|
||||
configMapGenerator:
|
||||
- name: literalConfigMap
|
||||
literals:
|
||||
- DB_USERNAME=admin
|
||||
- DB_PASSWORD=somepw
|
||||
secretGenerator:
|
||||
- name: secret
|
||||
literals:
|
||||
- DB_USERNAME=admin
|
||||
- DB_PASSWORD=somepw
|
||||
type: Opaque
|
||||
patchesJson6902:
|
||||
- target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: Deployment
|
||||
name: dply1
|
||||
path: jsonpatch.json
|
||||
`)
|
||||
th.WriteF("/whatever/deployment.yaml", `
|
||||
apiVersion: apps/v1
|
||||
metadata:
|
||||
name: dply1
|
||||
kind: Deployment
|
||||
`)
|
||||
th.WriteF("/whatever/namespace.yaml", `
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: ns1
|
||||
`)
|
||||
th.WriteF("/whatever/jsonpatch.json", `[
|
||||
{"op": "add", "path": "/spec/replica", "value": "3"}
|
||||
]`)
|
||||
|
||||
resFactory := resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())
|
||||
|
||||
resources := []*resource.Resource{
|
||||
resFactory.FromMapWithName("dply1", map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "foo-dply1-bar",
|
||||
"namespace": "ns1",
|
||||
"labels": map[string]interface{}{
|
||||
"app": "nginx",
|
||||
},
|
||||
"annotations": map[string]interface{}{
|
||||
"note": "This is a test annotation",
|
||||
},
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"replica": "3",
|
||||
"selector": map[string]interface{}{
|
||||
"matchLabels": map[string]interface{}{
|
||||
"app": "nginx",
|
||||
},
|
||||
},
|
||||
"template": map[string]interface{}{
|
||||
"metadata": map[string]interface{}{
|
||||
"annotations": map[string]interface{}{
|
||||
"note": "This is a test annotation",
|
||||
},
|
||||
"labels": map[string]interface{}{
|
||||
"app": "nginx",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
resFactory.FromMapWithName("ns1", map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Namespace",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "foo-ns1-bar",
|
||||
"labels": map[string]interface{}{
|
||||
"app": "nginx",
|
||||
},
|
||||
"annotations": map[string]interface{}{
|
||||
"note": "This is a test annotation",
|
||||
},
|
||||
},
|
||||
}),
|
||||
resFactory.FromMapWithName("literalConfigMap",
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "foo-literalConfigMap-bar-8d2dkb8k24",
|
||||
"namespace": "ns1",
|
||||
"labels": map[string]interface{}{
|
||||
"app": "nginx",
|
||||
},
|
||||
"annotations": map[string]interface{}{
|
||||
"note": "This is a test annotation",
|
||||
},
|
||||
},
|
||||
"data": map[string]interface{}{
|
||||
"DB_USERNAME": "admin",
|
||||
"DB_PASSWORD": "somepw",
|
||||
},
|
||||
}),
|
||||
resFactory.FromMapWithName("secret",
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Secret",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "foo-secret-bar-9btc7bt4kb",
|
||||
"namespace": "ns1",
|
||||
"labels": map[string]interface{}{
|
||||
"app": "nginx",
|
||||
},
|
||||
"annotations": map[string]interface{}{
|
||||
"note": "This is a test annotation",
|
||||
},
|
||||
},
|
||||
"type": ifc.SecretTypeOpaque,
|
||||
"data": map[string]interface{}{
|
||||
"DB_USERNAME": base64.StdEncoding.EncodeToString([]byte("admin")),
|
||||
"DB_PASSWORD": base64.StdEncoding.EncodeToString([]byte("somepw")),
|
||||
},
|
||||
}),
|
||||
}
|
||||
|
||||
expected := resmap.New()
|
||||
for _, r := range resources {
|
||||
if err := expected.Append(r); err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
actual, err := makeKustTargetWithRf(
|
||||
t, fSys, "/whatever", resFactory).MakeCustomizedResMap()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected Resources error %v", err)
|
||||
}
|
||||
|
||||
if err = expected.ErrorIfNotEqualLists(actual); err != nil {
|
||||
t.Fatalf("unexpected inequality: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package target_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/filesys"
|
||||
"sigs.k8s.io/kustomize/api/internal/k8sdeps/transformer"
|
||||
pLdr "sigs.k8s.io/kustomize/api/internal/plugins/loader"
|
||||
"sigs.k8s.io/kustomize/api/internal/target"
|
||||
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
|
||||
"sigs.k8s.io/kustomize/api/konfig"
|
||||
fLdr "sigs.k8s.io/kustomize/api/loader"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
|
||||
)
|
||||
|
||||
func makeKustTarget(
|
||||
t *testing.T,
|
||||
fSys filesys.FileSystem,
|
||||
root string) *target.KustTarget {
|
||||
return makeKustTargetWithRf(
|
||||
t, fSys, root,
|
||||
resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl()))
|
||||
}
|
||||
|
||||
func makeKustTargetWithRf(
|
||||
t *testing.T,
|
||||
fSys filesys.FileSystem,
|
||||
root string,
|
||||
resFact *resource.Factory) *target.KustTarget {
|
||||
rf := resmap.NewFactory(resFact, transformer.NewFactoryImpl())
|
||||
pc := konfig.DisabledPluginConfig()
|
||||
ldr, err := fLdr.NewLoader(fLdr.RestrictionRootOnly, root, fSys)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
kt := target.NewKustTarget(
|
||||
ldr,
|
||||
valtest_test.MakeFakeValidator(),
|
||||
rf,
|
||||
transformer.NewFactoryImpl(),
|
||||
pLdr.NewLoader(pc, rf))
|
||||
if err = kt.Load(); err != nil {
|
||||
t.Fatalf("Unexpected construction error %v", err)
|
||||
}
|
||||
return kt
|
||||
}
|
||||
@@ -1,188 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package target_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
// To simplify tests, these vars specified in alphabetical order.
|
||||
var someVars = []types.Var{
|
||||
{
|
||||
Name: "AWARD",
|
||||
ObjRef: types.Target{
|
||||
APIVersion: "v7",
|
||||
Gvk: resid.Gvk{Kind: "Service"},
|
||||
Name: "nobelPrize"},
|
||||
FieldRef: types.FieldSelector{FieldPath: "some.arbitrary.path"},
|
||||
},
|
||||
{
|
||||
Name: "BIRD",
|
||||
ObjRef: types.Target{
|
||||
APIVersion: "v300",
|
||||
Gvk: resid.Gvk{Kind: "Service"},
|
||||
Name: "heron"},
|
||||
FieldRef: types.FieldSelector{FieldPath: "metadata.name"},
|
||||
},
|
||||
{
|
||||
Name: "FRUIT",
|
||||
ObjRef: types.Target{
|
||||
Gvk: resid.Gvk{Kind: "Service"},
|
||||
Name: "apple"},
|
||||
FieldRef: types.FieldSelector{FieldPath: "metadata.name"},
|
||||
},
|
||||
{
|
||||
Name: "VEGETABLE",
|
||||
ObjRef: types.Target{
|
||||
Gvk: resid.Gvk{Kind: "Leafy"},
|
||||
Name: "kale"},
|
||||
FieldRef: types.FieldSelector{FieldPath: "metadata.name"},
|
||||
},
|
||||
}
|
||||
|
||||
func TestGetAllVarsSimple(t *testing.T) {
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
th.WriteK("/app", `
|
||||
vars:
|
||||
- name: AWARD
|
||||
objref:
|
||||
kind: Service
|
||||
name: nobelPrize
|
||||
apiVersion: v7
|
||||
fieldref:
|
||||
fieldpath: some.arbitrary.path
|
||||
- name: BIRD
|
||||
objref:
|
||||
kind: Service
|
||||
name: heron
|
||||
apiVersion: v300
|
||||
`)
|
||||
ra, err := makeKustTarget(
|
||||
t, th.GetFSys(), "/app").AccumulateTarget()
|
||||
if err != nil {
|
||||
t.Fatalf("Err: %v", err)
|
||||
}
|
||||
vars := ra.Vars()
|
||||
if len(vars) != 2 {
|
||||
t.Fatalf("unexpected size %d", len(vars))
|
||||
}
|
||||
for i := range vars[:2] {
|
||||
// By using Var.DeepEqual, we are protecting the code
|
||||
// from a potential invocation of vars[i].ObjRef.GVK()
|
||||
// during accumulateTarget
|
||||
if !vars[i].DeepEqual(someVars[i]) {
|
||||
t.Fatalf("unexpected var[%d]:\n %v\n %v", i, vars[i], someVars[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAllVarsNested(t *testing.T) {
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
th.WriteK("/app/base", `
|
||||
vars:
|
||||
- name: AWARD
|
||||
objref:
|
||||
kind: Service
|
||||
name: nobelPrize
|
||||
apiVersion: v7
|
||||
fieldref:
|
||||
fieldpath: some.arbitrary.path
|
||||
- name: BIRD
|
||||
objref:
|
||||
kind: Service
|
||||
name: heron
|
||||
apiVersion: v300
|
||||
`)
|
||||
th.WriteK("/app/overlays/o1", `
|
||||
vars:
|
||||
- name: FRUIT
|
||||
objref:
|
||||
kind: Service
|
||||
name: apple
|
||||
resources:
|
||||
- ../../base
|
||||
`)
|
||||
th.WriteK("/app/overlays/o2", `
|
||||
vars:
|
||||
- name: VEGETABLE
|
||||
objref:
|
||||
kind: Leafy
|
||||
name: kale
|
||||
resources:
|
||||
- ../o1
|
||||
`)
|
||||
|
||||
ra, err := makeKustTarget(
|
||||
t, th.GetFSys(), "/app/overlays/o2").AccumulateTarget()
|
||||
if err != nil {
|
||||
t.Fatalf("Err: %v", err)
|
||||
}
|
||||
vars := ra.Vars()
|
||||
if len(vars) != 4 {
|
||||
for i, v := range vars {
|
||||
fmt.Printf("%v: %v\n", i, v)
|
||||
}
|
||||
t.Fatalf("expected 4 vars, got %d", len(vars))
|
||||
}
|
||||
for i := range vars {
|
||||
// By using Var.DeepEqual, we are protecting the code
|
||||
// from a potential invocation of vars[i].ObjRef.GVK()
|
||||
// during accumulateTarget
|
||||
if !vars[i].DeepEqual(someVars[i]) {
|
||||
t.Fatalf("unexpected var[%d]:\n %v\n %v", i, vars[i], someVars[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestVarCollisionsForbidden(t *testing.T) {
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
th.WriteK("/app/base", `
|
||||
vars:
|
||||
- name: AWARD
|
||||
objref:
|
||||
kind: Service
|
||||
name: nobelPrize
|
||||
apiVersion: v7
|
||||
fieldref:
|
||||
fieldpath: some.arbitrary.path
|
||||
- name: BIRD
|
||||
objref:
|
||||
kind: Service
|
||||
name: heron
|
||||
apiVersion: v300
|
||||
`)
|
||||
th.WriteK("/app/overlays/o1", `
|
||||
vars:
|
||||
- name: AWARD
|
||||
objref:
|
||||
kind: Service
|
||||
name: academy
|
||||
resources:
|
||||
- ../../base
|
||||
`)
|
||||
th.WriteK("/app/overlays/o2", `
|
||||
vars:
|
||||
- name: VEGETABLE
|
||||
objref:
|
||||
kind: Leafy
|
||||
name: kale
|
||||
resources:
|
||||
- ../o1
|
||||
`)
|
||||
_, err := makeKustTarget(
|
||||
t, th.GetFSys(), "/app/overlays/o2").AccumulateTarget()
|
||||
if err == nil {
|
||||
t.Fatalf("expected var collision")
|
||||
}
|
||||
if !strings.Contains(err.Error(),
|
||||
"var 'AWARD' already encountered") {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
// +build tools
|
||||
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// This file exists to automatically trigger installs
|
||||
// of the given tools, and is the offical 'unofficial'
|
||||
// way to declare a dependence on a Go binary until
|
||||
// some better technique comes along.
|
||||
|
||||
package tools
|
||||
|
||||
import (
|
||||
// for code generation
|
||||
_ "golang.org/x/tools/cmd/stringer"
|
||||
// for lint checks
|
||||
_ "github.com/golangci/golangci-lint/cmd/golangci-lint"
|
||||
// REMOVED pluginator from this process, and leaving
|
||||
// this note to discourage its reintroduction,
|
||||
// because pluginator depends on the api, forcing
|
||||
// major version increments in pluginator with each
|
||||
// api release to allow this trick to work and not
|
||||
// introduce cycles.
|
||||
// _ "sigs.k8s.io/kustomize/pluginator/v2"
|
||||
)
|
||||
@@ -1,8 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package builtinpluginconsts provides builtin plugin
|
||||
// configuration data. Builtin plugins can also be
|
||||
// configured individually with plugin config files,
|
||||
// in which case the constants in this package are ignored.
|
||||
package builtinpluginconsts
|
||||
@@ -1,10 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package builtinpluginconsts
|
||||
|
||||
const (
|
||||
// imageFieldSpecs is left empty since `containers` and `initContainers`
|
||||
// of *ANY* kind in *ANY* path are builtin supported in code
|
||||
imagesFieldSpecs = ``
|
||||
)
|
||||
@@ -1,11 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package builtinpluginconsts
|
||||
|
||||
const (
|
||||
namePrefixFieldSpecs = `
|
||||
namePrefix:
|
||||
- path: metadata/name
|
||||
`
|
||||
)
|
||||
@@ -1,16 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package builtinpluginconsts
|
||||
|
||||
const (
|
||||
namespaceFieldSpecs = `
|
||||
namespace:
|
||||
- path: metadata/namespace
|
||||
create: true
|
||||
- path: subjects
|
||||
kind: RoleBinding
|
||||
- path: subjects
|
||||
kind: ClusterRoleBinding
|
||||
`
|
||||
)
|
||||
@@ -1,6 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package konfig provides configuration methods and constants
|
||||
// for the kustomize API.
|
||||
package konfig
|
||||
@@ -1,150 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package konfig
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/filesys"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
const (
|
||||
// Symbol that must be used inside Go plugins.
|
||||
PluginSymbol = "KustomizePlugin"
|
||||
|
||||
// Name of environment variable used to set AbsPluginHome.
|
||||
// See that variable for an explanation.
|
||||
KustomizePluginHomeEnv = "KUSTOMIZE_PLUGIN_HOME"
|
||||
|
||||
// Relative path below XDG_CONFIG_HOME/kustomize to find plugins.
|
||||
// e.g. AbsPluginHome = XDG_CONFIG_HOME/kustomize/plugin
|
||||
RelPluginHome = "plugin"
|
||||
|
||||
// Location of builtin plugins below AbsPluginHome.
|
||||
BuiltinPluginPackage = "builtin"
|
||||
|
||||
// The value of kubernetes ApiVersion to use in configuration
|
||||
// files for builtin plugins.
|
||||
// The value for non-builtins can be anything.
|
||||
BuiltinPluginApiVersion = BuiltinPluginPackage
|
||||
|
||||
// Domain from which kustomize code is imported, for locating
|
||||
// plugin source code under $GOPATH when GOPATH is defined.
|
||||
DomainName = "sigs.k8s.io"
|
||||
)
|
||||
|
||||
func EnabledPluginConfig() (*types.PluginConfig, error) {
|
||||
dir, err := DefaultAbsPluginHome(filesys.MakeFsOnDisk())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return MakePluginConfig(types.PluginRestrictionsNone, dir), nil
|
||||
}
|
||||
|
||||
func DisabledPluginConfig() *types.PluginConfig {
|
||||
return MakePluginConfig(
|
||||
types.PluginRestrictionsBuiltinsOnly, NoPluginHomeSentinal)
|
||||
}
|
||||
|
||||
func MakePluginConfig(
|
||||
pr types.PluginRestrictions, home string) *types.PluginConfig {
|
||||
return &types.PluginConfig{
|
||||
PluginRestrictions: pr,
|
||||
AbsPluginHome: home,
|
||||
}
|
||||
}
|
||||
|
||||
// Use an obviously erroneous path, in case it's accidentally used.
|
||||
const NoPluginHomeSentinal = "/no/non-builtin/plugins!"
|
||||
|
||||
type NotedFunc struct {
|
||||
Note string
|
||||
F func() string
|
||||
}
|
||||
|
||||
func DefaultAbsPluginHome(fSys filesys.FileSystem) (string, error) {
|
||||
return FirstDirThatExistsElseError(
|
||||
"plugin home directory", fSys, []NotedFunc{
|
||||
{
|
||||
Note: "homed in $" + KustomizePluginHomeEnv,
|
||||
F: func() string {
|
||||
return os.Getenv(KustomizePluginHomeEnv)
|
||||
},
|
||||
},
|
||||
{
|
||||
Note: "homed in $" + XdgConfigHomeEnv,
|
||||
F: func() string {
|
||||
return filepath.Join(
|
||||
os.Getenv(XdgConfigHomeEnv),
|
||||
ProgramName, RelPluginHome)
|
||||
},
|
||||
},
|
||||
{
|
||||
Note: "homed in default value of $" + XdgConfigHomeEnv,
|
||||
F: func() string {
|
||||
return filepath.Join(
|
||||
HomeDir(), XdgConfigHomeEnvDefault,
|
||||
ProgramName, RelPluginHome)
|
||||
},
|
||||
},
|
||||
{
|
||||
Note: "homed in home directory",
|
||||
F: func() string {
|
||||
return filepath.Join(
|
||||
HomeDir(), ProgramName, RelPluginHome)
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// FirstDirThatExistsElseError tests different path functions for
|
||||
// existence, returning the first that works, else error if all fail.
|
||||
func FirstDirThatExistsElseError(
|
||||
what string,
|
||||
fSys filesys.FileSystem,
|
||||
pathFuncs []NotedFunc) (string, error) {
|
||||
var nope []types.Pair
|
||||
for _, dt := range pathFuncs {
|
||||
dir := dt.F()
|
||||
if fSys.Exists(dir) {
|
||||
return dir, nil
|
||||
}
|
||||
nope = append(nope, types.Pair{Key: dt.Note, Value: dir})
|
||||
}
|
||||
return "", types.NewErrUnableToFind(what, nope)
|
||||
}
|
||||
|
||||
func HomeDir() string {
|
||||
home := os.Getenv(homeEnv())
|
||||
if len(home) > 0 {
|
||||
return home
|
||||
}
|
||||
return "~"
|
||||
}
|
||||
|
||||
func homeEnv() string {
|
||||
if runtime.GOOS == "windows" {
|
||||
return "USERPROFILE"
|
||||
}
|
||||
return "HOME"
|
||||
}
|
||||
|
||||
func CurrentWorkingDir() string {
|
||||
// Try for full path first to be explicit.
|
||||
pwd := os.Getenv(pwdEnv())
|
||||
if len(pwd) > 0 {
|
||||
return pwd
|
||||
}
|
||||
return filesys.SelfDir
|
||||
}
|
||||
|
||||
func pwdEnv() string {
|
||||
if runtime.GOOS == "windows" {
|
||||
return "CD"
|
||||
}
|
||||
return "PWD"
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package konfig
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/filesys"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
func TestDefaultAbsPluginHome_NoKustomizePluginHomeEnv(t *testing.T) {
|
||||
fSys := filesys.MakeFsInMemory()
|
||||
keep, isSet := os.LookupEnv(KustomizePluginHomeEnv)
|
||||
if isSet {
|
||||
_ = os.Unsetenv(KustomizePluginHomeEnv)
|
||||
}
|
||||
_, err := DefaultAbsPluginHome(fSys)
|
||||
if isSet {
|
||||
os.Setenv(KustomizePluginHomeEnv, keep)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatalf("expected err")
|
||||
}
|
||||
if !types.IsErrUnableToFind(err) {
|
||||
t.Fatalf("unexpected err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultAbsPluginHome_WithKustomizePluginHomeEnv(t *testing.T) {
|
||||
fSys := filesys.MakeFsInMemory()
|
||||
keep, isSet := os.LookupEnv(KustomizePluginHomeEnv)
|
||||
if !isSet {
|
||||
keep = "whatever"
|
||||
os.Setenv(KustomizePluginHomeEnv, keep)
|
||||
}
|
||||
fSys.Mkdir(keep)
|
||||
h, err := DefaultAbsPluginHome(fSys)
|
||||
if !isSet {
|
||||
_ = os.Unsetenv(KustomizePluginHomeEnv)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected err: %v", err)
|
||||
}
|
||||
if h != keep {
|
||||
t.Fatalf("unexpected config dir: %s", h)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultAbsPluginHomeWithXdg(t *testing.T) {
|
||||
fSys := filesys.MakeFsInMemory()
|
||||
keep, isSet := os.LookupEnv(XdgConfigHomeEnv)
|
||||
if !isSet {
|
||||
keep = "whatever"
|
||||
os.Setenv(XdgConfigHomeEnv, keep)
|
||||
}
|
||||
configDir := filepath.Join(keep, ProgramName, RelPluginHome)
|
||||
fSys.Mkdir(configDir)
|
||||
h, err := DefaultAbsPluginHome(fSys)
|
||||
if !isSet {
|
||||
_ = os.Unsetenv(XdgConfigHomeEnv)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected err: %v", err)
|
||||
}
|
||||
if h != configDir {
|
||||
t.Fatalf("unexpected config dir: %s", h)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultAbsPluginHomeNoConfig(t *testing.T) {
|
||||
fSys := filesys.MakeFsInMemory()
|
||||
keep, isSet := os.LookupEnv(XdgConfigHomeEnv)
|
||||
if isSet {
|
||||
_ = os.Unsetenv(XdgConfigHomeEnv)
|
||||
}
|
||||
_, err := DefaultAbsPluginHome(fSys)
|
||||
if isSet {
|
||||
os.Setenv(XdgConfigHomeEnv, keep)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatalf("expected err")
|
||||
}
|
||||
if !types.IsErrUnableToFind(err) {
|
||||
t.Fatalf("unexpected err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultAbsPluginHomeNoXdgWithDotConfig(t *testing.T) {
|
||||
fSys := filesys.MakeFsInMemory()
|
||||
configDir := filepath.Join(
|
||||
HomeDir(), XdgConfigHomeEnvDefault, ProgramName, RelPluginHome)
|
||||
fSys.Mkdir(configDir)
|
||||
keep, isSet := os.LookupEnv(XdgConfigHomeEnv)
|
||||
if isSet {
|
||||
_ = os.Unsetenv(XdgConfigHomeEnv)
|
||||
}
|
||||
s, _ := DefaultAbsPluginHome(fSys)
|
||||
if isSet {
|
||||
os.Setenv(XdgConfigHomeEnv, keep)
|
||||
}
|
||||
if s != configDir {
|
||||
t.Fatalf("unexpected config dir: %s", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultAbsPluginHomeNoXdgJustHomeDir(t *testing.T) {
|
||||
fSys := filesys.MakeFsInMemory()
|
||||
configDir := filepath.Join(
|
||||
HomeDir(), ProgramName, RelPluginHome)
|
||||
fSys.Mkdir(configDir)
|
||||
keep, isSet := os.LookupEnv(XdgConfigHomeEnv)
|
||||
if isSet {
|
||||
_ = os.Unsetenv(XdgConfigHomeEnv)
|
||||
}
|
||||
s, _ := DefaultAbsPluginHome(fSys)
|
||||
if isSet {
|
||||
os.Setenv(XdgConfigHomeEnv, keep)
|
||||
}
|
||||
if s != configDir {
|
||||
t.Fatalf("unexpected config dir: %s", s)
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package krusty_test
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
. "sigs.k8s.io/kustomize/api/internal/target"
|
||||
"sigs.k8s.io/kustomize/api/konfig"
|
||||
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
|
||||
)
|
||||
|
||||
func TestTargetMustHaveKustomizationFile(t *testing.T) {
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
th.WriteF("/app/service.yaml", `
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: aService
|
||||
`)
|
||||
th.WriteF("/app/deeper/service.yaml", `
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: anotherService
|
||||
`)
|
||||
err := th.RunWithErr("/app", th.MakeDefaultOptions())
|
||||
if err == nil {
|
||||
t.Fatalf("expected an error")
|
||||
}
|
||||
if !IsMissingKustomizationFileError(err) {
|
||||
t.Fatalf("unexpected error: %q", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTargetMustHaveOnlyOneKustomizationFile(t *testing.T) {
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
for _, n := range konfig.RecognizedKustomizationFileNames() {
|
||||
th.WriteF(filepath.Join("/app", n), `
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
`)
|
||||
}
|
||||
err := th.RunWithErr("/app", th.MakeDefaultOptions())
|
||||
if err == nil {
|
||||
t.Fatalf("expected an error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "Found multiple kustomization files under: /app") {
|
||||
t.Fatalf("unexpected error: %q", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBaseMustHaveKustomizationFile(t *testing.T) {
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
th.WriteK("/app", `
|
||||
resources:
|
||||
- base
|
||||
`)
|
||||
th.WriteF("/app/base/service.yaml", `
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: myService
|
||||
spec:
|
||||
selector:
|
||||
backend: bungie
|
||||
ports:
|
||||
- port: 7002
|
||||
`)
|
||||
err := th.RunWithErr("/app", th.MakeDefaultOptions())
|
||||
if err == nil {
|
||||
t.Fatalf("expected an error")
|
||||
}
|
||||
if !IsMissingKustomizationFileError(err) {
|
||||
t.Fatalf("unexpected error: %q", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResourceNotFound(t *testing.T) {
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
th.WriteK("/app", `
|
||||
resources:
|
||||
- deployment.yaml
|
||||
`)
|
||||
err := th.RunWithErr("/app", th.MakeDefaultOptions())
|
||||
if err == nil {
|
||||
t.Fatalf("expected an error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "'/app/deployment.yaml' doesn't exist") {
|
||||
t.Fatalf("unexpected error: %q", err)
|
||||
}
|
||||
}
|
||||
@@ -1,555 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package krusty_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
. "sigs.k8s.io/kustomize/api/krusty"
|
||||
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
const httpsService = `
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: my-https-svc
|
||||
spec:
|
||||
ports:
|
||||
- port: 443
|
||||
protocol: TCP
|
||||
name: https
|
||||
selector:
|
||||
app: my-app
|
||||
`
|
||||
|
||||
func writeStatefulSetBase(th kusttest_test.Harness) {
|
||||
th.WriteK("/app/base", `
|
||||
resources:
|
||||
- statefulset.yaml
|
||||
`)
|
||||
th.WriteF("/app/base/statefulset.yaml", `
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: my-sts
|
||||
spec:
|
||||
serviceName: my-svc
|
||||
selector:
|
||||
matchLabels:
|
||||
app: my-app
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: my-app
|
||||
spec:
|
||||
containers:
|
||||
- name: app
|
||||
image: my-image
|
||||
volumeClaimTemplates:
|
||||
- spec:
|
||||
storageClassName: default
|
||||
`)
|
||||
}
|
||||
|
||||
func writeHTTPSOverlay(th kusttest_test.Harness) {
|
||||
th.WriteK("/app/https", `
|
||||
resources:
|
||||
- ../base
|
||||
- https-svc.yaml
|
||||
patchesStrategicMerge:
|
||||
- sts-patch.yaml
|
||||
`)
|
||||
th.WriteF("/app/https/https-svc.yaml", httpsService)
|
||||
th.WriteF("/app/https/sts-patch.yaml", `
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: my-sts
|
||||
spec:
|
||||
serviceName: my-https-svc
|
||||
`)
|
||||
}
|
||||
|
||||
func writeHTTPSTransformerRaw(th kusttest_test.Harness) {
|
||||
th.WriteF("/app/https/service/https-svc.yaml", httpsService)
|
||||
th.WriteF("/app/https/transformer/transformer.yaml", `
|
||||
apiVersion: builtin
|
||||
kind: PatchTransformer
|
||||
metadata:
|
||||
name: svcNameTran
|
||||
target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: StatefulSet
|
||||
name: my-sts
|
||||
patch: |-
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: my-sts
|
||||
spec:
|
||||
serviceName: my-https-svc
|
||||
`)
|
||||
}
|
||||
|
||||
func writeHTTPSTransformerBase(th kusttest_test.Harness) {
|
||||
th.WriteK("/app/https/service", `
|
||||
resources:
|
||||
- https-svc.yaml
|
||||
`)
|
||||
th.WriteK("/app/https/transformer", `
|
||||
resources:
|
||||
- transformer.yaml
|
||||
`)
|
||||
writeHTTPSTransformerRaw(th)
|
||||
}
|
||||
|
||||
func writeConfigFromEnvOverlay(th kusttest_test.Harness) {
|
||||
th.WriteK("/app/config", `
|
||||
resources:
|
||||
- ../base
|
||||
configMapGenerator:
|
||||
- name: my-config
|
||||
literals:
|
||||
- MY_ENV=foo
|
||||
generatorOptions:
|
||||
disableNameSuffixHash: true
|
||||
patchesStrategicMerge:
|
||||
- sts-patch.yaml
|
||||
`)
|
||||
th.WriteF("/app/config/sts-patch.yaml", `
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: my-sts
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: app
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: my-config
|
||||
`)
|
||||
}
|
||||
|
||||
func writeConfigFromEnvTransformerRaw(th kusttest_test.Harness) {
|
||||
th.WriteF("/app/config/map/generator.yaml", `
|
||||
apiVersion: builtin
|
||||
kind: ConfigMapGenerator
|
||||
metadata:
|
||||
name: my-config
|
||||
disableNameSuffixHash: true
|
||||
literals:
|
||||
- MY_ENV=foo
|
||||
`)
|
||||
th.WriteF("/app/config/transformer/transformer.yaml", `
|
||||
apiVersion: builtin
|
||||
kind: PatchTransformer
|
||||
metadata:
|
||||
name: envFromConfigTrans
|
||||
target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: StatefulSet
|
||||
name: my-sts
|
||||
patch: |-
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: my-sts
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: app
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: my-config
|
||||
`)
|
||||
}
|
||||
func writeConfigFromEnvTransformerBase(th kusttest_test.Harness) {
|
||||
th.WriteK("/app/config/map", `
|
||||
resources:
|
||||
- generator.yaml
|
||||
`)
|
||||
th.WriteK("/app/config/transformer", `
|
||||
resources:
|
||||
- transformer.yaml
|
||||
`)
|
||||
writeConfigFromEnvTransformerRaw(th)
|
||||
}
|
||||
|
||||
func writeTolerationsOverlay(th kusttest_test.Harness) {
|
||||
th.WriteK("/app/tolerations", `
|
||||
resources:
|
||||
- ../base
|
||||
patchesStrategicMerge:
|
||||
- sts-patch.yaml
|
||||
`)
|
||||
th.WriteF("/app/tolerations/sts-patch.yaml", `
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: my-sts
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
tolerations:
|
||||
- effect: NoExecute
|
||||
key: node.kubernetes.io/not-ready
|
||||
tolerationSeconds: 30
|
||||
`)
|
||||
}
|
||||
|
||||
func writeTolerationsTransformerRaw(th kusttest_test.Harness) {
|
||||
th.WriteF("/app/tolerations/transformer.yaml", `
|
||||
apiVersion: builtin
|
||||
kind: PatchTransformer
|
||||
metadata:
|
||||
name: tolTrans
|
||||
target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: StatefulSet
|
||||
name: my-sts
|
||||
patch: |-
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: my-sts
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
tolerations:
|
||||
- effect: NoExecute
|
||||
key: node.kubernetes.io/not-ready
|
||||
tolerationSeconds: 30
|
||||
`)
|
||||
}
|
||||
|
||||
func writeTolerationsTransformerBase(th kusttest_test.Harness) {
|
||||
th.WriteK("/app/tolerations", `
|
||||
resources:
|
||||
- transformer.yaml
|
||||
`)
|
||||
writeTolerationsTransformerRaw(th)
|
||||
}
|
||||
|
||||
func writeStorageOverlay(th kusttest_test.Harness) {
|
||||
th.WriteK("/app/storage", `
|
||||
resources:
|
||||
- ../base
|
||||
patchesJson6902:
|
||||
- target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: StatefulSet
|
||||
name: my-sts
|
||||
path: sts-patch.json
|
||||
`)
|
||||
th.WriteF("/app/storage/sts-patch.json", `
|
||||
[{"op": "replace", "path": "/spec/volumeClaimTemplates/0/spec/storageClassName", "value": "my-sc"}]
|
||||
`)
|
||||
}
|
||||
|
||||
func writeStorageTransformerRaw(th kusttest_test.Harness) {
|
||||
th.WriteF("/app/storage/transformer.yaml", `
|
||||
apiVersion: builtin
|
||||
kind: PatchTransformer
|
||||
metadata:
|
||||
name: storageTrans
|
||||
target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: StatefulSet
|
||||
name: my-sts
|
||||
patch: |-
|
||||
[{"op": "replace", "path": "/spec/volumeClaimTemplates/0/spec/storageClassName", "value": "my-sc"}]
|
||||
`)
|
||||
}
|
||||
|
||||
func writeStorageTransformerBase(th kusttest_test.Harness) {
|
||||
th.WriteK("/app/storage", `
|
||||
resources:
|
||||
- transformer.yaml
|
||||
`)
|
||||
writeStorageTransformerRaw(th)
|
||||
}
|
||||
|
||||
func writePatchingOverlays(th kusttest_test.Harness) {
|
||||
writeStorageOverlay(th)
|
||||
writeConfigFromEnvOverlay(th)
|
||||
writeTolerationsOverlay(th)
|
||||
writeHTTPSOverlay(th)
|
||||
}
|
||||
|
||||
func writePatchingTransformersRaw(th kusttest_test.Harness) {
|
||||
writeStorageTransformerRaw(th)
|
||||
writeConfigFromEnvTransformerRaw(th)
|
||||
writeTolerationsTransformerRaw(th)
|
||||
writeHTTPSTransformerRaw(th)
|
||||
}
|
||||
|
||||
// Similar to writePatchingTransformersRaw, except here the
|
||||
// transformers and related artifacts are addressable as _bases_.
|
||||
// They are listed in a kustomization file, and consumers of
|
||||
// the plugin refer to the kustomization instead of to the local
|
||||
// file in the "transformers:" field.
|
||||
//
|
||||
// Using bases makes the set of files relocatable with
|
||||
// respect to the overlays, and avoids the need to relax load
|
||||
// restrictions on file paths reaching outside the `dev` and
|
||||
// `prod` kustomization roots. I.e. with bases tests can use
|
||||
// NewKustTestHarness instead of NewKustTestHarnessNoLoadRestrictor.
|
||||
//
|
||||
// Using transformer plugins from _bases_ means the plugin config
|
||||
// must be self-contained, i.e. the config may not have fields that
|
||||
// refer to local files, since those files won't be present when
|
||||
// the plugin is instantiated and used.
|
||||
func writePatchingTransformerBases(th kusttest_test.Harness) {
|
||||
writeStorageTransformerBase(th)
|
||||
writeConfigFromEnvTransformerBase(th)
|
||||
writeTolerationsTransformerBase(th)
|
||||
writeHTTPSTransformerBase(th)
|
||||
}
|
||||
|
||||
// Here's a complex kustomization scenario that combines multiple overlays
|
||||
// on a common base:
|
||||
//
|
||||
// dev prod
|
||||
// | |
|
||||
// | |
|
||||
// + ------- + + ------------ + ------------- +
|
||||
// | | | | |
|
||||
// | | | | |
|
||||
// v | v v v
|
||||
// storage + -----> config tolerations https
|
||||
// | | | |
|
||||
// | | | |
|
||||
// | + --- + + --- + |
|
||||
// | | | |
|
||||
// | v v |
|
||||
// + -----------------------> base <------------------ +
|
||||
//
|
||||
// The base resource is a statefulset. Each intermediate overlay manages or
|
||||
// generates new resources and patches different aspects of the same base
|
||||
// resource, without using any of the `namePrefix`, `nameSuffix` or `namespace`
|
||||
// kustomization keywords.
|
||||
//
|
||||
// Intermediate overlays:
|
||||
// - storage: Changes the storage class of the stateful set with a JSON patch.
|
||||
// - config: Generates a config map and adds a field as an environment
|
||||
// variable.
|
||||
// - tolerations: Adds a new tolerations field in the spec.
|
||||
// - https: Adds a new service resource and changes the service name in the
|
||||
// stateful set.
|
||||
//
|
||||
// Top overlays:
|
||||
// - dev: Combines the storage and config intermediate overlays.
|
||||
// - prod: Combines the config, tolerations and https intermediate overlays.
|
||||
|
||||
func TestComplexComposition_Dev_Failure(t *testing.T) {
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
writeStatefulSetBase(th)
|
||||
writePatchingOverlays(th)
|
||||
th.WriteK("/app/dev", `
|
||||
resources:
|
||||
- ../storage
|
||||
- ../config
|
||||
`)
|
||||
err := th.RunWithErr("/app/dev", th.MakeDefaultOptions())
|
||||
if err == nil {
|
||||
t.Fatalf("Expected resource accumulation error")
|
||||
}
|
||||
if !strings.Contains(
|
||||
err.Error(), "already registered id: apps_v1_StatefulSet|~X|my-sts") {
|
||||
t.Fatalf("Unexpected err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
const devDesiredResult = `
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: my-sts
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: my-app
|
||||
serviceName: my-svc
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: my-app
|
||||
spec:
|
||||
containers:
|
||||
- envFrom:
|
||||
- configMapRef:
|
||||
name: my-config
|
||||
image: my-image
|
||||
name: app
|
||||
volumeClaimTemplates:
|
||||
- spec:
|
||||
storageClassName: my-sc
|
||||
---
|
||||
apiVersion: v1
|
||||
data:
|
||||
MY_ENV: foo
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: my-config
|
||||
`
|
||||
|
||||
func TestComplexComposition_Dev_SuccessWithRawTransformers(t *testing.T) {
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
writeStatefulSetBase(th)
|
||||
writePatchingTransformersRaw(th)
|
||||
th.WriteK("/app/dev", `
|
||||
resources:
|
||||
- ../base
|
||||
generators:
|
||||
- ../config/map/generator.yaml
|
||||
transformers:
|
||||
- ../config/transformer/transformer.yaml
|
||||
- ../storage/transformer.yaml
|
||||
`)
|
||||
m := th.Run("/app/dev", func() Options {
|
||||
o := th.MakeDefaultOptions()
|
||||
o.LoadRestrictions = types.LoadRestrictionsNone
|
||||
return o
|
||||
}())
|
||||
th.AssertActualEqualsExpected(m, devDesiredResult)
|
||||
}
|
||||
|
||||
func TestComplexComposition_Dev_SuccessWithBaseTransformers(t *testing.T) {
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
writeStatefulSetBase(th)
|
||||
writePatchingTransformerBases(th)
|
||||
th.WriteK("/app/dev", `
|
||||
resources:
|
||||
- ../base
|
||||
generators:
|
||||
- ../config/map
|
||||
transformers:
|
||||
- ../config/transformer
|
||||
- ../storage
|
||||
`)
|
||||
m := th.Run("/app/dev", th.MakeDefaultOptions())
|
||||
th.AssertActualEqualsExpected(m, devDesiredResult)
|
||||
}
|
||||
|
||||
func TestComplexComposition_Prod_Failure(t *testing.T) {
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
writeStatefulSetBase(th)
|
||||
writePatchingOverlays(th)
|
||||
th.WriteK("/app/prod", `
|
||||
resources:
|
||||
- ../config
|
||||
- ../tolerations
|
||||
- ../https
|
||||
`)
|
||||
err := th.RunWithErr("/app/prod", th.MakeDefaultOptions())
|
||||
if err == nil {
|
||||
t.Fatalf("Expected resource accumulation error")
|
||||
}
|
||||
if !strings.Contains(
|
||||
err.Error(), "already registered id: apps_v1_StatefulSet|~X|my-sts") {
|
||||
t.Fatalf("Unexpected err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
const prodDesiredResult = `
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: my-sts
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: my-app
|
||||
serviceName: my-https-svc
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: my-app
|
||||
spec:
|
||||
containers:
|
||||
- envFrom:
|
||||
- configMapRef:
|
||||
name: my-config
|
||||
image: my-image
|
||||
name: app
|
||||
tolerations:
|
||||
- effect: NoExecute
|
||||
key: node.kubernetes.io/not-ready
|
||||
tolerationSeconds: 30
|
||||
volumeClaimTemplates:
|
||||
- spec:
|
||||
storageClassName: default
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: my-https-svc
|
||||
spec:
|
||||
ports:
|
||||
- name: https
|
||||
port: 443
|
||||
protocol: TCP
|
||||
selector:
|
||||
app: my-app
|
||||
---
|
||||
apiVersion: v1
|
||||
data:
|
||||
MY_ENV: foo
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: my-config
|
||||
`
|
||||
|
||||
func TestComplexComposition_Prod_SuccessWithRawTransformers(t *testing.T) {
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
writeStatefulSetBase(th)
|
||||
writePatchingTransformersRaw(th)
|
||||
th.WriteK("/app/prod", `
|
||||
resources:
|
||||
- ../base
|
||||
- ../https/service/https-svc.yaml
|
||||
generators:
|
||||
- ../config/map/generator.yaml
|
||||
transformers:
|
||||
- ../config/transformer/transformer.yaml
|
||||
- ../https/transformer/transformer.yaml
|
||||
- ../tolerations/transformer.yaml
|
||||
`)
|
||||
m := th.Run("/app/prod", func() Options {
|
||||
o := th.MakeDefaultOptions()
|
||||
o.LoadRestrictions = types.LoadRestrictionsNone
|
||||
return o
|
||||
}())
|
||||
th.AssertActualEqualsExpected(m, prodDesiredResult)
|
||||
}
|
||||
|
||||
func TestComplexComposition_Prod_SuccessWithBaseTransformers(t *testing.T) {
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
writeStatefulSetBase(th)
|
||||
writePatchingTransformerBases(th)
|
||||
th.WriteK("/app/prod", `
|
||||
resources:
|
||||
- ../base
|
||||
- ../https/service
|
||||
generators:
|
||||
- ../config/map
|
||||
transformers:
|
||||
- ../config/transformer
|
||||
- ../https/transformer
|
||||
- ../tolerations
|
||||
`)
|
||||
m := th.Run("/app/prod", th.MakeDefaultOptions())
|
||||
th.AssertActualEqualsExpected(m, prodDesiredResult)
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package krusty_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
|
||||
)
|
||||
|
||||
// Demo custom configuration of a builtin transformation.
|
||||
// This is a NamePrefixer that touches Deployments
|
||||
// and Services exclusively.
|
||||
func TestCustomNamePrefixer(t *testing.T) {
|
||||
th := kusttest_test.MakeEnhancedHarness(t).
|
||||
PrepBuiltin("PrefixSuffixTransformer")
|
||||
defer th.Reset()
|
||||
|
||||
th.WriteK("/app", `
|
||||
resources:
|
||||
- deployment.yaml
|
||||
- role.yaml
|
||||
- service.yaml
|
||||
transformers:
|
||||
- prefixer.yaml
|
||||
`)
|
||||
th.WriteF("/app/prefixer.yaml", `
|
||||
apiVersion: builtin
|
||||
kind: PrefixSuffixTransformer
|
||||
metadata:
|
||||
name: customPrefixer
|
||||
prefix: zzz-
|
||||
fieldSpecs:
|
||||
- kind: Deployment
|
||||
path: metadata/name
|
||||
- kind: Service
|
||||
path: metadata/name
|
||||
`)
|
||||
th.WriteF("/app/deployment.yaml", `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: myDeployment
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
backend: awesome
|
||||
spec:
|
||||
containers:
|
||||
- name: whatever
|
||||
image: whatever
|
||||
`)
|
||||
th.WriteF("/app/role.yaml", `
|
||||
apiVersion: v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: myRole
|
||||
`)
|
||||
th.WriteF("/app/service.yaml", `
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: myService
|
||||
`)
|
||||
|
||||
m := th.Run("/app", th.MakeDefaultOptions())
|
||||
th.AssertActualEqualsExpected(m, `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: zzz-myDeployment
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
backend: awesome
|
||||
spec:
|
||||
containers:
|
||||
- image: whatever
|
||||
name: whatever
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: myRole
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: zzz-myService
|
||||
`)
|
||||
}
|
||||
@@ -1,177 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package krusty_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
|
||||
)
|
||||
|
||||
// Demo custom configuration as a base.
|
||||
// This test shows usage of three custom configurations sitting
|
||||
// in a base, allowing them to be reused in any number of
|
||||
// kustomizations.
|
||||
func TestReusableCustomTransformers(t *testing.T) {
|
||||
th := kusttest_test.MakeEnhancedHarness(t).
|
||||
PrepBuiltin("PrefixSuffixTransformer").
|
||||
PrepBuiltin("AnnotationsTransformer").
|
||||
PrepBuiltin("LabelTransformer")
|
||||
defer th.Reset()
|
||||
|
||||
// First write three custom configurations for builtin plugins.
|
||||
|
||||
// A custom name prefixer that only touches Deployments and Services.
|
||||
th.WriteF("/app/mytransformers/deploymentServicePrefixer.yaml", `
|
||||
apiVersion: builtin
|
||||
kind: PrefixSuffixTransformer
|
||||
metadata:
|
||||
name: myPrefixer
|
||||
prefix: bob-
|
||||
fieldSpecs:
|
||||
- kind: Deployment
|
||||
path: metadata/name
|
||||
- kind: Service
|
||||
path: metadata/name
|
||||
`)
|
||||
|
||||
// A custom annotator exclusively annotating Roles.
|
||||
th.WriteF("/app/mytransformers/roleAnnotator.yaml", `
|
||||
apiVersion: builtin
|
||||
kind: AnnotationsTransformer
|
||||
metadata:
|
||||
name: myAnnotator
|
||||
annotations:
|
||||
# Imagine that SRE has not approved this role yet.
|
||||
status: probationary
|
||||
fieldSpecs:
|
||||
- path: metadata/annotations
|
||||
create: true
|
||||
kind: Role
|
||||
`)
|
||||
|
||||
// A custom labeller that only labels Deployments,
|
||||
// and only labels them at their top metadata level
|
||||
// exclusively. It does not modify selectors or
|
||||
// add labels to pods in the template.
|
||||
th.WriteF("/app/mytransformers/deploymentLabeller.yaml", `
|
||||
apiVersion: builtin
|
||||
kind: LabelTransformer
|
||||
metadata:
|
||||
name: myLabeller
|
||||
labels:
|
||||
pager: 867-5301
|
||||
fieldSpecs:
|
||||
- path: metadata/labels
|
||||
create: true
|
||||
kind: Deployment
|
||||
`)
|
||||
|
||||
// Combine these custom transformers in one kustomization file.
|
||||
// This kustomization file contains only resources that
|
||||
// all happen to be plugin configurations. This makes
|
||||
// these plugins re-usable as a group in any number of other
|
||||
// kustomizations.
|
||||
th.WriteK("/app/mytransformers", `
|
||||
resources:
|
||||
- deploymentServicePrefixer.yaml
|
||||
- roleAnnotator.yaml
|
||||
- deploymentLabeller.yaml
|
||||
`)
|
||||
|
||||
// Finally, define the kustomization for the (arbitrarily named)
|
||||
// staging environment.
|
||||
th.WriteK("/app/staging", `
|
||||
|
||||
# Bring in the custom transformers.
|
||||
transformers:
|
||||
- ../mytransformers
|
||||
|
||||
# Also use the "classic" labeller, which behind the scenes uses
|
||||
# the LabelTransformer, but with a broad configuration targeting
|
||||
# many resources and fields (including selector fields).
|
||||
# It's a big hammer - probably too big; the output shows all the
|
||||
# places 'acmeCorp' now appears as a result. To avoid this,
|
||||
# define your own config for your own LabelTransformer instance
|
||||
# as shown above.
|
||||
commonLabels:
|
||||
company: acmeCorp
|
||||
|
||||
# Specify the resources to modify.
|
||||
resources:
|
||||
- deployment.yaml
|
||||
- role.yaml
|
||||
- service.yaml
|
||||
`)
|
||||
th.WriteF("/app/staging/deployment.yaml", `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: myDeployment
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
backend: flawless
|
||||
spec:
|
||||
containers:
|
||||
- name: whatever
|
||||
image: whatever
|
||||
`)
|
||||
th.WriteF("/app/staging/role.yaml", `
|
||||
apiVersion: v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: myRole
|
||||
`)
|
||||
th.WriteF("/app/staging/service.yaml", `
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: myService
|
||||
`)
|
||||
|
||||
m := th.Run("/app/staging", th.MakeDefaultOptions())
|
||||
th.AssertActualEqualsExpected(m, `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
company: acmeCorp
|
||||
pager: 867-5301
|
||||
name: bob-myDeployment
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
company: acmeCorp
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
backend: flawless
|
||||
company: acmeCorp
|
||||
spec:
|
||||
containers:
|
||||
- image: whatever
|
||||
name: whatever
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Role
|
||||
metadata:
|
||||
annotations:
|
||||
status: probationary
|
||||
labels:
|
||||
company: acmeCorp
|
||||
name: myRole
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
company: acmeCorp
|
||||
name: bob-myService
|
||||
spec:
|
||||
selector:
|
||||
company: acmeCorp
|
||||
`)
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package krusty_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
|
||||
)
|
||||
|
||||
func TestIssue596AllowDirectoriesThatAreSubstringsOfEachOther(t *testing.T) {
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
th.WriteK("/app/base", "")
|
||||
th.WriteK("/app/overlays/aws", `
|
||||
resources:
|
||||
- ../../base
|
||||
`)
|
||||
th.WriteK("/app/overlays/aws-nonprod", `
|
||||
resources:
|
||||
- ../aws
|
||||
`)
|
||||
th.WriteK("/app/overlays/aws-sandbox2.us-east-1", `
|
||||
resources:
|
||||
- ../aws-nonprod
|
||||
`)
|
||||
m := th.Run("/app/overlays/aws-sandbox2.us-east-1", th.MakeDefaultOptions())
|
||||
th.AssertActualEqualsExpected(m, "")
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package krusty_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
|
||||
)
|
||||
|
||||
func findSecret(m resmap.ResMap) *resource.Resource {
|
||||
for _, r := range m.Resources() {
|
||||
if r.OrgId().Kind == "Secret" {
|
||||
return r
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestDisableNameSuffixHash(t *testing.T) {
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
const kustomizationContent = `
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
namePrefix: foo-
|
||||
nameSuffix: -bar
|
||||
namespace: ns1
|
||||
commonLabels:
|
||||
app: nginx
|
||||
commonAnnotations:
|
||||
note: This is a test annotation
|
||||
resources:
|
||||
- deployment.yaml
|
||||
- namespace.yaml
|
||||
generatorOptions:
|
||||
disableNameSuffixHash: false
|
||||
configMapGenerator:
|
||||
- name: literalConfigMap
|
||||
literals:
|
||||
- DB_USERNAME=admin
|
||||
- DB_PASSWORD=somepw
|
||||
secretGenerator:
|
||||
- name: secret
|
||||
literals:
|
||||
- DB_USERNAME=admin
|
||||
- DB_PASSWORD=somepw
|
||||
type: Opaque
|
||||
patchesJson6902:
|
||||
- target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: Deployment
|
||||
name: dply1
|
||||
path: jsonpatch.json
|
||||
`
|
||||
|
||||
th.WriteK("/whatever", kustomizationContent)
|
||||
th.WriteF("/whatever/deployment.yaml", `
|
||||
apiVersion: apps/v1
|
||||
metadata:
|
||||
name: dply1
|
||||
kind: Deployment
|
||||
`)
|
||||
th.WriteF("/whatever/namespace.yaml", `
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: ns1
|
||||
`)
|
||||
th.WriteF("/whatever/jsonpatch.json", `[
|
||||
{"op": "add", "path": "/spec/replica", "value": "3"}
|
||||
]`)
|
||||
|
||||
m := th.Run("/whatever", th.MakeDefaultOptions())
|
||||
|
||||
secret := findSecret(m)
|
||||
if secret == nil {
|
||||
t.Errorf("Expected to find a Secret")
|
||||
}
|
||||
if secret.GetName() != "foo-secret-bar-9btc7bt4kb" {
|
||||
t.Errorf("unexpected secret resource name: %s", secret.GetName())
|
||||
}
|
||||
|
||||
th.WriteK("/whatever",
|
||||
strings.Replace(kustomizationContent,
|
||||
"disableNameSuffixHash: false",
|
||||
"disableNameSuffixHash: true", -1))
|
||||
m = th.Run("/whatever", th.MakeDefaultOptions())
|
||||
secret = findSecret(m)
|
||||
if secret == nil {
|
||||
t.Errorf("Expected to find a Secret")
|
||||
}
|
||||
if secret.GetName() != "foo-secret-bar" { // No hash at end.
|
||||
t.Errorf("unexpected secret resource name: %s", secret.GetName())
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package krusty is intended as the entry point package
|
||||
// for those seeking to add kustomize ability to other
|
||||
// programs.
|
||||
//
|
||||
// To use, follow the example of the kustomize CLI's 'build'
|
||||
// command. Also, see the high level tests in this package,
|
||||
// which serve a dual purpose as examples.
|
||||
package krusty
|
||||
@@ -1,86 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package krusty
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/builtins"
|
||||
"sigs.k8s.io/kustomize/api/filesys"
|
||||
"sigs.k8s.io/kustomize/api/internal/k8sdeps/transformer"
|
||||
pLdr "sigs.k8s.io/kustomize/api/internal/plugins/loader"
|
||||
"sigs.k8s.io/kustomize/api/internal/target"
|
||||
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
|
||||
"sigs.k8s.io/kustomize/api/k8sdeps/validator"
|
||||
fLdr "sigs.k8s.io/kustomize/api/loader"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
// Kustomizer performs kustomizations. It's meant to behave
|
||||
// similarly to the kustomize CLI, and can be used instead of
|
||||
// performing an exec to a kustomize CLI subprocess.
|
||||
// To use, load a filesystem with kustomization files (any
|
||||
// number of overlays and bases), then make a Kustomizer
|
||||
// injected with the given fileystem, then call Run.
|
||||
type Kustomizer struct {
|
||||
fSys filesys.FileSystem
|
||||
options *Options
|
||||
}
|
||||
|
||||
// MakeKustomizer returns an instance of Kustomizer.
|
||||
func MakeKustomizer(fSys filesys.FileSystem, o *Options) *Kustomizer {
|
||||
return &Kustomizer{fSys: fSys, options: o}
|
||||
}
|
||||
|
||||
// Run performs a kustomization.
|
||||
//
|
||||
// It uses its internal filesystem reference to read the file at
|
||||
// the given path argument, interpret it as a kustomization.yaml
|
||||
// file, perform the kustomization it represents, and return the
|
||||
// resulting resources.
|
||||
//
|
||||
// Any files referenced by the kustomization must be present in the
|
||||
// internal filesystem. One may call Run any number of times,
|
||||
// on any number of internal paths (e.g. the filesystem may contain
|
||||
// multiple overlays, and Run can be called on each of them).
|
||||
func (b *Kustomizer) Run(path string) (resmap.ResMap, error) {
|
||||
pf := transformer.NewFactoryImpl()
|
||||
rf := resmap.NewFactory(
|
||||
resource.NewFactory(
|
||||
kunstruct.NewKunstructuredFactoryImpl()),
|
||||
pf)
|
||||
lr := fLdr.RestrictionNone
|
||||
if b.options.LoadRestrictions == types.LoadRestrictionsRootOnly {
|
||||
lr = fLdr.RestrictionRootOnly
|
||||
}
|
||||
ldr, err := fLdr.NewLoader(lr, path, b.fSys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer ldr.Cleanup()
|
||||
kt := target.NewKustTarget(
|
||||
ldr,
|
||||
validator.NewKustValidator(),
|
||||
rf,
|
||||
pf,
|
||||
pLdr.NewLoader(b.options.PluginConfig, rf),
|
||||
)
|
||||
err = kt.Load()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var m resmap.ResMap
|
||||
if b.options.DoPrune {
|
||||
m, err = kt.MakePruneConfigMap()
|
||||
} else {
|
||||
m, err = kt.MakeCustomizedResMap()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if b.options.DoLegacyResourceSort {
|
||||
builtins.NewLegacyOrderTransformerPlugin().Transform(m)
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package krusty_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/filesys"
|
||||
"sigs.k8s.io/kustomize/api/krusty"
|
||||
)
|
||||
|
||||
// A simple usage example to shows what happens when
|
||||
// there are no files to read.
|
||||
// For more substantial tests and examples,
|
||||
// see other tests in this package.
|
||||
func TestEmptyFileSystem(t *testing.T) {
|
||||
fSys := filesys.MakeFsInMemory()
|
||||
b := krusty.MakeKustomizer(fSys, krusty.MakeDefaultOptions())
|
||||
_, err := b.Run("noSuchThing")
|
||||
if err == nil {
|
||||
t.Fatalf("expected error")
|
||||
}
|
||||
if err.Error() != "'noSuchThing' doesn't exist" {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package krusty
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/konfig"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
// Options holds high-level kustomize configuration options,
|
||||
// e.g. are plugins enabled, should the loader be restricted
|
||||
// to the kustomization root, etc.
|
||||
type Options struct {
|
||||
// When true, sort the resources before emitting them,
|
||||
// per a particular sort order. When false, don't do the
|
||||
// sort, and instead respect the depth-first resource input
|
||||
// order as specified by the kustomization file(s).
|
||||
DoLegacyResourceSort bool
|
||||
|
||||
// Restrictions on what can be loaded from the file system.
|
||||
// See type definition.
|
||||
LoadRestrictions types.LoadRestrictions
|
||||
|
||||
// Create an inventory object for pruning.
|
||||
DoPrune bool
|
||||
|
||||
// Options related to kustomize plugins.
|
||||
PluginConfig *types.PluginConfig
|
||||
}
|
||||
|
||||
// MakeDefaultOptions returns a default instance of Options.
|
||||
func MakeDefaultOptions() *Options {
|
||||
return &Options{
|
||||
DoLegacyResourceSort: true,
|
||||
LoadRestrictions: types.LoadRestrictionsRootOnly,
|
||||
DoPrune: false,
|
||||
PluginConfig: konfig.DisabledPluginConfig(),
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package krusty_test
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/filesys"
|
||||
"sigs.k8s.io/kustomize/api/konfig"
|
||||
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
|
||||
)
|
||||
|
||||
// The PrintPluginEnv plugin is a toy plugin that emits
|
||||
// its working directory and some environment variables,
|
||||
// to add regression protection to plugin loading logic.
|
||||
func TestPluginEnvironment(t *testing.T) {
|
||||
th := kusttest_test.MakeEnhancedHarness(t).
|
||||
PrepExecPlugin(
|
||||
"someteam.example.com", "v1", "PrintPluginEnv")
|
||||
defer th.Reset()
|
||||
|
||||
confirmBehavior(
|
||||
kusttest_test.MakeHarnessWithFs(t, filesys.MakeFsInMemory()),
|
||||
filesys.Separator)
|
||||
|
||||
dir := makeTmpDir(t)
|
||||
defer os.RemoveAll(dir)
|
||||
confirmBehavior(
|
||||
kusttest_test.MakeHarnessWithFs(t, filesys.MakeFsOnDisk()),
|
||||
dir)
|
||||
}
|
||||
|
||||
func confirmBehavior(th kusttest_test.Harness, dir string) {
|
||||
th.WriteK(dir, `
|
||||
generators:
|
||||
- config.yaml
|
||||
`)
|
||||
th.WriteF(filepath.Join(dir, "config.yaml"), `
|
||||
apiVersion: someteam.example.com/v1
|
||||
kind: PrintPluginEnv
|
||||
metadata:
|
||||
name: irrelevantHere
|
||||
`)
|
||||
m := th.Run(dir, th.MakeOptionsPluginsEnabled())
|
||||
|
||||
pHome, ok := os.LookupEnv(konfig.KustomizePluginHomeEnv)
|
||||
if !ok {
|
||||
th.GetT().Fatalf(
|
||||
"expected env var '%s' to be defined",
|
||||
konfig.KustomizePluginHomeEnv)
|
||||
}
|
||||
|
||||
th.AssertActualEqualsExpected(m, `
|
||||
apiVersion: v1
|
||||
env:
|
||||
kustomize_plugin_config_root: `+dir+`
|
||||
kustomize_plugin_home: `+pHome+`
|
||||
pwd: `+dir+`
|
||||
kind: GeneratedEnv
|
||||
metadata:
|
||||
name: hello
|
||||
`)
|
||||
}
|
||||
|
||||
func makeTmpDir(t *testing.T) string {
|
||||
base, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatalf("err %v", err)
|
||||
}
|
||||
dir, err := ioutil.TempDir(base, "kustomize-tmp-test-")
|
||||
if err != nil {
|
||||
t.Fatalf("err %v", err)
|
||||
}
|
||||
return dir
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package loader has a data loading interface and various implementations.
|
||||
package loader
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/filesys"
|
||||
"sigs.k8s.io/kustomize/api/ifc"
|
||||
"sigs.k8s.io/kustomize/api/internal/git"
|
||||
)
|
||||
|
||||
// NewLoader returns a Loader pointed at the given target.
|
||||
// If the target is remote, the loader will be restricted
|
||||
// to the root and below only. If the target is local, the
|
||||
// loader will have the restrictions passed in. Regardless,
|
||||
// if a local target attempts to transitively load remote bases,
|
||||
// the remote bases will all be root-only restricted.
|
||||
func NewLoader(
|
||||
lr LoadRestrictorFunc,
|
||||
target string, fSys filesys.FileSystem) (ifc.Loader, error) {
|
||||
repoSpec, err := git.NewRepoSpecFromUrl(target)
|
||||
if err == nil {
|
||||
// The target qualifies as a remote git target.
|
||||
return newLoaderAtGitClone(
|
||||
repoSpec, fSys, nil, git.ClonerUsingGitExec)
|
||||
}
|
||||
root, err := demandDirectoryRoot(fSys, target)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newLoaderAtConfirmedDir(
|
||||
lr, root, fSys, nil, git.ClonerUsingGitExec), nil
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package loader
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/filesys"
|
||||
)
|
||||
|
||||
type LoadRestrictorFunc func(
|
||||
filesys.FileSystem, filesys.ConfirmedDir, string) (string, error)
|
||||
|
||||
func RestrictionRootOnly(
|
||||
fSys filesys.FileSystem, root filesys.ConfirmedDir, path string) (string, error) {
|
||||
d, f, err := fSys.CleanedAbs(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if f == "" {
|
||||
return "", fmt.Errorf("'%s' must resolve to a file", path)
|
||||
}
|
||||
if !d.HasPrefix(root) {
|
||||
return "", fmt.Errorf(
|
||||
"security; file '%s' is not in or below '%s'",
|
||||
path, root)
|
||||
}
|
||||
return d.Join(f), nil
|
||||
}
|
||||
|
||||
func RestrictionNone(
|
||||
_ filesys.FileSystem, _ filesys.ConfirmedDir, path string) (string, error) {
|
||||
return path, nil
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package loader
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/filesys"
|
||||
)
|
||||
|
||||
func TestRestrictionNone(t *testing.T) {
|
||||
fSys := filesys.MakeFsInMemory()
|
||||
root := filesys.ConfirmedDir("irrelevant")
|
||||
path := "whatever"
|
||||
p, err := RestrictionNone(fSys, root, path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if p != path {
|
||||
t.Fatalf("expected '%s', got '%s'", path, p)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRestrictionRootOnly(t *testing.T) {
|
||||
fSys := filesys.MakeFsInMemory()
|
||||
root := filesys.ConfirmedDir(
|
||||
filesys.Separator + filepath.Join("tmp", "foo"))
|
||||
path := filepath.Join(string(root), "whatever", "beans")
|
||||
|
||||
fSys.Create(path)
|
||||
p, err := RestrictionRootOnly(fSys, root, path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if p != path {
|
||||
t.Fatalf("expected '%s', got '%s'", path, p)
|
||||
}
|
||||
|
||||
// Legal.
|
||||
path = filepath.Join(
|
||||
string(root), "whatever", "..", "..", "foo", "whatever", "beans")
|
||||
p, err = RestrictionRootOnly(fSys, root, path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
path = filepath.Join(
|
||||
string(root), "whatever", "beans")
|
||||
if p != path {
|
||||
t.Fatalf("expected '%s', got '%s'", path, p)
|
||||
}
|
||||
|
||||
// Illegal; file exists but is out of bounds.
|
||||
path = filepath.Join(filesys.Separator+"tmp", "illegal")
|
||||
fSys.Create(path)
|
||||
_, err = RestrictionRootOnly(fSys, root, path)
|
||||
if err == nil {
|
||||
t.Fatal("should have an error")
|
||||
}
|
||||
if !strings.Contains(
|
||||
err.Error(),
|
||||
"file '/tmp/illegal' is not in or below '/tmp/foo'") {
|
||||
t.Fatalf("unexpected err: %s", err)
|
||||
}
|
||||
}
|
||||
20
api/main.go
20
api/main.go
@@ -1,20 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// A dummy main to help with releasing the kustomize API module.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/provenance"
|
||||
)
|
||||
|
||||
// TODO: delete this when we find a better way to generate release notes.
|
||||
func main() {
|
||||
fmt.Println(`
|
||||
This 'main' exists only to make goreleaser create release notes for the API.
|
||||
See https://github.com/goreleaser/goreleaser/issues/981
|
||||
and https://github.com/kubernetes-sigs/kustomize/tree/master/releasing`)
|
||||
fmt.Println(provenance.GetProvenance())
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package kusttest_test
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/filesys"
|
||||
"sigs.k8s.io/kustomize/api/konfig"
|
||||
"sigs.k8s.io/kustomize/api/konfig/builtinpluginconsts"
|
||||
"sigs.k8s.io/kustomize/api/krusty"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
// Harness manages a kustomize environment for tests.
|
||||
type Harness struct {
|
||||
t *testing.T
|
||||
fSys filesys.FileSystem
|
||||
}
|
||||
|
||||
func MakeHarness(t *testing.T) Harness {
|
||||
return MakeHarnessWithFs(t, filesys.MakeFsInMemory())
|
||||
}
|
||||
|
||||
func MakeHarnessWithFs(
|
||||
t *testing.T, fSys filesys.FileSystem) Harness {
|
||||
return Harness{
|
||||
t: t,
|
||||
fSys: fSys,
|
||||
}
|
||||
}
|
||||
|
||||
func (th Harness) GetT() *testing.T {
|
||||
return th.t
|
||||
}
|
||||
|
||||
func (th Harness) GetFSys() filesys.FileSystem {
|
||||
return th.fSys
|
||||
}
|
||||
|
||||
func (th Harness) WriteK(path string, content string) {
|
||||
th.fSys.WriteFile(
|
||||
filepath.Join(
|
||||
path,
|
||||
konfig.DefaultKustomizationFileName()), []byte(`
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
`+content))
|
||||
}
|
||||
|
||||
func (th Harness) WriteF(path string, content string) {
|
||||
th.fSys.WriteFile(path, []byte(content))
|
||||
}
|
||||
|
||||
func (th Harness) MakeDefaultOptions() krusty.Options {
|
||||
return th.MakeOptionsPluginsDisabled()
|
||||
}
|
||||
|
||||
// This has no impact on Builtin plugins, as they are always enabled.
|
||||
func (th Harness) MakeOptionsPluginsDisabled() krusty.Options {
|
||||
return krusty.Options{
|
||||
LoadRestrictions: types.LoadRestrictionsRootOnly,
|
||||
PluginConfig: konfig.DisabledPluginConfig(),
|
||||
}
|
||||
}
|
||||
|
||||
// Enables use of non-builtin plugins.
|
||||
func (th Harness) MakeOptionsPluginsEnabled() krusty.Options {
|
||||
c, err := konfig.EnabledPluginConfig()
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "unable to find plugin root") {
|
||||
th.t.Log(
|
||||
"Tests that want to run with plugins enabled must be " +
|
||||
"bookended by calls to MakeEnhancedHarness(), Reset().")
|
||||
}
|
||||
th.t.Fatal(err)
|
||||
}
|
||||
return krusty.Options{
|
||||
LoadRestrictions: types.LoadRestrictionsRootOnly,
|
||||
PluginConfig: c,
|
||||
}
|
||||
}
|
||||
|
||||
// Run, failing on error.
|
||||
func (th Harness) Run(path string, o krusty.Options) resmap.ResMap {
|
||||
m, err := krusty.MakeKustomizer(th.fSys, &o).Run(path)
|
||||
if err != nil {
|
||||
th.t.Fatal(err)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// Run, failing if there is no error.
|
||||
func (th Harness) RunWithErr(path string, o krusty.Options) error {
|
||||
_, err := krusty.MakeKustomizer(th.fSys, &o).Run(path)
|
||||
if err == nil {
|
||||
th.t.Fatalf("expected error")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (th Harness) WriteLegacyConfigs(fName string) {
|
||||
m := builtinpluginconsts.GetDefaultFieldSpecsAsMap()
|
||||
var content []byte
|
||||
for _, tCfg := range m {
|
||||
content = append(content, []byte(tCfg)...)
|
||||
}
|
||||
err := th.fSys.WriteFile(fName, content)
|
||||
if err != nil {
|
||||
th.t.Fatalf("unable to add file %s", fName)
|
||||
}
|
||||
}
|
||||
|
||||
func (th Harness) AssertActualEqualsExpected(
|
||||
m resmap.ResMap, expected string) {
|
||||
th.AssertActualEqualsExpectedWithTweak(m, nil, expected)
|
||||
}
|
||||
|
||||
func (th Harness) AssertActualEqualsExpectedWithTweak(
|
||||
m resmap.ResMap, tweaker func([]byte) []byte, expected string) {
|
||||
assertActualEqualsExpectedWithTweak(th, m, tweaker, expected)
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package kusttest_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/filesys"
|
||||
"sigs.k8s.io/kustomize/api/ifc"
|
||||
"sigs.k8s.io/kustomize/api/internal/k8sdeps/transformer"
|
||||
pLdr "sigs.k8s.io/kustomize/api/internal/plugins/loader"
|
||||
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
|
||||
"sigs.k8s.io/kustomize/api/konfig"
|
||||
fLdr "sigs.k8s.io/kustomize/api/loader"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
|
||||
)
|
||||
|
||||
// HarnessEnhanced manages a full plugin environment for tests.
|
||||
type HarnessEnhanced struct {
|
||||
Harness
|
||||
pte *pluginTestEnv
|
||||
rf *resmap.Factory
|
||||
ldr ifc.Loader
|
||||
pl *pLdr.Loader
|
||||
}
|
||||
|
||||
func MakeEnhancedHarness(t *testing.T) *HarnessEnhanced {
|
||||
pte := newPluginTestEnv(t).set()
|
||||
|
||||
pc, err := konfig.EnabledPluginConfig()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
fSys := filesys.MakeFsInMemory()
|
||||
|
||||
rf := resmap.NewFactory(
|
||||
resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl()),
|
||||
transformer.NewFactoryImpl())
|
||||
|
||||
result := &HarnessEnhanced{
|
||||
Harness: Harness{t: t, fSys: fSys},
|
||||
pte: pte,
|
||||
rf: rf,
|
||||
pl: pLdr.NewLoader(pc, rf)}
|
||||
result.ResetLoaderRoot(filesys.Separator)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (th *HarnessEnhanced) Reset() {
|
||||
th.pte.reset()
|
||||
}
|
||||
|
||||
func (th *HarnessEnhanced) BuildGoPlugin(g, v, k string) *HarnessEnhanced {
|
||||
th.pte.buildGoPlugin(g, v, k)
|
||||
return th
|
||||
}
|
||||
|
||||
func (th *HarnessEnhanced) PrepExecPlugin(g, v, k string) *HarnessEnhanced {
|
||||
th.pte.prepExecPlugin(g, v, k)
|
||||
return th
|
||||
}
|
||||
|
||||
func (th *HarnessEnhanced) PrepBuiltin(k string) *HarnessEnhanced {
|
||||
th.pte.buildGoPlugin(konfig.BuiltinPluginPackage, "", k)
|
||||
return th
|
||||
}
|
||||
|
||||
func (th *HarnessEnhanced) ResetLoaderRoot(root string) {
|
||||
if err := th.fSys.Mkdir(root); err != nil {
|
||||
th.t.Fatal(err)
|
||||
}
|
||||
ldr, err := fLdr.NewLoader(
|
||||
fLdr.RestrictionRootOnly, root, th.fSys)
|
||||
if err != nil {
|
||||
th.t.Fatalf("Unable to make loader: %v", err)
|
||||
}
|
||||
th.ldr = ldr
|
||||
}
|
||||
|
||||
func (th *HarnessEnhanced) LoadAndRunGenerator(
|
||||
config string) resmap.ResMap {
|
||||
res, err := th.rf.RF().FromBytes([]byte(config))
|
||||
if err != nil {
|
||||
th.t.Fatalf("Err: %v", err)
|
||||
}
|
||||
g, err := th.pl.LoadGenerator(
|
||||
th.ldr, valtest_test.MakeFakeValidator(), res)
|
||||
if err != nil {
|
||||
th.t.Fatalf("Err: %v", err)
|
||||
}
|
||||
rm, err := g.Generate()
|
||||
if err != nil {
|
||||
th.t.Fatalf("Err: %v", err)
|
||||
}
|
||||
return rm
|
||||
}
|
||||
|
||||
func (th *HarnessEnhanced) LoadAndRunTransformer(
|
||||
config, input string) resmap.ResMap {
|
||||
resMap, err := th.RunTransformer(config, input)
|
||||
if err != nil {
|
||||
th.t.Fatalf("Err: %v", err)
|
||||
}
|
||||
return resMap
|
||||
}
|
||||
|
||||
func (th *HarnessEnhanced) ErrorFromLoadAndRunTransformer(
|
||||
config, input string) error {
|
||||
_, err := th.RunTransformer(config, input)
|
||||
return err
|
||||
}
|
||||
|
||||
func (th *HarnessEnhanced) RunTransformer(
|
||||
config, input string) (resmap.ResMap, error) {
|
||||
resMap, err := th.rf.NewResMapFromBytes([]byte(input))
|
||||
if err != nil {
|
||||
th.t.Fatalf("Err: %v", err)
|
||||
}
|
||||
return th.RunTransformerFromResMap(config, resMap)
|
||||
}
|
||||
|
||||
func (th *HarnessEnhanced) RunTransformerFromResMap(
|
||||
config string, resMap resmap.ResMap) (resmap.ResMap, error) {
|
||||
transConfig, err := th.rf.RF().FromBytes([]byte(config))
|
||||
if err != nil {
|
||||
th.t.Fatalf("Err: %v", err)
|
||||
}
|
||||
g, err := th.pl.LoadTransformer(
|
||||
th.ldr, valtest_test.MakeFakeValidator(), transConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = g.Transform(resMap)
|
||||
return resMap, err
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package kusttest_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
)
|
||||
|
||||
type hasGetT interface {
|
||||
GetT() *testing.T
|
||||
}
|
||||
|
||||
func assertActualEqualsExpectedWithTweak(
|
||||
ht hasGetT,
|
||||
m resmap.ResMap,
|
||||
tweaker func([]byte) []byte, expected string) {
|
||||
if m == nil {
|
||||
ht.GetT().Fatalf("Map should not be nil.")
|
||||
}
|
||||
// Ignore leading linefeed in expected value
|
||||
// to ease readability of tests.
|
||||
if len(expected) > 0 && expected[0] == 10 {
|
||||
expected = expected[1:]
|
||||
}
|
||||
actual, err := m.AsYaml()
|
||||
if err != nil {
|
||||
ht.GetT().Fatalf("Unexpected err: %v", err)
|
||||
}
|
||||
if tweaker != nil {
|
||||
actual = tweaker(actual)
|
||||
}
|
||||
if string(actual) != expected {
|
||||
reportDiffAndFail(ht.GetT(), actual, expected)
|
||||
}
|
||||
}
|
||||
|
||||
// Pretty printing of file differences.
|
||||
func reportDiffAndFail(
|
||||
t *testing.T, actual []byte, expected string) {
|
||||
sE, maxLen := convertToArray(expected)
|
||||
sA, _ := convertToArray(string(actual))
|
||||
fmt.Println("===== ACTUAL BEGIN ========================================")
|
||||
fmt.Print(string(actual))
|
||||
fmt.Println("===== ACTUAL END ==========================================")
|
||||
format := fmt.Sprintf("%%s %%-%ds %%s\n", maxLen+4)
|
||||
limit := 0
|
||||
if len(sE) < len(sA) {
|
||||
limit = len(sE)
|
||||
} else {
|
||||
limit = len(sA)
|
||||
}
|
||||
fmt.Printf(format, " ", "EXPECTED", "ACTUAL")
|
||||
fmt.Printf(format, " ", "--------", "------")
|
||||
for i := 0; i < limit; i++ {
|
||||
fmt.Printf(format, hint(sE[i], sA[i]), sE[i], sA[i])
|
||||
}
|
||||
if len(sE) < len(sA) {
|
||||
for i := len(sE); i < len(sA); i++ {
|
||||
fmt.Printf(format, "X", "", sA[i])
|
||||
}
|
||||
} else {
|
||||
for i := len(sA); i < len(sE); i++ {
|
||||
fmt.Printf(format, "X", sE[i], "")
|
||||
}
|
||||
}
|
||||
t.Fatalf("Expected not equal to actual")
|
||||
}
|
||||
|
||||
func hint(a, b string) string {
|
||||
if a == b {
|
||||
return " "
|
||||
}
|
||||
return "X"
|
||||
}
|
||||
|
||||
func convertToArray(x string) ([]string, int) {
|
||||
a := strings.Split(strings.TrimSuffix(x, "\n"), "\n")
|
||||
maxLen := 0
|
||||
for i, v := range a {
|
||||
z := tabToSpace(v)
|
||||
if len(z) > maxLen {
|
||||
maxLen = len(z)
|
||||
}
|
||||
a[i] = z
|
||||
}
|
||||
return a, maxLen
|
||||
}
|
||||
|
||||
func tabToSpace(input string) string {
|
||||
var result []string
|
||||
for _, i := range input {
|
||||
if i == 9 {
|
||||
result = append(result, " ")
|
||||
} else {
|
||||
result = append(result, string(i))
|
||||
}
|
||||
}
|
||||
return strings.Join(result, "")
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package kusttest_test
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/filesys"
|
||||
"sigs.k8s.io/kustomize/api/internal/plugins/compiler"
|
||||
"sigs.k8s.io/kustomize/api/konfig"
|
||||
)
|
||||
|
||||
// pluginTestEnv manages plugins for tests.
|
||||
// It manages a Go plugin compiler,
|
||||
// makes and removes a temporary working directory,
|
||||
// and sets/resets shell env vars as needed.
|
||||
type pluginTestEnv struct {
|
||||
t *testing.T
|
||||
compiler *compiler.Compiler
|
||||
srcRoot string
|
||||
workDir string
|
||||
oldXdg string
|
||||
wasSet bool
|
||||
}
|
||||
|
||||
// newPluginTestEnv returns a new instance of pluginTestEnv.
|
||||
func newPluginTestEnv(t *testing.T) *pluginTestEnv {
|
||||
return &pluginTestEnv{t: t}
|
||||
}
|
||||
|
||||
// set creates a test environment.
|
||||
// Uses a filesystem on disk for compilation (or copying) of
|
||||
// plugin code - this FileSystem has nothing to do with
|
||||
// the FileSystem used for loading config yaml in the tests.
|
||||
func (x *pluginTestEnv) set() *pluginTestEnv {
|
||||
x.createWorkDir()
|
||||
var err error
|
||||
x.srcRoot, err = compiler.DeterminePluginSrcRoot(filesys.MakeFsOnDisk())
|
||||
if err != nil {
|
||||
x.t.Error(err)
|
||||
}
|
||||
x.compiler = compiler.NewCompiler(x.srcRoot, x.workDir)
|
||||
x.setEnv()
|
||||
return x
|
||||
}
|
||||
|
||||
// reset restores the environment to pre-test state.
|
||||
func (x *pluginTestEnv) reset() {
|
||||
x.resetEnv()
|
||||
x.removeWorkDir()
|
||||
}
|
||||
|
||||
// buildGoPlugin compiles a Go plugin, leaving the newly
|
||||
// created object code in the right place - a temporary
|
||||
// working directory pointed to by KustomizePluginHomeEnv.
|
||||
// This avoids overwriting anything the user/developer has
|
||||
// otherwise created.
|
||||
func (x *pluginTestEnv) buildGoPlugin(g, v, k string) {
|
||||
err := x.compiler.Compile(g, v, k)
|
||||
if err != nil {
|
||||
x.t.Errorf("compile failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// prepExecPlugin copies an exec plugin from it's
|
||||
// home in the discovered srcRoot to the same temp
|
||||
// directory where Go plugin object code is placed.
|
||||
// Kustomize (and its tests) expect to find plugins
|
||||
// (Go or Exec) in the same spot, and since the test
|
||||
// framework is compiling Go plugins to a temp dir,
|
||||
// it must likewise copy Exec plugins to that same
|
||||
// temp dir.
|
||||
func (x *pluginTestEnv) prepExecPlugin(g, v, k string) {
|
||||
lowK := strings.ToLower(k)
|
||||
src := filepath.Join(x.srcRoot, g, v, lowK, k)
|
||||
tmp := filepath.Join(x.workDir, g, v, lowK, k)
|
||||
if err := os.MkdirAll(filepath.Dir(tmp), 0755); err != nil {
|
||||
x.t.Errorf("error making directory: %s", filepath.Dir(tmp))
|
||||
}
|
||||
cmd := exec.Command("cp", src, tmp)
|
||||
cmd.Env = os.Environ()
|
||||
if err := cmd.Run(); err != nil {
|
||||
x.t.Errorf("error copying %s to %s: %v", src, tmp, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *pluginTestEnv) createWorkDir() {
|
||||
var err error
|
||||
x.workDir, err = ioutil.TempDir("", "kustomize-plugin-tests")
|
||||
if err != nil {
|
||||
x.t.Errorf("failed to make work dir: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *pluginTestEnv) removeWorkDir() {
|
||||
err := os.RemoveAll(x.workDir)
|
||||
if err != nil {
|
||||
x.t.Errorf(
|
||||
"removing work dir: %s %v", x.workDir, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *pluginTestEnv) setEnv() {
|
||||
x.oldXdg, x.wasSet = os.LookupEnv(konfig.KustomizePluginHomeEnv)
|
||||
os.Setenv(konfig.KustomizePluginHomeEnv, x.workDir)
|
||||
}
|
||||
|
||||
func (x *pluginTestEnv) resetEnv() {
|
||||
if x.wasSet {
|
||||
os.Setenv(konfig.KustomizePluginHomeEnv, x.oldXdg)
|
||||
} else {
|
||||
os.Unsetenv(konfig.KustomizePluginHomeEnv)
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package transform
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
// mapTransformer applies a string->string map to fieldSpecs.
|
||||
type mapTransformer struct {
|
||||
m map[string]string
|
||||
fieldSpecs []types.FieldSpec
|
||||
}
|
||||
|
||||
var _ resmap.Transformer = &mapTransformer{}
|
||||
|
||||
// NewMapTransformer construct a mapTransformer.
|
||||
func NewMapTransformer(
|
||||
pc []types.FieldSpec, m map[string]string) (resmap.Transformer, error) {
|
||||
if m == nil {
|
||||
return newNoOpTransformer(), nil
|
||||
}
|
||||
if pc == nil {
|
||||
return nil, errors.New("fieldSpecs is not expected to be nil")
|
||||
}
|
||||
return &mapTransformer{fieldSpecs: pc, m: m}, nil
|
||||
}
|
||||
|
||||
// Transform apply each <key, value> pair in the mapTransformer to the
|
||||
// fields specified in mapTransformer.
|
||||
func (o *mapTransformer) Transform(m resmap.ResMap) error {
|
||||
for _, r := range m.Resources() {
|
||||
for _, path := range o.fieldSpecs {
|
||||
if !r.OrgId().IsSelected(&path.Gvk) {
|
||||
continue
|
||||
}
|
||||
err := MutateField(
|
||||
r.Map(), path.PathSlice(),
|
||||
path.CreateIfNotPresent, o.addMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *mapTransformer) addMap(in interface{}) (interface{}, error) {
|
||||
m, ok := in.(map[string]interface{})
|
||||
if in == nil {
|
||||
m = map[string]interface{}{}
|
||||
} else if !ok {
|
||||
return nil, fmt.Errorf("%#v is expected to be %T", in, m)
|
||||
}
|
||||
for k, v := range o.m {
|
||||
m[k] = v
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package transform
|
||||
|
||||
import "sigs.k8s.io/kustomize/api/resmap"
|
||||
|
||||
// noOpTransformer contains a no-op transformer.
|
||||
type noOpTransformer struct{}
|
||||
|
||||
var _ resmap.Transformer = &noOpTransformer{}
|
||||
|
||||
// newNoOpTransformer constructs a noOpTransformer.
|
||||
func newNoOpTransformer() resmap.Transformer {
|
||||
return &noOpTransformer{}
|
||||
}
|
||||
|
||||
// Transform does nothing.
|
||||
func (o *noOpTransformer) Transform(_ resmap.ResMap) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package types holds the definition of the kustomization struct and
|
||||
// supporting structs. It's the k8s API conformant object that describes
|
||||
// a set of generation and transformation operations to create and/or
|
||||
// modify k8s resources.
|
||||
// A kustomization file is a serialization of this struct.
|
||||
package types
|
||||
@@ -1,33 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type errOnlyBuiltinPluginsAllowed struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (e *errOnlyBuiltinPluginsAllowed) Error() string {
|
||||
return fmt.Sprintf(
|
||||
"external plugins disabled; unable to load external plugin '%s'",
|
||||
e.name)
|
||||
}
|
||||
|
||||
func NewErrOnlyBuiltinPluginsAllowed(n string) *errOnlyBuiltinPluginsAllowed {
|
||||
return &errOnlyBuiltinPluginsAllowed{name: n}
|
||||
}
|
||||
|
||||
func IsErrOnlyBuiltinPluginsAllowed(err error) bool {
|
||||
_, ok := err.(*errOnlyBuiltinPluginsAllowed)
|
||||
if ok {
|
||||
return true
|
||||
}
|
||||
_, ok = errors.Cause(err).(*errOnlyBuiltinPluginsAllowed)
|
||||
return ok
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type errUnableToFind struct {
|
||||
// What are we unable to find?
|
||||
what string
|
||||
// What things did we try?
|
||||
attempts []Pair
|
||||
}
|
||||
|
||||
func (e *errUnableToFind) Error() string {
|
||||
var m []string
|
||||
for _, p := range e.attempts {
|
||||
m = append(m, "('"+p.Value+"'; "+p.Key+")")
|
||||
}
|
||||
return fmt.Sprintf(
|
||||
"unable to find plugin root - tried: %s", strings.Join(m, ", "))
|
||||
}
|
||||
|
||||
func NewErrUnableToFind(w string, a []Pair) *errUnableToFind {
|
||||
return &errUnableToFind{what: w, attempts: a}
|
||||
}
|
||||
|
||||
func IsErrUnableToFind(err error) bool {
|
||||
_, ok := err.(*errUnableToFind)
|
||||
if ok {
|
||||
return true
|
||||
}
|
||||
_, ok = errors.Cause(err).(*errUnableToFind)
|
||||
return ok
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
//go:generate stringer -type=GarbagePolicy
|
||||
type GarbagePolicy int
|
||||
|
||||
const (
|
||||
GarbageIgnore GarbagePolicy = iota + 1
|
||||
GarbageCollect
|
||||
)
|
||||
@@ -1,50 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// GenArgs contains both GeneratorArgs and GeneratorOptions.
|
||||
type GenArgs struct {
|
||||
args *GeneratorArgs
|
||||
opts *GeneratorOptions
|
||||
}
|
||||
|
||||
// NewGenArgs returns a new object of GenArgs
|
||||
func NewGenArgs(args *GeneratorArgs, opts *GeneratorOptions) *GenArgs {
|
||||
return &GenArgs{
|
||||
args: args,
|
||||
opts: opts,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *GenArgs) String() string {
|
||||
if g == nil {
|
||||
return "{nilGenArgs}"
|
||||
}
|
||||
return "{" +
|
||||
strings.Join([]string{
|
||||
"nsfx:" + strconv.FormatBool(g.ShouldAddHashSuffixToName()),
|
||||
"beh:" + g.Behavior().String()},
|
||||
",") +
|
||||
"}"
|
||||
}
|
||||
|
||||
// ShouldAddHashSuffixToName returns true if a resource
|
||||
// content hash should be appended to the name of the resource.
|
||||
func (g *GenArgs) ShouldAddHashSuffixToName() bool {
|
||||
return g.args != nil &&
|
||||
(g.opts == nil || !g.opts.DisableNameSuffixHash)
|
||||
}
|
||||
|
||||
// Behavior returns Behavior field of GeneratorArgs
|
||||
func (g *GenArgs) Behavior() GenerationBehavior {
|
||||
if g.args == nil {
|
||||
return BehaviorUnspecified
|
||||
}
|
||||
return NewGenerationBehavior(g.args.Behavior)
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
func TestGenArgs_String(t *testing.T) {
|
||||
tests := []struct {
|
||||
ga *GenArgs
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
ga: nil,
|
||||
expected: "{nilGenArgs}",
|
||||
},
|
||||
{
|
||||
ga: &GenArgs{},
|
||||
expected: "{nsfx:false,beh:unspecified}",
|
||||
},
|
||||
{
|
||||
ga: NewGenArgs(
|
||||
&GeneratorArgs{Behavior: "merge"},
|
||||
&GeneratorOptions{DisableNameSuffixHash: false}),
|
||||
expected: "{nsfx:true,beh:merge}",
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
if test.ga.String() != test.expected {
|
||||
t.Fatalf("Expected '%s', got '%s'", test.expected, test.ga.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// GeneratorArgs contains arguments common to ConfigMap and Secret generators.
|
||||
type GeneratorArgs struct {
|
||||
// Namespace for the configmap, optional
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
|
||||
// Name - actually the partial name - of the generated resource.
|
||||
// The full name ends up being something like
|
||||
// NamePrefix + this.Name + hash(content of generated resource).
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
|
||||
// Behavior of generated resource, must be one of:
|
||||
// 'create': create a new one
|
||||
// 'replace': replace the existing one
|
||||
// 'merge': merge with the existing one
|
||||
Behavior string `json:"behavior,omitempty" yaml:"behavior,omitempty"`
|
||||
|
||||
// KvPairSources for the generator.
|
||||
KvPairSources `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// Inventory records all objects touched in a build operation.
|
||||
type Inventory struct {
|
||||
Type string `json:"type,omitempty" yaml:"type,omitempty"`
|
||||
ConfigMap NameArgs `json:"configMap,omitempty" yaml:"configMap,omitempty"`
|
||||
}
|
||||
|
||||
// NameArgs holds both namespace and name.
|
||||
type NameArgs struct {
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// Restrictions on what things can be referred to
|
||||
// in a kustomization file.
|
||||
//
|
||||
//go:generate stringer -type=LoadRestrictions
|
||||
type LoadRestrictions int
|
||||
|
||||
const (
|
||||
LoadRestrictionsUnknown LoadRestrictions = iota
|
||||
|
||||
// Files referenced by a kustomization file must be in
|
||||
// or under the directory holding the kustomization
|
||||
// file itself.
|
||||
LoadRestrictionsRootOnly
|
||||
|
||||
// The kustomization file may specify absolute or
|
||||
// relative paths to patch or resources files outside
|
||||
// its own tree.
|
||||
LoadRestrictionsNone
|
||||
)
|
||||
@@ -1,25 +0,0 @@
|
||||
// Code generated by "stringer -type=LoadRestrictions"; DO NOT EDIT.
|
||||
|
||||
package types
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[LoadRestrictionsUnknown-0]
|
||||
_ = x[LoadRestrictionsRootOnly-1]
|
||||
_ = x[LoadRestrictionsNone-2]
|
||||
}
|
||||
|
||||
const _LoadRestrictions_name = "LoadRestrictionsUnknownLoadRestrictionsRootOnlyLoadRestrictionsNone"
|
||||
|
||||
var _LoadRestrictions_index = [...]uint8{0, 23, 47, 67}
|
||||
|
||||
func (i LoadRestrictions) String() string {
|
||||
if i < 0 || i >= LoadRestrictions(len(_LoadRestrictions_index)-1) {
|
||||
return "LoadRestrictions(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _LoadRestrictions_name[_LoadRestrictions_index[i]:_LoadRestrictions_index[i+1]]
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// Pair is a key value pair.
|
||||
type Pair struct {
|
||||
Key string
|
||||
Value string
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// Patch represent either a Strategic Merge Patch or a JSON patch
|
||||
// and its targets.
|
||||
// The content of the patch can either be from a file
|
||||
// or from an inline string.
|
||||
type Patch struct {
|
||||
// Path is a relative file path to the patch file.
|
||||
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||
|
||||
// Patch is the content of a patch.
|
||||
Patch string `json:"patch,omitempty" yaml:"patch,omitempty"`
|
||||
|
||||
// Target points to the resources that the patch is applied to
|
||||
Target *Selector `json:"target,omitempty" yaml:"target,omitempty"`
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// PatchJson6902 represents a json patch for an object
|
||||
// with format documented https://tools.ietf.org/html/rfc6902.
|
||||
type PatchJson6902 struct {
|
||||
// PatchTarget refers to a Kubernetes object that the json patch will be
|
||||
// applied to. It must refer to a Kubernetes resource under the
|
||||
// purview of this kustomization. PatchTarget should use the
|
||||
// raw name of the object (the name specified in its YAML,
|
||||
// before addition of a namePrefix and a nameSuffix).
|
||||
Target *PatchTarget `json:"target" yaml:"target"`
|
||||
|
||||
// relative file path for a json patch file inside a kustomization
|
||||
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||
|
||||
// inline patch string
|
||||
Patch string `json:"patch,omitempty" yaml:"patch,omitempty"`
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// PluginConfig holds plugin configuration.
|
||||
type PluginConfig struct {
|
||||
// AbsPluginHome is the home of kustomize plugins.
|
||||
// Kustomize plugin configuration files are k8s-style objects
|
||||
// containing the fields 'apiVersion' and 'kind', e.g.
|
||||
// apiVersion: apps/v1
|
||||
// kind: Deployment
|
||||
// When kustomize reads a plugin configuration file (as as result
|
||||
// of seeing the file name in the 'generators:' or 'transformers:'
|
||||
// field in a kustomization file), it must then locate the plugin
|
||||
// code (Go plugin or exec plugin).
|
||||
// Every kustomize plugin (its code, its tests, supporting data
|
||||
// files, etc.) must be housed in its own directory at
|
||||
// ${AbsPluginHome}/${pluginApiVersion}/LOWERCASE(${pluginKind})
|
||||
// where
|
||||
// - ${AbsPluginHome} is an absolute path, defined below.
|
||||
// - ${pluginApiVersion} is taken from the plugin config file.
|
||||
// - ${pluginKind} is taken from the plugin config file.
|
||||
// The value of AbsPluginHome can be any absolute path, but might
|
||||
// default to $XDG_CONFIG_HOME/kustomize/plugin.
|
||||
AbsPluginHome string
|
||||
|
||||
// PluginRestrictions defines the plugin restriction state.
|
||||
// See type for more information.
|
||||
PluginRestrictions PluginRestrictions
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// Some plugin classes
|
||||
// - builtin: plugins defined in the kustomize repo.
|
||||
// May be freely used and re-configured.
|
||||
// - local: plugins that aren't builtin but are
|
||||
// locally defined (presumably by the user), meaning
|
||||
// the kustomization refers to them via a relative
|
||||
// file path, not a URL.
|
||||
// - remote: require a build-time download to obtain.
|
||||
// Unadvised, unless one controls the
|
||||
// serving site.
|
||||
//
|
||||
//go:generate stringer -type=PluginRestrictions
|
||||
type PluginRestrictions int
|
||||
|
||||
const (
|
||||
PluginRestrictionsUnknown PluginRestrictions = iota
|
||||
|
||||
// Non-builtin plugins completely disabled.
|
||||
PluginRestrictionsBuiltinsOnly
|
||||
|
||||
// No restrictions, do whatever you want.
|
||||
PluginRestrictionsNone
|
||||
)
|
||||
@@ -1,25 +0,0 @@
|
||||
// Code generated by "stringer -type=PluginRestrictions"; DO NOT EDIT.
|
||||
|
||||
package types
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[PluginRestrictionsUnknown-0]
|
||||
_ = x[PluginRestrictionsBuiltinsOnly-1]
|
||||
_ = x[PluginRestrictionsNone-2]
|
||||
}
|
||||
|
||||
const _PluginRestrictions_name = "PluginRestrictionsUnknownPluginRestrictionsBuiltinsOnlyPluginRestrictionsNone"
|
||||
|
||||
var _PluginRestrictions_index = [...]uint8{0, 25, 55, 77}
|
||||
|
||||
func (i PluginRestrictions) String() string {
|
||||
if i < 0 || i >= PluginRestrictions(len(_PluginRestrictions_index)-1) {
|
||||
return "PluginRestrictions(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _PluginRestrictions_name[_PluginRestrictions_index[i]:_PluginRestrictions_index[i+1]]
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// Replacement defines how to perform a substitution
|
||||
// where it is from and where it is to.
|
||||
type Replacement struct {
|
||||
Source *ReplSource `json:"source" yaml:"source"`
|
||||
Target *ReplTarget `json:"target" yaml:"target"`
|
||||
}
|
||||
|
||||
// ReplSource defines where a substitution is from
|
||||
// It can from two different kinds of sources
|
||||
// - from a field of one resource
|
||||
// - from a string
|
||||
type ReplSource struct {
|
||||
ObjRef *Target `json:"objref,omitempty" yaml:"objref,omitempty"`
|
||||
FieldRef string `json:"fieldref,omitempty" yaml:"fiedldref,omitempty"`
|
||||
Value string `json:"value,omitempty" yaml:"value,omitempty"`
|
||||
}
|
||||
|
||||
// ReplTarget defines where a substitution is to.
|
||||
type ReplTarget struct {
|
||||
ObjRef *Selector `json:"objref,omitempty" yaml:"objref,omitempty"`
|
||||
FieldRefs []string `json:"fieldrefs,omitempty" yaml:"fieldrefs,omitempty"`
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// TypeMeta partially copies apimachinery/pkg/apis/meta/v1.TypeMeta
|
||||
// No need for a direct dependence; the fields are stable.
|
||||
type TypeMeta struct {
|
||||
Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
|
||||
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
# Copyright 2019 The Kubernetes Authors.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
run:
|
||||
deadline: 5m
|
||||
|
||||
linters:
|
||||
# please, do not use `enable-all`: it's deprecated and will be removed soon.
|
||||
# inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint
|
||||
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
|
||||
- typecheck
|
||||
- unconvert
|
||||
# - unparam
|
||||
- unused
|
||||
- varcheck
|
||||
# - whitespace
|
||||
|
||||
|
||||
linters-settings:
|
||||
dupl:
|
||||
threshold: 400
|
||||
lll:
|
||||
line-length: 170
|
||||
gocyclo:
|
||||
min-complexity: 30
|
||||
golint:
|
||||
min-confidence: 0.85
|
||||
@@ -1,2 +0,0 @@
|
||||
Copyright {{.Year}} {{.Holder}}
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
@@ -1,39 +0,0 @@
|
||||
# Copyright 2019 The Kubernetes Authors.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
.PHONY: generate license fix vet fmt test build tidy
|
||||
|
||||
GOBIN := $(shell go env GOPATH)/bin
|
||||
|
||||
build:
|
||||
go build -v -o $(GOBIN)/config .
|
||||
|
||||
all: generate build license fix vet fmt test lint tidy
|
||||
|
||||
fix:
|
||||
go fix ./...
|
||||
|
||||
fmt:
|
||||
go fmt ./...
|
||||
|
||||
generate:
|
||||
(which $(GOBIN)/mdtogo || go get sigs.k8s.io/kustomize/cmd/mdtogo)
|
||||
GOBIN=$(GOBIN) go generate ./...
|
||||
|
||||
license:
|
||||
(which $(GOBIN)/addlicense || go get github.com/google/addlicense)
|
||||
$(GOBIN)/addlicense -y 2019 -c "The Kubernetes Authors." -f LICENSE_TEMPLATE .
|
||||
|
||||
tidy:
|
||||
go mod tidy
|
||||
|
||||
lint:
|
||||
(which $(GOBIN)/golangci-lint || go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.19.1)
|
||||
$(GOBIN)/golangci-lint run ./...
|
||||
|
||||
test:
|
||||
go test -cover ./...
|
||||
|
||||
vet:
|
||||
go vet ./...
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
# cmd/config
|
||||
|
||||
This package exists to expose config filters directly as cli commands for the purposes
|
||||
of development of the kyaml package and as a reference implementation for using the libraries.
|
||||
|
||||
## Docs
|
||||
|
||||
All documentation is also built directly into the `config` command group using
|
||||
`kustomize help config`.
|
||||
|
||||
- [tutorials](docs/tutorials)
|
||||
- [commands](docs/commands)
|
||||
- [api-conventions](docs/api-conventions)
|
||||
|
||||
## Build Command
|
||||
|
||||
Build the `config` command under `GOBIN`
|
||||
|
||||
$ make
|
||||
|
||||
## Run Tests
|
||||
|
||||
Run all tests, linting, etc and build
|
||||
|
||||
$ make all
|
||||
@@ -1,72 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package complete
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/posener/complete/v2"
|
||||
"github.com/posener/complete/v2/predict"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
)
|
||||
|
||||
// NewCommand returns a new install-completion command
|
||||
func NewCommand() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "install-completion",
|
||||
Short: commands.CompletionShort,
|
||||
Long: commands.CompletionLong,
|
||||
PreRunE: preRunE,
|
||||
Run: run,
|
||||
}
|
||||
}
|
||||
|
||||
func preRunE(cmd *cobra.Command, args []string) error {
|
||||
// install by default
|
||||
if os.Getenv("COMP_INSTALL") == "" {
|
||||
if err := errors.Wrap(os.Setenv("COMP_INSTALL", "1")); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func run(cmd *cobra.Command, args []string) {
|
||||
// find the root command
|
||||
for cmd.Parent() != nil {
|
||||
cmd = cmd.Parent()
|
||||
}
|
||||
|
||||
// do completion
|
||||
Complete(cmd).Complete("kustomize")
|
||||
}
|
||||
|
||||
// Complete returns a completion command for a cobra command
|
||||
func Complete(cmd *cobra.Command) *complete.Command {
|
||||
cc := &complete.Command{
|
||||
Flags: map[string]complete.Predictor{},
|
||||
Sub: map[string]*complete.Command{},
|
||||
}
|
||||
if strings.Contains(cmd.Use, "DIR") {
|
||||
// if usage contains directory, then use a file predictor
|
||||
cc.Args = predict.Dirs("*")
|
||||
}
|
||||
|
||||
// add completion for each subcommand
|
||||
for i := range cmd.Commands() {
|
||||
c := cmd.Commands()[i]
|
||||
name := strings.Split(c.Use, " ")[0]
|
||||
cc.Sub[name] = Complete(c)
|
||||
}
|
||||
|
||||
// add completion for each flag
|
||||
cmd.Flags().VisitAll(func(flag *pflag.Flag) {
|
||||
cc.Flags[flag.Name] = predict.Nothing
|
||||
})
|
||||
return cc
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package configcobra provides a target for embedding the config command group in another
|
||||
// cobra command.
|
||||
package configcobra
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/kustomize/cmd/config/internal/commands"
|
||||
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/api"
|
||||
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/tutorials"
|
||||
"sigs.k8s.io/kustomize/kyaml/commandutil"
|
||||
)
|
||||
|
||||
var root = &cobra.Command{
|
||||
Use: "config",
|
||||
Short: "[Alpha] Utilities for working with Resource Configuration.",
|
||||
Long: `[Alpha] Utilities for working with Resource Configuration.
|
||||
|
||||
Tutorials:
|
||||
|
||||
Run 'kustomize help config tutorial-TUTORIAL'
|
||||
|
||||
$ kustomize help config tutorials-command-basics
|
||||
|
||||
Command Documentation:
|
||||
|
||||
Run 'kustomize help config CMD'
|
||||
|
||||
$ kustomize help config tree
|
||||
|
||||
Advanced Documentation Topics:
|
||||
|
||||
Run 'kustomize help config docs-TOPIC'
|
||||
|
||||
$ kustomize help config docs-merge
|
||||
$ kustomize help config docs-merge3
|
||||
$ kustomize help config docs-fn
|
||||
$ kustomize help config docs-io-annotations
|
||||
`,
|
||||
}
|
||||
|
||||
// NewConfigCommand returns a new *cobra.Command for the config command group. This may
|
||||
// be embedded into other go binaries as a way of packaging the "config" command as part
|
||||
// of another binary.
|
||||
//
|
||||
// name is substituted into the built-in documentation for each sub-command as the command
|
||||
// invocation prefix -- e.g. if the result is embedded in kustomize, then name should be
|
||||
// "kustomize" and the built-in docs will display "kustomize config" in the examples.
|
||||
//
|
||||
func NewConfigCommand(name string) *cobra.Command {
|
||||
// config command is alpha
|
||||
root.Version = "v0.0.0"
|
||||
|
||||
// Only populate the command if Alpha commands are enabled.
|
||||
if !commandutil.GetAlphaEnabled() {
|
||||
// return the command because other subcommands are added to it
|
||||
root.Short = "[Alpha] To enable set KUSTOMIZE_ENABLE_ALPHA_COMMANDS=true"
|
||||
root.Long = "[Alpha] To enable set KUSTOMIZE_ENABLE_ALPHA_COMMANDS=true"
|
||||
root.Example = ""
|
||||
return root
|
||||
}
|
||||
|
||||
root.PersistentFlags().BoolVar(&commands.StackOnError, "stack-trace", false,
|
||||
"print a stack-trace on failure")
|
||||
|
||||
name = strings.TrimSpace(name + " config")
|
||||
commands.ExitOnError = true
|
||||
root.AddCommand(commands.GrepCommand(name))
|
||||
root.AddCommand(commands.TreeCommand(name))
|
||||
root.AddCommand(commands.CatCommand(name))
|
||||
root.AddCommand(commands.FmtCommand(name))
|
||||
root.AddCommand(commands.MergeCommand(name))
|
||||
root.AddCommand(commands.Merge3Command(name))
|
||||
root.AddCommand(commands.CountCommand(name))
|
||||
root.AddCommand(commands.RunFnCommand(name))
|
||||
root.AddCommand(commands.SetCommand(name))
|
||||
root.AddCommand(commands.ListSettersCommand(name))
|
||||
root.AddCommand(commands.CreateSetterCommand(name))
|
||||
root.AddCommand(commands.SinkCommand(name))
|
||||
root.AddCommand(commands.SourceCommand(name))
|
||||
|
||||
root.AddCommand(&cobra.Command{
|
||||
Use: "docs-merge",
|
||||
Short: "[Alpha] Documentation for merging Resources (2-way merge).",
|
||||
Long: api.Merge2Long,
|
||||
})
|
||||
root.AddCommand(&cobra.Command{
|
||||
Use: "docs-merge3",
|
||||
Short: "[Alpha] Documentation for merging Resources (3-way merge).",
|
||||
Long: api.Merge3Long,
|
||||
})
|
||||
root.AddCommand(&cobra.Command{
|
||||
Use: "docs-fn",
|
||||
Short: "[Alpha] Documentation for developing and invoking Configuration Functions.",
|
||||
Long: api.FunctionsImplLong,
|
||||
})
|
||||
root.AddCommand(&cobra.Command{
|
||||
Use: "docs-fn-spec",
|
||||
Short: "[Alpha] Documentation for Configuration Functions Specification.",
|
||||
Long: api.FunctionsSpecLong,
|
||||
})
|
||||
root.AddCommand(&cobra.Command{
|
||||
Use: "docs-io-annotations",
|
||||
Short: "[Alpha] Documentation for annotations used by io.",
|
||||
Long: api.ConfigIoLong,
|
||||
})
|
||||
|
||||
root.AddCommand(&cobra.Command{
|
||||
Use: "tutorials-command-basics",
|
||||
Short: "[Alpha] Tutorials for using basic config commands.",
|
||||
Long: tutorials.ConfigurationBasicsLong,
|
||||
})
|
||||
|
||||
root.AddCommand(&cobra.Command{
|
||||
Use: "tutorials-function-basics",
|
||||
Short: "[Alpha] Tutorials for using functions.",
|
||||
Long: tutorials.FunctionBasicsLong,
|
||||
})
|
||||
|
||||
return root
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user