Compare commits

..

22 Commits

Author SHA1 Message Date
Phillip Wittrock
d27135e3a3 update go.mod for release 2020-02-19 15:00:57 -08:00
Phillip Wittrock
282b1fa49a Merge remote-tracking branch 'upstream/master' into release-cmd/config-v0.0 2020-02-19 15:00:38 -08:00
Phillip Wittrock
584eb236fd update go.mod for release 2020-02-05 17:46:10 -08:00
Phillip Wittrock
31a193f60f Merge remote-tracking branch 'upstream/master' into release-cmd/config-v0.0 2020-02-05 17:46:04 -08:00
Phillip Wittrock
bf17b244e5 update go.mod for release 2020-01-16 16:24:55 -08:00
Phillip Wittrock
8338299529 Merge remote-tracking branch 'upstream/master' into release-cmd/config-v0.0 2020-01-16 16:24:35 -08:00
Phillip Wittrock
7adf7eb271 update go.mod for release 2020-01-15 18:10:02 -08:00
Phillip Wittrock
06b091b175 Merge remote-tracking branch 'upstream/master' into release-cmd/config-v0.0 2020-01-15 18:09:55 -08:00
Phillip Wittrock
bf03669e94 update go.mod for release 2020-01-13 12:49:07 -08:00
Phillip Wittrock
7f52c814a8 release cmd/config
Merge remote-tracking branch 'upstream/master' into release-cmd/config-v0.0
2020-01-13 12:47:01 -08:00
Phillip Wittrock
d5aac922d9 Merge remote-tracking branch 'upstream/master' into release-cmd/config-v0.0 2020-01-10 16:38:39 -08:00
Phillip Wittrock
9a62d866f3 update go.mod for release 2020-01-09 17:02:34 -08:00
Phillip Wittrock
b2812838bf release cmd/config 0.0.6
Merge remote-tracking branch 'upstream/master' into release-cmd/config-v0.0
2020-01-09 17:02:08 -08:00
Phillip Wittrock
e59e477702 update go.mod for release 2020-01-03 10:01:16 -08:00
Phillip Wittrock
4264ad0ad4 release cmd/config 0.0.5 Merge remote-tracking branch 'upstream/master' into release-cmd/config-v0.0 2020-01-03 10:01:06 -08:00
Phillip Wittrock
2554cd00eb update go.mod for release 2020-01-02 09:02:06 -08:00
Phillip Wittrock
383244cd63 Release cmd/config 0.0.4
Merge remote-tracking branch 'upstream/master' into release-cmd/config-v0.0
2020-01-02 09:01:56 -08:00
Phillip Wittrock
b9da33afd4 update go.mod for release 2019-12-20 09:44:25 -08:00
Phillip Wittrock
23e339b86c Merge remote-tracking branch 'upstream/master' into release-cmd/config-v0.0 2019-12-20 09:44:21 -08:00
Phillip Wittrock
9555009df8 update go.mod for release 2019-12-16 14:21:02 -08:00
Phillip Wittrock
91a10c560c Merge remote-tracking branch 'upstream/master' into release-cmd/config-v0.0 2019-12-16 14:20:58 -08:00
Phillip Wittrock
780cb19c4d drop replace 2019-12-13 13:50:17 -08:00
65 changed files with 951 additions and 3847 deletions

43
.travis.yml Normal file
View File

@@ -0,0 +1,43 @@
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.
# - windows
addons:
apt:
packages:
- tree
homebrew:
packages:
- tree
update: true
# Only clone the most recent commit.
git:
depth: 1
language: go
go:
- "1.13"
go_import_path: sigs.k8s.io/kustomize
before_install:
- source ./travis/consider-early-travis-exit.sh
# Skip the install process; let pre-commit.sh do it.
install: true
script:
- make verify-kustomize
- ./travis/kyaml-pre-commit.sh
- ./travis/check-go-mod.sh
# TBD. Suppressing for now.
notifications:
email: false

View File

@@ -21,10 +21,7 @@ verify-kustomize: \
# https://github.com/kubernetes/test-infra/tree/master/config/jobs/kubernetes-sigs/kustomize
.PHONY: prow-presubmit-check
prow-presubmit-check: \
lint-kustomize \
test-unit-kustomize-all \
test-unit-cmd-all \
test-go-mod
test-unit-kustomize-all
.PHONY: verify-kustomize-e2e
verify-kustomize-e2e: test-examples-e2e-kustomize
@@ -206,12 +203,6 @@ test-unit-kustomize-all: \
test-unit-kustomize-cli \
test-unit-kustomize-plugins
test-unit-cmd-all:
./travis/kyaml-pre-commit.sh
test-go-mod:
./travis/check-go-mod.sh
.PHONY:
test-examples-kustomize-against-HEAD: $(MYGOBIN)/kustomize $(MYGOBIN)/mdrip
./hack/testExamplesAgainstKustomize.sh HEAD

View File

@@ -144,10 +144,8 @@ func (p *ImageTagTransformerPlugin) findContainers(obj map[string]interface{}) e
}
func isImageMatched(s, t string) bool {
// Tag values are limited to [a-zA-Z0-9_.{}-].
// Some tools like Bazel rules_k8s allow tag patterns with {} characters.
// More info: https://github.com/bazelbuild/rules_k8s/pull/423
pattern, _ := regexp.Compile("^" + t + "(@sha256)?(:[a-zA-Z0-9_.{}-]*)?$")
// Tag values are limited to [a-zA-Z0-9_.-].
pattern, _ := regexp.Compile("^" + t + "(@sha256)?(:[a-zA-Z0-9_.-]*)?$")
return pattern.MatchString(s)
}

View File

@@ -114,7 +114,7 @@ type ResMap interface {
Append(*resource.Resource) error
// AppendAll appends another ResMap to self,
// failing on any CurId collision.
// failing on any OrgId collision.
AppendAll(ResMap) error
// AbsorbAll appends, replaces or merges the contents

View File

@@ -1,12 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package ext
import "path/filepath"
// GetOpenAPIFile returns the path to the file containing supplementary OpenAPI definitions.
// Maybe be overridden to configure which file to read OpenAPI definitions from.
var GetOpenAPIFile = func(args []string) (string, error) {
return filepath.Join(args[0], "kustomization"), nil
}

View File

@@ -10,7 +10,5 @@ require (
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.4.0
k8s.io/apimachinery v0.17.0
sigs.k8s.io/kustomize/kyaml v0.0.0
sigs.k8s.io/kustomize/kyaml v0.0.12
)
replace sigs.k8s.io/kustomize/kyaml v0.0.0 => ../../kyaml

View File

@@ -156,15 +156,15 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2 h1:XZx7nhd5GMaZpmDaEHFVafUZC7ya0fuo7cSJ3UCKYmM=
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d h1:LCPbGQ34PMrwad11aMZ+dbz5SAsq/0ySjRwQ8I9Qwd8=
gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/apimachinery v0.17.0 h1:xRBnuie9rXcPxUkDizUsGvPf1cnlZCFu210op7J7LJo=
k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg=
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 v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
sigs.k8s.io/kustomize/kyaml v0.0.12 h1:5HFupVWGTHD4Tfu1+YL+A7oqUujySRkLiTeN1mACpc8=
sigs.k8s.io/kustomize/kyaml v0.0.12/go.mod h1:tDOfJjL6slQVBLHJ76XfXAFgAOEdfm04AW2HehYOp8k=
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=

View File

@@ -5,7 +5,6 @@ package commands
import (
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/setters"
@@ -38,7 +37,8 @@ func NewCreateSetterRunner(parent string) *CreateSetterRunner {
"kind of the Resource on which to create the setter.")
set.Flags().MarkHidden("kind")
set.Flags().StringVar(&r.Set.SetPartialField.Type, "type", "",
"OpenAPI field type for the setter -- e.g. integer,boolean,string.")
"valid OpenAPI field type -- e.g. integer,boolean,string.")
set.Flags().MarkHidden("type")
set.Flags().BoolVar(&r.Set.SetPartialField.Partial, "partial", false,
"create a partial setter for only part of the field value.")
set.Flags().MarkHidden("partial")
@@ -85,10 +85,9 @@ func (r *CreateSetterRunner) preRunE(c *cobra.Command, args []string) error {
}
if setterVersion == "v2" {
var err error
r.OpenAPIFile, err = ext.GetOpenAPIFile(args)
r.OpenAPIFile, err = GetOpenAPIFile(args)
r.CreateSetter.Description = r.Set.SetPartialField.Description
r.CreateSetter.SetBy = r.Set.SetPartialField.SetBy
r.CreateSetter.Type = r.Set.SetPartialField.Type
if err != nil {
return err
}

View File

@@ -11,7 +11,6 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/commands"
"sigs.k8s.io/kustomize/kyaml/openapi"
)
@@ -78,9 +77,7 @@ kind: Example
if !assert.NoError(t, err) {
t.FailNow()
}
old := ext.GetOpenAPIFile
defer func() { ext.GetOpenAPIFile = old }()
ext.GetOpenAPIFile = func(args []string) (s string, err error) {
commands.GetOpenAPIFile = func(args []string) (s string, err error) {
return f.Name(), nil
}

View File

@@ -7,7 +7,6 @@ import (
"strings"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/setters2"
"sigs.k8s.io/kustomize/kyaml/setters2/settersutil"
@@ -59,7 +58,7 @@ func (r *CreateSubstitutionRunner) preRunE(c *cobra.Command, args []string) erro
return err
}
r.OpenAPIFile, err = ext.GetOpenAPIFile(args)
r.OpenAPIFile, err = GetOpenAPIFile(args)
if err != nil {
return err
}

View File

@@ -11,7 +11,6 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/commands"
"sigs.k8s.io/kustomize/kyaml/openapi"
)
@@ -102,72 +101,6 @@ spec:
image: nginx:1.7.9 # {"$ref":"#/definitions/io.k8s.cli.substitutions.image"}
- name: sidecar
image: sidecar:1.7.9
`,
},
{
name: "substitution and create setters 1",
args: []string{
"image", "something/nginx::1.7.9/nginxotherthing", "--pattern", "something/IMAGE::TAG/nginxotherthing",
"--value", "IMAGE=image", "--value", "TAG=tag"},
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
template:
spec:
containers:
- name: nginx
image: something/nginx::1.7.9/nginxotherthing
- name: sidecar
image: sidecar:1.7.9
`,
inputOpenAPI: `
apiVersion: v1alpha1
kind: Example
`,
expectedOpenAPI: `
apiVersion: v1alpha1
kind: Example
openAPI:
definitions:
io.k8s.cli.setters.image:
x-k8s-cli:
setter:
name: image
value: nginx
io.k8s.cli.setters.tag:
x-k8s-cli:
setter:
name: tag
value: 1.7.9
io.k8s.cli.substitutions.image:
x-k8s-cli:
substitution:
name: image
pattern: something/IMAGE::TAG/nginxotherthing
values:
- marker: IMAGE
ref: '#/definitions/io.k8s.cli.setters.image'
- marker: TAG
ref: '#/definitions/io.k8s.cli.setters.tag'
`,
expectedResources: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
template:
spec:
containers:
- name: nginx
image: something/nginx::1.7.9/nginxotherthing # {"$ref":"#/definitions/io.k8s.cli.substitutions.image"}
- name: sidecar
image: sidecar:1.7.9
`,
},
}
@@ -187,9 +120,7 @@ spec:
if !assert.NoError(t, err) {
t.FailNow()
}
old := ext.GetOpenAPIFile
defer func() { ext.GetOpenAPIFile = old }()
ext.GetOpenAPIFile = func(args []string) (s string, err error) {
commands.GetOpenAPIFile = func(args []string) (s string, err error) {
return f.Name(), nil
}

View File

@@ -10,7 +10,6 @@ import (
"github.com/olekukonko/tablewriter"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/kyaml/setters"
"sigs.k8s.io/kustomize/kyaml/setters2"
@@ -56,7 +55,7 @@ func (r *ListSettersRunner) preRunE(c *cobra.Command, args []string) error {
func (r *ListSettersRunner) runE(c *cobra.Command, args []string) error {
if setterVersion == "v2" {
// use setters v2
path, err := ext.GetOpenAPIFile(args)
path, err := GetOpenAPIFile(args)
if err != nil {
return err
}

View File

@@ -10,7 +10,6 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/commands"
"sigs.k8s.io/kustomize/kyaml/openapi"
)
@@ -262,9 +261,7 @@ spec:
t.FailNow()
}
defer os.Remove(f.Name())
old := ext.GetOpenAPIFile
defer func() { ext.GetOpenAPIFile = old }()
ext.GetOpenAPIFile = func(args []string) (s string, err error) {
commands.GetOpenAPIFile = func(args []string) (s string, err error) {
err = ioutil.WriteFile(f.Name(), []byte(test.openapi), 0600)
if !assert.NoError(t, err) {
t.FailNow()

View File

@@ -6,10 +6,10 @@ package commands
import (
"fmt"
"os"
"path/filepath"
"github.com/olekukonko/tablewriter"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/setters"
@@ -43,6 +43,10 @@ func NewSetRunner(parent string) *SetRunner {
var setterVersion string
var GetOpenAPIFile = func(args []string) (string, error) {
return filepath.Join(args[0], "kustomization"), nil
}
func SetCommand(parent string) *cobra.Command {
return NewSetRunner(parent).Command
}
@@ -96,7 +100,7 @@ func (r *SetRunner) preRunE(c *cobra.Command, args []string) error {
r.Set.Value = args[2]
r.Set.Description = r.Perform.Description
r.Set.SetBy = r.Perform.SetBy
r.OpenAPIFile, err = ext.GetOpenAPIFile(args)
r.OpenAPIFile, err = GetOpenAPIFile(args)
if err != nil {
return err
}

View File

@@ -11,7 +11,6 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/commands"
"sigs.k8s.io/kustomize/kyaml/openapi"
)
@@ -109,6 +108,7 @@ openAPI:
setter:
name: replicas
value: "4"
setBy: me
`,
expectedResources: `
apiVersion: apps/v1
@@ -224,9 +224,7 @@ spec:
if !assert.NoError(t, err) {
t.FailNow()
}
old := ext.GetOpenAPIFile
defer func() { ext.GetOpenAPIFile = old }()
ext.GetOpenAPIFile = func(args []string) (s string, err error) {
commands.GetOpenAPIFile = func(args []string) (s string, err error) {
return f.Name(), nil
}

View File

@@ -1,2 +0,0 @@
Copyright {{.Year}} {{.Holder}}
SPDX-License-Identifier: Apache-2.0

View File

@@ -1,42 +0,0 @@
# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
.PHONY: generate license fix vet fmt test build tidy image
GOBIN := $(shell go env GOPATH)/bin
build:
(cd image && go build -v -o $(GOBIN)/config-function .)
all: generate license build fix vet fmt test lint tidy
fix:
(cd image && go fix ./...)
fmt:
(cd image && go fmt ./...)
generate:
(which $(GOBIN)/mdtogo || go get sigs.k8s.io/kustomize/cmd/mdtogo)
(cd image && GOBIN=$(GOBIN) go generate ./...)
license:
(which $(GOPATH)/bin/addlicense || go get github.com/google/addlicense)
$(GOPATH)/bin/addlicense -y 2019 -c "The Kubernetes Authors." -f LICENSE_TEMPLATE .
tidy:
(cd image && go mod tidy)
lint:
(which $(GOBIN)/golangci-lint || go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.19.1)
(cd image && $(GOBIN)/golangci-lint run ./...)
test:
(cd image && go test -cover ./...)
vet:
(cd image && go vet ./...)
image:
docker build image -t gcr.io/kustomize-functions/create-application:v0.1.0
docker push gcr.io/kustomize-functions/create-application:v0.1.0

View File

@@ -1,30 +0,0 @@
# Append Application CR
This is an example of appending an Application CR to a group of resources.
This example is written in `go` and uses the `kyaml` libraries for parsing the
input and writing the output. Writing in `go` is not a requirement.
## Function implementation
The function is implemented as an [image](image), and built using `make image`.
The template is implemented as a go program, which reads a collection of input
Resource configuration, and looks for invalid configuration.
## Function invocation
The function is invoked by authoring a [local Resource](local-resource)
with `metadata.annotations.[config.kubernetes.io/function]` and running:
kustomize config run local-resource/ --fn-path config/
This exits non-zero if there is an error.
## Running the Example
Run the validator with:
kustomize config run local-resource/ --fn-path config/
This will append an Application CR.

View File

@@ -1,13 +0,0 @@
# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
apiVersion: examples.config.kubernetes.io/v1beta1
kind: CreateApp
metadata:
annotations:
config.kubernetes.io/function: |
container:
image: gcr.io/kustomize-functions/create-application:v0.1.0
spec:
managedBy: jingfang
name: example-app
namespace: example-namespace

View File

@@ -1,15 +0,0 @@
# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
FROM golang:1.13-stretch
ENV CGO_ENABLED=0
WORKDIR /go/src/
COPY go.mod .
COPY go.sum .
RUN go mod download
COPY main.go .
RUN go build -v -o /usr/local/bin/config-function ./
FROM alpine:latest
COPY --from=0 /usr/local/bin/config-function /usr/local/bin/config-function
CMD ["config-function"]

View File

@@ -1,13 +0,0 @@
module sigs.k8s.io/kustomize/functions/examples/application-cr
go 1.13
require (
github.com/gogo/protobuf v1.3.1 // indirect
github.com/google/gofuzz v1.1.0 // indirect
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 // indirect
k8s.io/apimachinery v0.17.2
sigs.k8s.io/application v0.8.2-0.20200228023238-a3b16d81fa81
sigs.k8s.io/kustomize/kyaml v0.1.1-0.20200227221838-a24cc4d305f4
sigs.k8s.io/yaml v1.1.0
)

View File

@@ -1,520 +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 h1:ROfEUZz+Gh5pa62DJWXSaonyu3StP6EA6lPEXPI6mCo=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
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/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/coreos/bbolt v1.3.1-coreos.6/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/etcd v3.3.15+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/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/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/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/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M=
github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
github.com/go-logr/zapr v0.1.0 h1:h+WVe9j6HAA01niTJPA/kKH0i7e0rLZBCwauQFcRE54=
github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU=
github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w=
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o=
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs=
github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk=
github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA=
github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64=
github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4=
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY=
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
github.com/go-openapi/spec v0.19.5 h1:Xm0Ao53uqnk9QE/LlYV5DEU09UAgpliA85QoT9LzqPw=
github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk=
github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY=
github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=
github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
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/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef h1:veQD95Isof8w9/WXiA+pa3tz3fJXkt5B7QaRBrM62gk=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.0.0/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/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/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk=
github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU=
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-middleware v0.0.0-20190222133341-cfaf5686ec79/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.3.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
github.com/grpc-ecosystem/grpc-gateway v1.9.5/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 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
github.com/imdario/mergo v0.3.6/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.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok=
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM=
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/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/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.4.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/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.3.0/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
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/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
github.com/prometheus/client_golang v1.0.0 h1:vrDKnkGzuGvhNAL56c7DBz29ZL+KxnoR0x7enabFceM=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw=
github.com/prometheus/common v0.4.1/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-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNGfs=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/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.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/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/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI=
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.uber.org/atomic v0.0.0-20181018215023-8dc6146f7569/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v0.0.0-20180122172545-ddea229ff1df/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v0.0.0-20180814183419-67bc79d13d15/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7 h1:0hQKqeLdqlt5iIwVOBErRisrHJAN57yOiPRQItI20fU=
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
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/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180112015858-5ccada7d0a7b/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-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-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/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-20180117170059-2c42eef0765b/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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-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-20191105231009-c1f44814a5cd h1:3x5uuvBgE6oaXJjCOvpCC1IpgJogqQ+PqGGU3ZxAgII=
golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd/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.20171227012246-e19ae1496984/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gomodules.xyz/jsonpatch/v2 v2.0.1 h1:xyiBuvkD2g5n7cYzx6u2sxQvsAy4QJsZFCzGVdzOXZ0=
gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU=
gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0=
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ=
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 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c=
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/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
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/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
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.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.0.0/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2 h1:XZx7nhd5GMaZpmDaEHFVafUZC7ya0fuo7cSJ3UCKYmM=
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
k8s.io/api v0.0.0-20190918155943-95b840bb6a1f/go.mod h1:uWuOHnjmNrtQomJrvEBg0c0HRNyQ+8KTEERVsK0PW48=
k8s.io/api v0.17.0 h1:H9d/lw+VkZKEVIUc8F3wgiQ+FUXTTr21M87jXLU7yqM=
k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI=
k8s.io/apiextensions-apiserver v0.0.0-20190918161926-8f644eb6e783/go.mod h1:xvae1SZB3E17UpV59AWc271W/Ph25N+bjPyR63X6tPY=
k8s.io/apiextensions-apiserver v0.17.0 h1:+XgcGxqaMztkbbvsORgCmHIb4uImHKvTjNyu7b8gRnA=
k8s.io/apiextensions-apiserver v0.17.0/go.mod h1:XiIFUakZywkUl54fVXa7QTEHcqQz9HG55nHd1DCoHj8=
k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655/go.mod h1:nL6pwRT8NgfF8TT68DBI8uEePRt89cSvoXUVqbkWHq4=
k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg=
k8s.io/apimachinery v0.17.2 h1:hwDQQFbdRlpnnsR64Asdi55GyCaIP/3WQpMmbNBeWr4=
k8s.io/apimachinery v0.17.2/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg=
k8s.io/apiserver v0.0.0-20190918160949-bfa5e2e684ad/go.mod h1:XPCXEwhjaFN29a8NldXA901ElnKeKLrLtREO9ZhFyhg=
k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg=
k8s.io/client-go v0.0.0-20190918160344-1fbdaa4c8d90/go.mod h1:J69/JveO6XESwVgG53q3Uz5OSfgsv4uxpScmmyYOOlk=
k8s.io/client-go v0.17.0 h1:8QOGvUGdqDMFrm9sD6IUFl256BcffynGoe80sxgTEDg=
k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k=
k8s.io/code-generator v0.0.0-20190912054826-cd179ad6a269/go.mod h1:V5BD6M4CyaN5m+VthcclXWsVcT1Hu+glwa1bi3MIsyE=
k8s.io/code-generator v0.17.0/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s=
k8s.io/component-base v0.0.0-20190918160511-547f6c5d7090/go.mod h1:933PBGtQFJky3TEwYx4aEPZ4IxqhWh3R6DCmzqIn1hA=
k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc=
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/gengo v0.0.0-20190822140433-26a664648505/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 v0.4.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
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-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
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-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f h1:GiPwtSzdP43eI1hpPCbROQCCIgCuiMMNF8YUVLF3vJo=
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=
modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I=
sigs.k8s.io/application v0.8.2-0.20200228023238-a3b16d81fa81 h1:UfB69/nuzg30T/EyejFxgIPHjKNbBmNL2rqOrtcV6Cs=
sigs.k8s.io/application v0.8.2-0.20200228023238-a3b16d81fa81/go.mod h1:Mv+ht9RE/QNtITYCzRbt3XTIN6t6so6cInmiyg6wOIg=
sigs.k8s.io/controller-runtime v0.4.0 h1:wATM6/m+3w8lj8FXNaO6Fs/rq/vqoOjO1Q116Z9NPsg=
sigs.k8s.io/controller-runtime v0.4.0/go.mod h1:ApC79lpY3PHW9xj/w9pj+lYkLgwAAUZwfXkME1Lajns=
sigs.k8s.io/kustomize/kyaml v0.1.1-0.20200227221838-a24cc4d305f4 h1:sAwSXsspJa7zmKAmrKlYpkdhoMjQUqA06SdBTvPL0S4=
sigs.k8s.io/kustomize/kyaml v0.1.1-0.20200227221838-a24cc4d305f4/go.mod h1:/NdPPfrperSCGjm55cwEro1loBVtbtVIXSb7FguK6uk=
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA=
sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18=
sigs.k8s.io/testing_frameworks v0.1.2 h1:vK0+tvjF0BZ/RYFeZ1E6BYBwHJJXhjuZ3TdsEKH+UQM=
sigs.k8s.io/testing_frameworks v0.1.2/go.mod h1:ToQrwSC3s8Xf/lADdZp3Mktcql9CG0UAmdJG9th5i0w=
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=

View File

@@ -1,160 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package main implements adding an Application CR to a group of resources and
// is run with `kustomize config run -- DIR/`.
package main
import (
"fmt"
"os"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/application/api/v1beta1"
yaml2 "sigs.k8s.io/yaml"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
func appCR() error {
rw := &kio.ByteReadWriter{
Reader: os.Stdin,
Writer: os.Stdout,
OmitReaderAnnotations: true,
KeepReaderAnnotations: true,
}
p := kio.Pipeline{
Inputs: []kio.Reader{rw}, // read the inputs into a slice
Filters: []kio.Filter{appCRFilter{rw: rw}},
Outputs: []kio.Writer{rw}, // copy the inputs to the output
}
if err := p.Execute(); err != nil {
return err
}
return nil
}
func main() {
if err := appCR(); err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
os.Exit(1)
}
}
// appCRFilter implements kio.Filter
type appCRFilter struct {
rw *kio.ByteReadWriter
}
// define the input API schema as a struct
type API struct {
Spec struct {
ManagedBy string `yaml:"managedBy"`
Name string `yaml:"name"`
Namespace string `yaml:"namespace"`
Descriptor v1beta1.Descriptor `yaml:"descriptor,omitempty"`
} `yaml:"spec"`
}
// Filter checks each resource for validity, otherwise returning an error.
func (f appCRFilter) Filter(in []*yaml.RNode) ([]*yaml.RNode, error) {
api := f.parseAPI()
groupKinds, err := getGroupKinds(in)
if err != nil {
return nil, err
}
app, err := addApplicationCR(api, groupKinds)
if err != nil {
return nil, err
}
err = addApplicationLabel(api.Spec.Name, in)
if err != nil {
return nil, err
}
if app != nil {
return append(in, app), nil
}
return in, nil
}
// parseAPI parses the functionConfig into an API struct.
func (f *appCRFilter) parseAPI() API {
// parse the input function config -- TODO: simplify this
var api API
if err := yaml.Unmarshal([]byte(f.rw.FunctionConfig.MustString()), &api); err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
os.Exit(1)
}
return api
}
func getGroupKinds(in []*yaml.RNode) ([]metav1.GroupKind, error) {
var groupKinds []metav1.GroupKind
for _, r := range in {
meta, err := r.GetMeta()
if err != nil {
return nil, err
}
gvk := schema.FromAPIVersionAndKind(meta.APIVersion, meta.Kind)
found := false
for _, gk := range groupKinds {
if gk.Group == gvk.Group && gk.Kind == gvk.Kind {
break
}
}
if !found {
groupKinds = append(groupKinds, metav1.GroupKind{
Group: gvk.Group,
Kind: gvk.Kind,
})
}
}
return groupKinds, nil
}
func addApplicationCR(api API, groupKinds []metav1.GroupKind) (*yaml.RNode, error) {
app := v1beta1.Application{
TypeMeta: metav1.TypeMeta{
APIVersion: "app.k8s.io/v1beta1",
Kind: "Application",
},
ObjectMeta: metav1.ObjectMeta{
Namespace: api.Spec.Namespace,
Name: api.Spec.Name,
Labels: map[string]string{"app.kubernetes.io/name": api.Spec.Name},
Annotations: map[string]string{"app.kubernetes.io/managed-by": api.Spec.ManagedBy},
},
Spec: v1beta1.ApplicationSpec{
ComponentGroupKinds: groupKinds,
Descriptor: api.Spec.Descriptor,
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{"app.kubernetes.io/name": api.Spec.Name},
},
},
}
data, err := yaml2.Marshal(app)
if err != nil {
return nil, err
}
return yaml.Parse(string(data))
}
func addApplicationLabel(name string, in []*yaml.RNode) error {
for _, r := range in {
if _, err := r.Pipe(yaml.SetLabel("app.kubernetes.io/name", name)); err != nil {
return err
}
}
return nil
}

View File

@@ -1,251 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package main implements adding an Application CR to a group of resources and
// is run with `kustomize config run -- DIR/`.
package main
import (
"bytes"
"io"
"io/ioutil"
"os"
"testing"
)
var input = `apiVersion: config.kubernetes.io/v1alpha1
kind: ResourceList
items:
- apiVersion: v1
kind: ConfigMap
metadata:
name: the-map
annotations:
config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'example.yaml'
data:
altGreeting: "Good Morning!"
enableRisky: "false"
- apiVersion: apps/v1
kind: Deployment
metadata:
name: the-deployment
annotations:
config.kubernetes.io/index: '1'
config.kubernetes.io/path: 'example.yaml'
spec:
replicas: 3
template:
metadata:
labels:
deployment: hello
spec:
containers:
- name: the-container
image: monopole/hello:1
command: ["/hello", "--port=8080", "--enableRiskyFeature=$(ENABLE_RISKY)"]
ports:
- containerPort: 8080
env:
- name: ALT_GREETING
valueFrom:
configMapKeyRef:
name: the-map
key: altGreeting
- name: ENABLE_RISKY
valueFrom:
configMapKeyRef:
name: the-map
key: enableRisky
- kind: Service
apiVersion: v1
metadata:
name: the-service
annotations:
config.kubernetes.io/index: '2'
config.kubernetes.io/path: 'example.yaml'
spec:
selector:
deployment: hello
type: LoadBalancer
ports:
- protocol: TCP
port: 8666
targetPort: 8080
functionConfig:
# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
apiVersion: examples.config.kubernetes.io/v1beta1
kind: CreateApp
spec:
managedBy: jingfang
name: example-app
namespace: example-namespace
descriptor:
links:
- description: About
url: https://worldpress.org/
- description: web server dashboard
url: https://metrics/internal/worldpress-01/web-app
`
var output = `apiVersion: config.kubernetes.io/v1alpha1
kind: ResourceList
items:
- apiVersion: v1
kind: ConfigMap
metadata:
name: the-map
annotations:
config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'example.yaml'
labels:
app.kubernetes.io/name: 'example-app'
data:
altGreeting: "Good Morning!"
enableRisky: "false"
- apiVersion: apps/v1
kind: Deployment
metadata:
name: the-deployment
annotations:
config.kubernetes.io/index: '1'
config.kubernetes.io/path: 'example.yaml'
labels:
app.kubernetes.io/name: 'example-app'
spec:
replicas: 3
template:
metadata:
labels:
deployment: hello
spec:
containers:
- name: the-container
image: monopole/hello:1
command: ["/hello", "--port=8080", "--enableRiskyFeature=$(ENABLE_RISKY)"]
ports:
- containerPort: 8080
env:
- name: ALT_GREETING
valueFrom:
configMapKeyRef:
name: the-map
key: altGreeting
- name: ENABLE_RISKY
valueFrom:
configMapKeyRef:
name: the-map
key: enableRisky
- kind: Service
apiVersion: v1
metadata:
name: the-service
annotations:
config.kubernetes.io/index: '2'
config.kubernetes.io/path: 'example.yaml'
labels:
app.kubernetes.io/name: 'example-app'
spec:
selector:
deployment: hello
type: LoadBalancer
ports:
- protocol: TCP
port: 8666
targetPort: 8080
- apiVersion: app.k8s.io/v1beta1
kind: Application
metadata:
annotations:
app.kubernetes.io/managed-by: jingfang
creationTimestamp: null
labels:
app.kubernetes.io/name: example-app
name: example-app
namespace: example-namespace
spec:
componentKinds:
- group: ""
kind: ConfigMap
- group: apps
kind: Deployment
- group: ""
kind: Service
descriptor:
links:
- description: About
url: https://worldpress.org/
- description: web server dashboard
url: https://metrics/internal/worldpress-01/web-app
selector:
matchLabels:
app.kubernetes.io/name: example-app
status: {}
functionConfig:
# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
apiVersion: examples.config.kubernetes.io/v1beta1
kind: CreateApp
spec:
managedBy: jingfang
name: example-app
namespace: example-namespace
descriptor:
links:
- description: About
url: https://worldpress.org/
- description: web server dashboard
url: https://metrics/internal/worldpress-01/web-app
`
func Test(t *testing.T) {
oldStdin := os.Stdin
oldStdout := os.Stdout
defer func() {
os.Stdin = oldStdin
os.Stdout = oldStdout
}()
r, w, _ := os.Pipe()
os.Stdout = w
outC := make(chan string)
go func() {
var buf bytes.Buffer
_, err := io.Copy(&buf, r)
if err != nil {
outC <- ""
}
outC <- buf.String()
}()
tmpfile, err := ioutil.TempFile("", "test-input")
if err != nil {
t.Fatal(err)
}
defer os.Remove(tmpfile.Name()) // noerrcheck
if _, err := tmpfile.Write([]byte(input)); err != nil {
t.Fatal(err)
}
if _, err := tmpfile.Seek(0, 0); err != nil {
t.Fatal(err)
}
os.Stdin = tmpfile
err = appCR()
if err != nil {
t.Fatal(err)
}
if err := tmpfile.Close(); err != nil {
t.Fatal(err)
}
if err := w.Close(); err != nil {
t.Fatal(err)
}
out := <-outC
if out != output {
t.Fatalf("expected %s\nbut got %s\n", output, out)
}
}

View File

@@ -1,52 +0,0 @@
# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
apiVersion: v1
kind: ConfigMap
metadata:
name: the-map
data:
altGreeting: "Good Morning!"
enableRisky: "false"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: the-deployment
spec:
replicas: 3
template:
metadata:
labels:
deployment: hello
spec:
containers:
- name: the-container
image: monopole/hello:1
command: ["/hello", "--port=8080", "--enableRiskyFeature=$(ENABLE_RISKY)"]
ports:
- containerPort: 8080
env:
- name: ALT_GREETING
valueFrom:
configMapKeyRef:
name: the-map
key: altGreeting
- name: ENABLE_RISKY
valueFrom:
configMapKeyRef:
name: the-map
key: enableRisky
---
kind: Service
apiVersion: v1
metadata:
name: the-service
spec:
selector:
deployment: hello
type: LoadBalancer
ports:
- protocol: TCP
port: 8666
targetPort: 8080

View File

@@ -5,7 +5,6 @@ package fieldmeta
import (
"encoding/json"
"reflect"
"strconv"
"strings"
@@ -37,29 +36,16 @@ type PartialFieldSetter struct {
Value string `yaml:"value" json:"value"`
}
// IsEmpty returns true if the FieldMeta has any empty Schema
func (fm *FieldMeta) IsEmpty() bool {
if fm == nil {
return true
}
return reflect.DeepEqual(fm.Schema, spec.Schema{})
}
// Read reads the FieldMeta from a node
func (fm *FieldMeta) Read(n *yaml.RNode) error {
// check for metadata on head and line comments
comments := []string{n.YNode().LineComment, n.YNode().HeadComment}
for _, c := range comments {
if c == "" {
continue
}
c := strings.TrimLeft(c, "#")
if n.YNode().LineComment != "" {
v := strings.TrimLeft(n.YNode().LineComment, "#")
// if it doesn't Unmarshal that is fine, it means there is no metadata
// other comments are valid, they just don't parse
// TODO: consider more sophisticated parsing techniques similar to what is used
// TODO: consider most sophisticated parsing techniques similar to what is used
// for go struct tags.
if err := fm.Schema.UnmarshalJSON([]byte(c)); err != nil {
if err := fm.Schema.UnmarshalJSON([]byte(v)); err != nil {
// note: don't return an error if the comment isn't a fieldmeta struct
return nil
}

View File

@@ -9,7 +9,6 @@ require (
github.com/sergi/go-diff v1.1.0
github.com/stretchr/testify v1.4.0
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 // indirect
gopkg.in/yaml.v2 v2.2.7
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2
gopkg.in/yaml.v2 v2.2.4
gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d
)

View File

@@ -39,20 +39,18 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/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/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/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/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2 h1:XZx7nhd5GMaZpmDaEHFVafUZC7ya0fuo7cSJ3UCKYmM=
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d h1:LCPbGQ34PMrwad11aMZ+dbz5SAsq/0ySjRwQ8I9Qwd8=
gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -7,7 +7,6 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
"reflect"
"sync"
"github.com/go-openapi/spec"
@@ -33,14 +32,6 @@ type ResourceSchema struct {
Schema *spec.Schema
}
// IsEmpty returns true if the ResourceSchema is empty
func (rs *ResourceSchema) IsEmpty() bool {
if rs == nil || rs.Schema == nil {
return true
}
return reflect.DeepEqual(*rs.Schema, spec.Schema{})
}
// SchemaForResourceType returns the Schema for the given Resource
// TODO(pwittrock): create a version of this function that will return a schema
// which can be used for duck-typed Resources -- e.g. contains common fields such
@@ -202,15 +193,15 @@ func SuppressBuiltInSchemaUse() {
}
// Elements returns the Schema for the elements of an array.
func (rs *ResourceSchema) Elements() *ResourceSchema {
func (r *ResourceSchema) Elements() *ResourceSchema {
// load the schema from swagger.json
initSchema()
if len(rs.Schema.Type) != 1 || rs.Schema.Type[0] != "array" {
if len(r.Schema.Type) != 1 || r.Schema.Type[0] != "array" {
// either not an array, or array has multiple types
return nil
}
s := *rs.Schema.Items.Schema
s := *r.Schema.Items.Schema
for s.Ref.String() != "" {
sc, e := Resolve(&s.Ref)
if e != nil {
@@ -228,8 +219,8 @@ const Elements = "[]"
// Field is called.
// If any Field or Elements call returns nil, then Lookup returns
// nil immediately.
func (rs *ResourceSchema) Lookup(path ...string) *ResourceSchema {
s := rs
func (r *ResourceSchema) Lookup(path ...string) *ResourceSchema {
s := r
for _, p := range path {
if s == nil {
break
@@ -244,19 +235,19 @@ func (rs *ResourceSchema) Lookup(path ...string) *ResourceSchema {
}
// Field returns the Schema for a field.
func (rs *ResourceSchema) Field(field string) *ResourceSchema {
func (r *ResourceSchema) Field(field string) *ResourceSchema {
// load the schema from swagger.json
initSchema()
// locate the Schema
s, found := rs.Schema.Properties[field]
s, found := r.Schema.Properties[field]
switch {
case found:
// no-op, continue with s as the schema
case rs.Schema.AdditionalProperties != nil && rs.Schema.AdditionalProperties.Schema != nil:
case r.Schema.AdditionalProperties != nil && r.Schema.AdditionalProperties.Schema != nil:
// map field type -- use Schema of the value
// (the key doesn't matter, they all have the same value type)
s = *rs.Schema.AdditionalProperties.Schema
s = *r.Schema.AdditionalProperties.Schema
default:
// no Schema found from either swagger.json or line comments
return nil
@@ -276,14 +267,14 @@ func (rs *ResourceSchema) Field(field string) *ResourceSchema {
}
// PatchStrategyAndKey returns the patch strategy and merge key extensions
func (rs *ResourceSchema) PatchStrategyAndKey() (string, string) {
ps, found := rs.Schema.Extensions[kubernetesPatchStrategyExtensionKey]
func (r *ResourceSchema) PatchStrategyAndKey() (string, string) {
ps, found := r.Schema.Extensions[kubernetesPatchStrategyExtensionKey]
if !found {
// merge key and patch strategy must appear together
return "", ""
}
mk, found := rs.Schema.Extensions[kubernetesMergeKeyExtensionKey]
mk, found := r.Schema.Extensions[kubernetesMergeKeyExtensionKey]
if !found {
// merge key and patch strategy must appear together
return "", ""

View File

@@ -104,17 +104,6 @@ type SetterDefinition struct {
// Count is the number of fields set by this setter.
Count int `yaml:"count,omitempty"`
// Type is the type of the setter value.
Type string `yaml:"type,omitempty"`
// EnumValues is a map of possible setter values to actual field values.
// If EnumValues is specified, then the value set the by user 1) MUST
// be present in the enumValues map as a key, and 2) the map entry value
// MUST be used as the value to set in the configuration (rather than the key)
// Example -- may be used for t-shirt sizing values by allowing cpu to be
// set to small, medium or large, and then mapping these values to cpu values -- 0.5, 2, 8
EnumValues map[string]string `yaml:"enumValues,omitempty"`
}
func (sd SetterDefinition) AddToFile(path string) error {
@@ -138,15 +127,6 @@ func (sd SetterDefinition) Filter(object *yaml.RNode) (*yaml.RNode, error) {
sd.Description = ""
}
if sd.Type != "" {
err = def.PipeE(yaml.FieldSetter{Name: "type", StringValue: sd.Type})
if err != nil {
return nil, err
}
// don't write the type to the extension
sd.Type = ""
}
ext, err := def.Pipe(yaml.LookupCreate(yaml.MappingNode, K8sCliExtensionKey))
if err != nil {
return nil, err

View File

@@ -30,7 +30,7 @@ func (s *Set) Filter(object *yaml.RNode) (*yaml.RNode, error) {
// visitScalar
func (s *Set) visitScalar(object *yaml.RNode, p string) error {
// get the openAPI for this field describing how to apply the setter
ext, sch, err := getExtFromComment(object)
ext, err := getExtFromComment(object)
if err != nil {
return err
}
@@ -39,13 +39,13 @@ func (s *Set) visitScalar(object *yaml.RNode, p string) error {
}
// perform a direct set of the field if it matches
if s.set(object, ext, sch) {
if s.set(object, ext) {
s.Count++
return nil
}
// perform a substitution of the field if it matches
sub, err := s.substitute(object, ext, sch)
sub, err := s.substitute(object, ext)
if err != nil {
return err
}
@@ -57,7 +57,7 @@ func (s *Set) visitScalar(object *yaml.RNode, p string) error {
// substitute updates the value of field from ext if ext contains a substitution that
// depends on a setter whose name matches s.Name.
func (s *Set) substitute(field *yaml.RNode, ext *cliExtension, _ *spec.Schema) (bool, error) {
func (s *Set) substitute(field *yaml.RNode, ext *cliExtension) (bool, error) {
nameMatch := false
// check partial setters to see if they contain the setter as part of a
@@ -86,15 +86,8 @@ func (s *Set) substitute(field *yaml.RNode, ext *cliExtension, _ *spec.Schema) (
if err != nil {
return false, errors.Wrap(err)
}
if val, found := subSetter.Setter.EnumValues[subSetter.Setter.Value]; found {
// the setter has an enum-map. we should replace the marker with the
// enum value looked up from the map rather than the enum key
p = strings.ReplaceAll(p, v.Marker, val)
} else {
// substitute the setters current value into the substitution pattern
p = strings.ReplaceAll(p, v.Marker, subSetter.Setter.Value)
}
// substitute the setters current value into the substitution pattern
p = strings.ReplaceAll(p, v.Marker, subSetter.Setter.Value)
if subSetter.Setter.Name == s.Name {
// the substitution depends on the specified setter
@@ -109,15 +102,11 @@ func (s *Set) substitute(field *yaml.RNode, ext *cliExtension, _ *spec.Schema) (
// TODO(pwittrock): validate the field value
field.YNode().Value = p
// substitutions are always strings
field.YNode().Tag = "!!str"
return true, nil
}
// set applies the value from ext to field if its name matches s.Name
func (s *Set) set(field *yaml.RNode, ext *cliExtension, sch *spec.Schema) bool {
func (s *Set) set(field *yaml.RNode, ext *cliExtension) bool {
// check full setter
if ext.Setter == nil || ext.Setter.Name != s.Name {
return false
@@ -125,18 +114,8 @@ func (s *Set) set(field *yaml.RNode, ext *cliExtension, sch *spec.Schema) bool {
// TODO(pwittrock): validate the field value
if val, found := ext.Setter.EnumValues[ext.Setter.Value]; found {
// the setter has an enum-map. we should replace the marker with the
// enum value looked up from the map rather than the enum key
field.YNode().Value = val
return true
}
// this has a full setter, set its value
field.YNode().Value = ext.Setter.Value
// format the node so it is quoted if it is a string
yaml.FormatNonStringStyle(field.YNode(), *sch)
return true
}
@@ -167,50 +146,14 @@ func (s SetOpenAPI) Filter(object *yaml.RNode) (*yaml.RNode, error) {
if def == nil {
return nil, errors.Errorf("no setter %s found", s.Name)
}
// if the setter contains an enumValues map, then ensure the set value appears
// as a key in the map
if values, err := def.Pipe(yaml.Lookup("enumValues")); err != nil {
// error looking up the enumValues
if err := def.PipeE(&yaml.FieldSetter{Name: "value", StringValue: s.Value}); err != nil {
return nil, err
} else if values != nil {
// contains enumValues map -- validate the set value against the map entries
}
// get the enumValues keys
fields, err := values.Fields()
if err != nil {
if s.SetBy != "" {
if err := def.PipeE(&yaml.FieldSetter{Name: "setBy", StringValue: s.SetBy}); err != nil {
return nil, err
}
// search for the user provided value in the set of allowed values
var match bool
for i := range fields {
if fields[i] == s.Value {
// found a match, we are good
match = true
break
}
}
if !match {
// no match found -- provide an informative error to the user
return nil, errors.Errorf("%s does not match the possible values for %s: [%s]",
s.Value, s.Name, strings.Join(fields, ","))
}
}
v := yaml.NewScalarRNode(s.Value)
// values are always represented as strings the OpenAPI
// since the are unmarshalled into strings. Use double quote style to
// ensure this consistently.
v.YNode().Tag = "!!str"
v.YNode().Style = yaml.DoubleQuotedStyle
if err := def.PipeE(&yaml.FieldSetter{Name: "value", Value: v}); err != nil {
return nil, err
}
if err := def.PipeE(&yaml.FieldSetter{Name: "setBy", StringValue: s.SetBy}); err != nil {
return nil, err
}
if s.Description != "" {

View File

@@ -15,12 +15,11 @@ import (
func TestSet_Filter(t *testing.T) {
var tests = []struct {
name string
description string
setter string
openapi string
input string
expected string
name string
setter string
openapi string
input string
expected string
}{
{
name: "set-replicas",
@@ -59,184 +58,6 @@ metadata:
name: nginx-deployment
spec:
replicas: 4 # {"$ref": "#/definitions/io.k8s.cli.setters.replicas"}
`,
},
{
name: "set-foo-type",
description: "if a type is specified for a setter, ensure the field is properly quoted",
setter: "foo",
openapi: `
openAPI:
definitions:
io.k8s.cli.setters.foo:
x-k8s-cli:
setter:
name: foo
value: "4"
type: string
`,
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
annotations:
foo: 3 # {"$ref": "#/definitions/io.k8s.cli.setters.foo"}
`,
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
annotations:
foo: "4" # {"$ref": "#/definitions/io.k8s.cli.setters.foo"}
`,
},
{
name: "set-foo-type-wrong",
description: "if a type is specified for a setter, for the field to the type",
setter: "foo",
openapi: `
openAPI:
definitions:
io.k8s.cli.setters.foo:
x-k8s-cli:
setter:
name: foo
value: "4"
type: boolean
`,
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
annotations:
foo: 3 # {"$ref": "#/definitions/io.k8s.cli.setters.foo"}
`,
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
annotations:
foo: !!bool 4 # {"$ref": "#/definitions/io.k8s.cli.setters.foo"}
`,
},
{
name: "set-foo-no-type",
description: "if a type is not specified for a setter, keep the existing quoting",
setter: "foo",
openapi: `
openAPI:
definitions:
io.k8s.cli.setters.foo:
x-k8s-cli:
setter:
name: foo
value: "4"
`,
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
annotations:
foo: 3 # {"$ref": "#/definitions/io.k8s.cli.setters.foo"}
`,
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
annotations:
foo: 4 # {"$ref": "#/definitions/io.k8s.cli.setters.foo"}
`,
},
{
name: "set-replicas-enum",
setter: "replicas",
openapi: `
openAPI:
definitions:
io.k8s.cli.setters.no-match-1':
x-k8s-cli:
setter:
name: no-match-1
value: "1"
io.k8s.cli.setters.replicas:
x-k8s-cli:
setter:
name: replicas
value: "medium"
enumValues:
small: "1"
medium: "5"
large: "50"
io.k8s.cli.setters.no-match-2':
x-k8s-cli:
setter:
name: no-match-2
value: "2"
`,
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1 # {"$ref": "#/definitions/io.k8s.cli.setters.replicas"}
`,
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 5 # {"$ref": "#/definitions/io.k8s.cli.setters.replicas"}
`,
},
{
name: "set-replicas-enum-large",
setter: "replicas",
openapi: `
openAPI:
definitions:
io.k8s.cli.setters.no-match-1':
x-k8s-cli:
setter:
name: no-match-1
value: "1"
io.k8s.cli.setters.replicas:
x-k8s-cli:
setter:
name: replicas
value: "large"
enumValues:
small: "1"
medium: "5"
large: "50"
io.k8s.cli.setters.no-match-2':
x-k8s-cli:
setter:
name: no-match-2
value: "2"
`,
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1 # {"$ref": "#/definitions/io.k8s.cli.setters.replicas"}
`,
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 50 # {"$ref": "#/definitions/io.k8s.cli.setters.replicas"}
`,
},
{
@@ -334,61 +155,6 @@ spec:
containers:
- name: nginx
image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
`,
},
{
name: "substitute-image-name-enum",
setter: "image-tag",
openapi: `
openAPI:
definitions:
io.k8s.cli.setters.image-name:
x-k8s-cli:
setter:
name: image-name
value: "helloworld"
enumValues:
nginx: gcr.io/nginx
helloworld: us.gcr.io/helloworld
io.k8s.cli.setters.image-tag:
x-k8s-cli:
setter:
name: image-tag
value: "1.8.1"
io.k8s.cli.substitutions.image:
x-k8s-cli:
substitution:
name: image
pattern: IMAGE_NAME:IMAGE_TAG
values:
- marker: "IMAGE_NAME"
ref: "#/definitions/io.k8s.cli.setters.image-name"
- marker: "IMAGE_TAG"
ref: "#/definitions/io.k8s.cli.setters.image-tag"
`,
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
template:
spec:
containers:
- name: nginx
image: nginx:1.7.9 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
`,
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
template:
spec:
containers:
- name: nginx
image: us.gcr.io/helloworld:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
`,
},
{
@@ -725,29 +491,6 @@ openAPI:
setter:
name: no-match-2
value: "2"
`,
},
{
name: "set-annotation-quoted",
setter: "replicas",
value: "3",
input: `
openAPI:
definitions:
io.k8s.cli.setters.replicas:
x-k8s-cli:
setter:
name: replicas
value: 4
`,
expected: `
openAPI:
definitions:
io.k8s.cli.setters.replicas:
x-k8s-cli:
setter:
name: replicas
value: "3"
`,
},
{
@@ -840,137 +583,6 @@ openAPI:
value: "2"
`,
},
{
name: "set-replicas-set-by-empty",
setter: "replicas",
value: "3",
input: `
openAPI:
definitions:
io.k8s.cli.setters.no-match-1':
x-k8s-cli:
setter:
name: no-match-1
value: "1"
setBy: "package-default"
io.k8s.cli.setters.replicas:
x-k8s-cli:
setter:
name: replicas
value: "4"
setBy: "package-default"
io.k8s.cli.setters.no-match-2':
x-k8s-cli:
setter:
name: no-match-2
value: "2"
setBy: "package-default"
`,
expected: `
openAPI:
definitions:
io.k8s.cli.setters.no-match-1':
x-k8s-cli:
setter:
name: no-match-1
value: "1"
setBy: "package-default"
io.k8s.cli.setters.replicas:
x-k8s-cli:
setter:
name: replicas
value: "3"
io.k8s.cli.setters.no-match-2':
x-k8s-cli:
setter:
name: no-match-2
value: "2"
setBy: "package-default"
`,
},
{
name: "set-replicas-with-enum",
setter: "replicas",
value: "baz",
input: `
openAPI:
definitions:
io.k8s.cli.setters.no-match-1':
x-k8s-cli:
setter:
name: no-match-1
value: "1"
setBy: "package-default"
io.k8s.cli.setters.replicas:
x-k8s-cli:
setter:
name: replicas
value: "foo"
enumValues:
foo: bar
baz: biz
io.k8s.cli.setters.no-match-2':
x-k8s-cli:
setter:
name: no-match-2
value: "2"
setBy: "package-default"
`,
expected: `
openAPI:
definitions:
io.k8s.cli.setters.no-match-1':
x-k8s-cli:
setter:
name: no-match-1
value: "1"
setBy: "package-default"
io.k8s.cli.setters.replicas:
x-k8s-cli:
setter:
name: replicas
value: "baz"
enumValues:
foo: bar
baz: biz
io.k8s.cli.setters.no-match-2':
x-k8s-cli:
setter:
name: no-match-2
value: "2"
setBy: "package-default"
`,
},
{
name: "set-replicas-fail",
setter: "replicas",
value: "hello",
input: `
openAPI:
definitions:
io.k8s.cli.setters.no-match-1':
x-k8s-cli:
setter:
name: no-match-1
value: "1"
setBy: "package-default"
io.k8s.cli.setters.replicas:
x-k8s-cli:
setter:
name: replicas
value: "foo"
enumValues:
foo: bar
baz: biz
io.k8s.cli.setters.no-match-2':
x-k8s-cli:
setter:
name: no-match-2
value: "2"
setBy: "package-default"
`,
err: "hello does not match the possible values for replicas: [foo,baz]",
},
{
name: "error",
setter: "replicas",

View File

@@ -19,8 +19,6 @@ type SetterCreator struct {
SetBy string
Type string
// FieldName if set will add the OpenAPI reference to fields with this name or path
// FieldName may be the full name of the field, full path to the field, or the path suffix.
// e.g. all of the following would match spec.template.spec.containers.image --
@@ -37,9 +35,7 @@ type SetterCreator struct {
func (c SetterCreator) Create(openAPIPath, resourcesPath string) error {
// Update the OpenAPI definitions to hace the setter
sd := setters2.SetterDefinition{
Name: c.Name, Value: c.FieldValue, Description: c.Description, SetBy: c.SetBy,
Type: c.Type,
}
Name: c.Name, Value: c.FieldValue, Description: c.Description, SetBy: c.SetBy}
if err := sd.AddToFile(openAPIPath); err != nil {
return err
}

View File

@@ -4,13 +4,9 @@
package settersutil
import (
"strings"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/openapi"
"sigs.k8s.io/kustomize/kyaml/setters2"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
// SubstitutionCreator creates or updates a substitution in the OpenAPI definitions, and
@@ -44,12 +40,6 @@ func (c SubstitutionCreator) Create(openAPIPath, resourcesPath string) error {
Values: c.Values,
Pattern: c.Pattern,
}
err := c.CreateSettersForSubstitution(openAPIPath)
if err != nil {
return err
}
if err := d.AddToFile(openAPIPath); err != nil {
return err
}
@@ -72,187 +62,3 @@ func (c SubstitutionCreator) Create(openAPIPath, resourcesPath string) error {
Outputs: []kio.Writer{inout},
}.Execute()
}
// CreateSettersForSubstitution creates the setters for all the references in the substitution
// values if they don't already exist in openAPIPath file.
func (c SubstitutionCreator) CreateSettersForSubstitution(openAPIPath string) error {
y, err := yaml.ReadFile(openAPIPath)
if err != nil {
return err
}
m, err := c.GetValuesForMarkers()
if err != nil {
return err
}
// for each ref in values, check if the setter already exists, if not create them
for _, value := range c.Values {
obj, err := y.Pipe(yaml.Lookup(
// get the setter key from ref. Ex: from #/definitions/io.k8s.cli.setters.image_setter
// extract io.k8s.cli.setters.image_setter
"openAPI", "definitions", strings.TrimPrefix(value.Ref, "#/definitions/")))
if err != nil {
return err
}
if obj == nil {
sd := setters2.SetterDefinition{
// get the setter name from ref. Ex: from #/definitions/io.k8s.cli.setters.image_setter
// extract image_setter
Name: strings.TrimPrefix(value.Ref, "#/definitions/io.k8s.cli.setters."),
Value: m[value.Marker],
}
err := sd.AddToFile(openAPIPath)
if err != nil {
return err
}
}
}
return nil
}
// GetValuesForMarkers parses the pattern and field value to derive values for the
// markers in the pattern string. Returns error if the marker values can't be derived
func (c SubstitutionCreator) GetValuesForMarkers() (map[string]string, error) {
m := make(map[string]string)
indices, err := c.GetStartIndices()
if err != nil {
return nil, err
}
fv := c.FieldValue
pattern := c.Pattern
fvInd := 0
patternInd := 0
// iterate fv, pattern with indices fvInd, patternInd respectively and when patternInd hits the index of a marker,
// freeze patternInd and iterate fvInd and capture string till we find the substring just after current marker
// and before next marker
// Ex: fv = "something/ubuntu:0.1.0", pattern = "something/IMAGE:VERSION", till patternInd reaches 10
// just proceed fvInd and patternInd and check if fv[fvInd]==pattern[patternInd] when patternInd is 10,
// freeze patternInd and move fvInd till it sees substring ':' which derives IMAGE = ubuntu and so on.
for fvInd < len(fv) && patternInd < len(pattern) {
// if we hit marker index, extract its corresponding value
if marker, ok := indices[patternInd]; ok {
// increment the patternInd to end of marker. This helps us to extract the substring before next marker.
patternInd += len(marker)
var value string
if value, fvInd, err = c.extractValueForMarker(fvInd, fv, patternInd, indices); err != nil {
return nil, err
}
// if marker is repeated in the pattern, make sure that the corresponding values
// are same and throw error if not.
if prevValue, ok := m[marker]; ok && prevValue != value {
return nil, errors.Errorf(
"marker %s is found to have different values %s and %s", marker, prevValue, value)
}
m[marker] = value
} else {
// Ex: fv = "samething/ubuntu:0.1.0" pattern = "something/IMAGE:VERSION". Error out at 'a' in fv.
if fv[fvInd] != pattern[patternInd] {
return nil, errors.Errorf(
"unable to derive values for markers, " +
"create setters for all markers and then try again")
}
fvInd++
patternInd++
}
}
// check if both strings are completely visited or throw error
if fvInd < len(fv) || patternInd < len(pattern) {
return nil, errors.Errorf(
"unable to derive values for markers, " +
"create setters for all markers and then try again")
}
return m, nil
}
// GetStartIndices returns the start indices of all the markers in the pattern
func (c SubstitutionCreator) GetStartIndices() (map[int]string, error) {
indices := make(map[int]string)
for _, value := range c.Values {
found := false
for i := range c.Pattern {
if strings.HasPrefix(c.Pattern[i:], value.Marker) {
indices[i] = value.Marker
found = true
}
}
if !found {
return nil, errors.Errorf("unable to find marker " + value.Marker + " in the pattern")
}
}
if err := validateMarkers(indices); err != nil {
return nil, err
}
return indices, nil
}
// validateMarkers takes the indices map, checks if any of 2 markers not have delimiters,
// checks if any marker is substring of other and returns error
func validateMarkers(indices map[int]string) error {
for k1, v1 := range indices {
for k2, v2 := range indices {
if k1 != k2 && k1+len(v1) == k2 {
return errors.Errorf(
"markers %s and %s are found to have no delimiters between them,"+
" pre-create setters and try again", v1, v2)
}
if v1 != v2 && strings.Contains(v1, v2) {
return errors.Errorf(
"markers %s is substring of %s,"+
" no marker should be substring of other", v2, v1)
}
}
}
return nil
}
// extractValueForMarker returns the value string for a marker and the incremented index
func (c SubstitutionCreator) extractValueForMarker(fvInd int, fv string, patternInd int, indices map[int]string) (string, int, error) {
nonMarkerStr := strTillNextMarker(indices, patternInd, c.Pattern)
// return the remaining string of fv till end if patternInd is at end of pattern
if patternInd == len(c.Pattern) {
return fv[fvInd:], len(fv), nil
}
// split remaining fv starting from fvInd with the non marker substring delimiter and get the first value
// In example fv = "something/ubuntu::0.1.0", pattern = "something/IMAGE::VERSION",
// split with "::" delimiter in fv which gives markerValue = ubuntu for marker IMAGE
// increment fvInd by length of extracted marker value and return fvInd
if markerValues := strings.Split(fv[fvInd:], nonMarkerStr); len(markerValues) > 0 {
return markerValues[0], fvInd + len(markerValues[0]), nil
}
return "", -1, errors.Errorf(
"unable to derive values for markers," +
" create setters for all markers and then try again")
}
// substrOfLen takes a string, start index and length and returns substring of given length
// or till end of string
func substrOfLen(str string, startInd int, length int) string {
return str[startInd:min(len(str), startInd+length)]
}
// strTillNextMarker takes in the indices map, a start index and returns the substring till
// start of next marker
func strTillNextMarker(indices map[int]string, startInd int, pattern string) string {
// initialize with max value which is length of pattern
nextMarkerStartInd := len(pattern)
for ind := range indices {
if ind > startInd {
nextMarkerStartInd = min(ind-startInd, nextMarkerStartInd)
}
}
return substrOfLen(pattern, startInd, nextMarkerStartInd)
}
func min(a int, b int) int {
if a < b {
return a
}
return b
}

View File

@@ -1,111 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package settersutil
import (
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/setters2"
)
func TestGetValuesForMarkers(t *testing.T) {
var tests = []struct {
name string
pattern string
fieldValue string
markers []string
expectedError error
expectedOutput map[string]string
}{
{
name: "positive example",
markers: []string{"IMAGE", "VERSION"},
pattern: "something/IMAGE::VERSION/otherthing/IMAGE::VERSION/",
fieldValue: "something/nginx::0.1.0/otherthing/nginx::0.1.0/",
expectedOutput: map[string]string{"IMAGE": "nginx", "VERSION": "0.1.0"},
},
{
name: "marker with different values",
markers: []string{"IMAGE", "VERSION"},
pattern: "something/IMAGE:VERSION/IMAGE",
fieldValue: "something/nginx:0.1.0/ubuntu",
expectedError: errors.Errorf("marker IMAGE is found to have different values nginx and ubuntu"),
},
{
name: "unmatched pattern",
markers: []string{"IMAGE", "VERSION"},
pattern: "something/IMAGE:VERSION",
fieldValue: "otherthing/nginx:0.1.0",
expectedError: errors.Errorf("unable to derive values for markers"),
},
{
name: "unmatched pattern at the end",
markers: []string{"IMAGE", "VERSION"},
pattern: "something/IMAGE:VERSION/abc",
fieldValue: "something/nginx:0.1.0/abcd",
expectedError: errors.Errorf("unable to derive values for markers"),
},
{
name: "substring markers",
markers: []string{"IMAGE", "VERSION", "MAGE"},
pattern: "something/IMAGE:VERSION/abc/MAGE",
fieldValue: "something/nginx:0.1.0/abc/ubuntu",
expectedError: errors.Errorf("no marker should be substring of other"),
},
{
name: "markers with no delimiters",
markers: []string{"IMAGE", "VERSION"},
pattern: "something/IMAGEVERSION/",
fieldValue: "something/nginx0.1.0/",
expectedError: errors.Errorf("no delimiters between them"),
},
{
name: "unmatched delimiter",
markers: []string{"IMAGE", "VERSION"},
pattern: "something/IMAGE:^VERSION/otherthing/IMAGE::VERSION/",
fieldValue: "something/nginx::0.1.0/otherthing/nginx::0.1.0/",
expectedError: errors.Errorf("unable to derive values for markers"),
},
}
for i := range tests {
test := tests[i]
t.Run(test.name, func(t *testing.T) {
values := []setters2.Value{}
for _, marker := range test.markers {
value := setters2.Value{
Marker: marker,
}
values = append(values, value)
}
sc := SubstitutionCreator{
Pattern: test.pattern,
Values: values,
FieldValue: test.fieldValue,
}
m, err := sc.GetValuesForMarkers()
if test.expectedError == nil {
// fail if expectedError is nil but actual error is not
if !assert.NoError(t, err) {
t.FailNow()
}
// check if all the expected markers and values are present in actual map
for k, v := range test.expectedOutput {
if val, ok := m[k]; ok {
assert.Equal(t, v, val)
} else {
t.FailNow()
}
}
} else {
//if expectedError is not nil, check for correctness of error message
assert.Contains(t, err.Error(), test.expectedError.Error())
}
})
}
}

View File

@@ -19,9 +19,8 @@ type cliExtension struct {
}
type setter struct {
Name string `yaml:"name,omitempty" json:"name,omitempty"`
Value string `yaml:"value,omitempty" json:"value,omitempty"`
EnumValues map[string]string `yaml:"enumValues,omitempty" json:"enumValues,omitempty"`
Name string `yaml:"name,omitempty" json:"name,omitempty"`
Value string `yaml:"value,omitempty" json:"value,omitempty"`
}
type substitution struct {
@@ -57,32 +56,32 @@ func getExtFromSchema(schema *spec.Schema) (*cliExtension, error) {
// getExtFromComment returns the cliExtension openAPI extension if it is present as
// a comment on the field.
func getExtFromComment(object *yaml.RNode) (*cliExtension, *spec.Schema, error) {
func getExtFromComment(object *yaml.RNode) (*cliExtension, error) {
// TODO(pwittrock): also use path to the field to get openapi, not just comments
// parse comment containing the extended openapi for this field
fm := fieldmeta.FieldMeta{}
if err := fm.Read(object); err != nil {
return nil, nil, errors.Wrap(err)
return nil, errors.Wrap(err)
}
if fm.Schema.Ref.String() == "" {
return nil, nil, nil
return nil, nil
}
// resolve the comment reference to the extended openapi definitions
r, err := openapi.Resolve(&fm.Schema.Ref)
if err != nil {
return nil, nil, errors.Wrap(err)
return nil, errors.Wrap(err)
}
if r == nil {
// no schema found
// TODO(pwittrock): should this be an error if it doesn't resolve?
return nil, nil, nil
return nil, nil
}
// get the cli extension from the openapi (contains setter information)
ext, err := getExtFromSchema(r)
if err != nil {
return nil, nil, errors.Wrap(err)
return nil, errors.Wrap(err)
}
return ext, r, nil
return ext, nil
}

View File

@@ -15,7 +15,6 @@ var Filters = map[string]func() Filter{
"AnnotationClearer": func() Filter { return &AnnotationClearer{} },
"AnnotationGetter": func() Filter { return &AnnotationGetter{} },
"AnnotationSetter": func() Filter { return &AnnotationSetter{} },
"LabelSetter": func() Filter { return &LabelSetter{} },
"ElementAppender": func() Filter { return &ElementAppender{} },
"ElementMatcher": func() Filter { return &ElementMatcher{} },
"FieldClearer": func() Filter { return &FieldClearer{} },

View File

@@ -68,25 +68,3 @@ func (g AnnotationGetter) Filter(rn *RNode) (*RNode, error) {
func GetAnnotation(key string) AnnotationGetter {
return AnnotationGetter{Key: key}
}
// LabelSetter sets a label at metadata.labels.
// Creates metadata.labels if does not exist.
type LabelSetter struct {
Kind string `yaml:"kind,omitempty"`
Key string `yaml:"key,omitempty"`
Value string `yaml:"value,omitempty"`
}
func (s LabelSetter) Filter(rn *RNode) (*RNode, error) {
// some tools get confused about the type if labels are not quoted
v := NewScalarRNode(s.Value)
v.YNode().Tag = "!!str"
v.YNode().Style = yaml.SingleQuotedStyle
return rn.Pipe(
PathGetter{Path: []string{"metadata", "labels"}, Create: yaml.MappingNode},
FieldSetter{Name: s.Key, Value: v})
}
func SetLabel(key, value string) LabelSetter {
return LabelSetter{Key: key, Value: value}
}

View File

@@ -1,63 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package yaml
import (
"testing"
)
var input = `apiVersion: v1
kind: ConfigMap
metadata:
name: the-map
data:
altGreeting: "Good Morning!"
enableRisky: "false"
`
func TestSetLabel(t *testing.T) {
rn := MustParse(input)
_, err := rn.Pipe(SetLabel("foo", "bar"))
if err != nil {
t.Fatalf("unexpected error %v", err)
}
output := rn.MustString()
expected := `apiVersion: v1
kind: ConfigMap
metadata:
name: the-map
labels:
foo: 'bar'
data:
altGreeting: "Good Morning!"
enableRisky: "false"
`
if output != expected {
t.Fatalf("expected \n%s\nbut got \n%s\n", expected, output)
}
}
func TestAnnotation(t *testing.T) {
rn := MustParse(input)
_, err := rn.Pipe(SetAnnotation("foo", "bar"))
if err != nil {
t.Fatalf("unexpected error %v", err)
}
output := rn.MustString()
expected := `apiVersion: v1
kind: ConfigMap
metadata:
name: the-map
annotations:
foo: 'bar'
data:
altGreeting: "Good Morning!"
enableRisky: "false"
`
if output != expected {
t.Fatalf("expected \n%s\nbut got \n%s\n", expected, output)
}
}

View File

@@ -4,461 +4,251 @@
package merge2_test
var elementTestCases = []testCase{
{description: `merge Element -- keep field in dest`,
source: `
apiVersion: apps/v1
{`merge Element -- keep field in dest`,
`
kind: Deployment
spec:
template:
spec:
containers:
- name: foo
image: foo:v1
`,
dest: `
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: foo
image: foo:v0
command: ['run.sh']
`,
expected: `
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: foo
image: foo:v1
command: ['run.sh']
`,
},
{description: `merge Element -- add field to dest`,
source: `
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: foo
image: foo:v1
command: ['run.sh']
`,
dest: `
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: foo
image: foo:v0
`,
expected: `
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: foo
image: foo:v1
command: ['run.sh']
`,
},
{description: `merge Element -- add list, empty in dest`,
source: `
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: foo
image: foo:v1
command: ['run.sh']
`,
dest: `
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers: []
`,
expected: `
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: foo
image: foo:v1
command: ['run.sh']
`,
},
{description: `merge Element -- add list, missing from dest`,
source: `
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: foo
image: foo:v1
command: ['run.sh']
`,
dest: `
apiVersion: apps/v1
kind: Deployment
`,
expected: `
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: foo
image: foo:v1
command: ['run.sh']
`,
},
{description: `merge Element -- add Element first`,
source: `
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: bar
image: bar:v1
command: ['run2.sh']
- name: foo
image: foo:v1
`,
dest: `
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: foo
image: foo:v0
`,
expected: `
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: foo
image: foo:v1
- name: bar
image: bar:v1
command: ['run2.sh']
`,
},
{description: `merge Element -- add Element second`,
source: `
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: foo
image: foo:v1
- name: bar
image: bar:v1
command: ['run2.sh']
`,
dest: `
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: foo
image: foo:v0
`,
expected: `
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: foo
image: foo:v1
- name: bar
image: bar:v1
command: ['run2.sh']
`,
},
//
// Test Case
//
{description: `keep list -- list missing from src`,
source: `
apiVersion: apps/v1
kind: Deployment
`,
dest: `
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: foo
image: foo:v1
- name: bar
image: bar:v1
command: ['run2.sh']
`,
expected: `
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: foo
image: foo:v1
- name: bar
image: bar:v1
command: ['run2.sh']
`,
},
//
// Test Case
//
{description: `keep Element -- element missing in src`,
source: `
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: foo
image: foo:v1
`,
dest: `
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: foo
image: foo:v0
- name: bar
image: bar:v1
command: ['run2.sh']
`,
expected: `
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: foo
image: foo:v1
- name: bar
image: bar:v1
command: ['run2.sh']
`,
},
//
// Test Case
//
{description: `keep element -- empty list in src`,
source: `
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers: {}
`,
dest: `
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: foo
image: foo:v1
- name: bar
image: bar:v1
command: ['run2.sh']
`,
expected: `
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: foo
image: foo:v1
- name: bar
image: bar:v1
command: ['run2.sh']
`,
},
//
// Test Case
//
{description: `remove Element -- null in src`,
source: `
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers: null
`,
dest: `
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: foo
image: foo:v1
- name: bar
image: bar:v1
command: ['run2.sh']
`,
expected: `
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec: {}
`,
},
//
// Test Case
//
{description: `infer merge keys merge'`,
source: `
apiVersion: custom
kind: Deployment
containers:
items:
- name: foo
image: foo:v1
`,
`
kind: Deployment
items:
- name: foo
image: foo:v0
command: ['run.sh']
`,
`
kind: Deployment
items:
- name: foo
image: foo:v1
command: ['run.sh']
`,
},
{`merge Element -- add field to dest`,
`
kind: Deployment
items:
- name: foo
image: foo:v1
command: ['run.sh']
`,
`
kind: Deployment
items:
- name: foo
image: foo:v0
`,
`
kind: Deployment
items:
- name: foo
image: foo:v1
command: ['run.sh']
`,
},
{`merge Element -- add list, empty in dest`,
`
kind: Deployment
items:
- name: foo
image: foo:v1
command: ['run.sh']
`,
`
kind: Deployment
items: []
`,
`
kind: Deployment
items:
- name: foo
image: foo:v1
command: ['run.sh']
`,
},
{`merge Element -- add list, missing from dest`,
`
kind: Deployment
items:
- name: foo
image: foo:v1
command: ['run.sh']
`,
`
kind: Deployment
`,
`
kind: Deployment
items:
- name: foo
image: foo:v1
command: ['run.sh']
`,
},
{`merge Element -- add Element first`,
`
kind: Deployment
items:
- name: bar
image: bar:v1
command: ['run2.sh']
- name: foo
image: foo:v1
`,
`
kind: Deployment
items:
- name: foo
image: foo:v0
`,
`
kind: Deployment
items:
- name: foo
image: foo:v1
- name: bar
image: bar:v1
command: ['run2.sh']
`,
dest: `
apiVersion: custom
},
{`merge Element -- add Element second`,
`
kind: Deployment
containers:
items:
- name: foo
image: foo:bar
`,
expected: `
apiVersion: custom
kind: Deployment
containers:
- name: foo
image: foo:bar
image: foo:v1
- name: bar
image: bar:v1
command: ['run2.sh']
`,
`
kind: Deployment
items:
- name: foo
image: foo:v0
`,
`
kind: Deployment
items:
- name: foo
image: foo:v1
- name: bar
image: bar:v1
command: ['run2.sh']
`,
infer: true,
},
//
// Test Case
//
{description: `no infer merge keys merge using schema`,
source: `
apiVersion: apps/v1
{`keep list -- list missing from src`,
`
kind: Deployment
spec:
template:
spec:
containers:
- name: foo
command: ['run2.sh']
`,
dest: `
apiVersion: apps/v1
`
kind: Deployment
spec:
template:
spec:
containers:
- name: foo
image: foo:bar
items:
- name: foo
image: foo:v1
- name: bar
image: bar:v1
command: ['run2.sh']
`,
expected: `
apiVersion: apps/v1
`
kind: Deployment
spec:
template:
spec:
containers:
- name: foo
image: foo:bar
command: ['run2.sh']
items:
- name: foo
image: foo:v1
- name: bar
image: bar:v1
command: ['run2.sh']
`,
infer: false,
},
//
// Test Case
//
{description: `no infer merge keys merge using explicit schema as line comment'`,
source: `
apiVersion: custom
{`keep Element -- element missing in src`,
`
kind: Deployment
containers:
items:
- name: foo
image: foo:v1
`,
`
kind: Deployment
items:
- name: foo
image: foo:v0
- name: bar
image: bar:v1
command: ['run2.sh']
`,
dest: `
apiVersion: custom
`
kind: Deployment
containers: # {"items":{"$ref": "#/definitions/io.k8s.api.core.v1.Container"},"type":"array","x-kubernetes-patch-merge-key":"name","x-kubernetes-patch-strategy": "merge"}
- name: foo # hell ow
image: foo:bar
`,
expected: `
apiVersion: custom
kind: Deployment
containers: # {"items":{"$ref": "#/definitions/io.k8s.api.core.v1.Container"},"type":"array","x-kubernetes-patch-merge-key":"name","x-kubernetes-patch-strategy": "merge"}
items:
- name: foo
image: foo:bar
image: foo:v1
- name: bar
image: bar:v1
command: ['run2.sh']
`,
infer: false,
},
//
// Test Case
//
{`keep element -- empty list in src`,
`
kind: Deployment
items: {}
`,
`
kind: Deployment
items:
- name: foo
image: foo:v1
- name: bar
image: bar:v1
command: ['run2.sh']
`,
`
kind: Deployment
items:
- name: foo
image: foo:v1
- name: bar
image: bar:v1
command: ['run2.sh']
`,
},
//
// Test Case
//
{`remove Element -- null in src`,
`
kind: Deployment
items: null
`,
`
kind: Deployment
items:
- name: foo
image: foo:v1
- name: bar
image: bar:v1
command: ['run2.sh']
`,
`
kind: Deployment
`,
},
}

View File

@@ -4,21 +4,21 @@
package merge2_test
var listTestCases = []testCase{
{description: `replace List -- different value in dest`,
source: `
{`replace List -- different value in dest`,
`
kind: Deployment
items:
- 1
- 2
- 3
`,
dest: `
`
kind: Deployment
items:
- 0
- 1
`,
expected: `
`
kind: Deployment
items:
- 1
@@ -27,18 +27,18 @@ items:
`,
},
{description: `replace List -- missing from dest`,
source: `
{`replace List -- missing from dest`,
`
kind: Deployment
items:
- 1
- 2
- 3
`,
dest: `
`
kind: Deployment
`,
expected: `
`
kind: Deployment
items:
- 1
@@ -50,22 +50,22 @@ items:
//
// Test Case
//
{description: `keep List -- same value in src and dest`,
source: `
{`keep List -- same value in src and dest`,
`
kind: Deployment
items:
- 1
- 2
- 3
`,
dest: `
`
kind: Deployment
items:
- 1
- 2
- 3
`,
expected: `
`
kind: Deployment
items:
- 1
@@ -77,18 +77,18 @@ items:
//
// Test Case
//
{description: `keep List -- unspecified in src`,
source: `
{`keep List -- unspecified in src`,
`
kind: Deployment
`,
dest: `
`
kind: Deployment
items:
- 1
- 2
- 3
`,
expected: `
`
kind: Deployment
items:
- 1
@@ -100,19 +100,19 @@ items:
//
// Test Case
//
{description: `remove List -- null in src`,
source: `
{`remove List -- null in src`,
`
kind: Deployment
items: null
`,
dest: `
`
kind: Deployment
items:
- 1
- 2
- 3
`,
expected: `
`
kind: Deployment
`,
},
@@ -120,19 +120,19 @@ kind: Deployment
//
// Test Case
//
{description: `remove list -- empty in src`,
source: `
{`remove list -- empty in src`,
`
kind: Deployment
items: {}
`,
dest: `
`
kind: Deployment
items:
- 1
- 2
- 3
`,
expected: `
`
kind: Deployment
items: {}
`,

View File

@@ -4,19 +4,19 @@
package merge2_test
var mapTestCases = []testCase{
{description: `merge Map -- update field in dest`,
source: `
{`merge Map -- update field in dest`,
`
kind: Deployment
spec:
foo: bar1
`,
dest: `
`
kind: Deployment
spec:
foo: bar0
baz: buz
`,
expected: `
`
kind: Deployment
spec:
foo: bar1
@@ -24,19 +24,19 @@ spec:
`,
},
{description: `merge Map -- add field to dest`,
source: `
{`merge Map -- add field to dest`,
`
kind: Deployment
spec:
foo: bar1
baz: buz
`,
dest: `
`
kind: Deployment
spec:
foo: bar0
`,
expected: `
`
kind: Deployment
spec:
foo: bar1
@@ -44,18 +44,18 @@ spec:
`,
},
{description: `merge Map -- add list, empty in dest`,
source: `
{`merge Map -- add list, empty in dest`,
`
kind: Deployment
spec:
foo: bar1
baz: buz
`,
dest: `
`
kind: Deployment
spec: {}
`,
expected: `
`
kind: Deployment
spec:
foo: bar1
@@ -63,17 +63,17 @@ spec:
`,
},
{description: `merge Map -- add list, missing from dest`,
source: `
{`merge Map -- add list, missing from dest`,
`
kind: Deployment
spec:
foo: bar1
baz: buz
`,
dest: `
`
kind: Deployment
`,
expected: `
`
kind: Deployment
spec:
foo: bar1
@@ -81,19 +81,19 @@ spec:
`,
},
{description: `merge Map -- add Map first`,
source: `
{`merge Map -- add Map first`,
`
kind: Deployment
spec:
foo: bar1
baz: buz
`,
dest: `
`
kind: Deployment
spec:
foo: bar1
`,
expected: `
`
kind: Deployment
spec:
foo: bar1
@@ -101,19 +101,19 @@ spec:
`,
},
{description: `merge Map -- add Map second`,
source: `
{`merge Map -- add Map second`,
`
kind: Deployment
spec:
baz: buz
foo: bar1
`,
dest: `
`
kind: Deployment
spec:
foo: bar1
`,
expected: `
`
kind: Deployment
spec:
foo: bar1
@@ -124,17 +124,17 @@ spec:
//
// Test Case
//
{description: `keep map -- map missing from src`,
source: `
{`keep map -- map missing from src`,
`
kind: Deployment
`,
dest: `
`
kind: Deployment
spec:
foo: bar1
baz: buz
`,
expected: `
`
kind: Deployment
spec:
foo: bar1
@@ -145,18 +145,18 @@ spec:
//
// Test Case
//
{description: `keep map -- empty list in src`,
source: `
{`keep map -- empty list in src`,
`
kind: Deployment
items: {}
`,
dest: `
`
kind: Deployment
spec:
foo: bar1
baz: buz
`,
expected: `
`
kind: Deployment
spec:
foo: bar1
@@ -168,18 +168,18 @@ items: {}
//
// Test Case
//
{description: `remove Map -- null in src`,
source: `
{`remove Map -- null in src`,
`
kind: Deployment
spec: null
`,
dest: `
`
kind: Deployment
spec:
foo: bar1
baz: buz
`,
expected: `
`
kind: Deployment
`,
},

View File

@@ -6,7 +6,6 @@
package merge2
import (
"sigs.k8s.io/kustomize/kyaml/openapi"
"sigs.k8s.io/kustomize/kyaml/yaml"
"sigs.k8s.io/kustomize/kyaml/yaml/walk"
)
@@ -17,7 +16,7 @@ func Merge(src, dest *yaml.RNode) (*yaml.RNode, error) {
}
// Merge parses the arguments, and merges fields from srcStr into destStr.
func MergeStrings(srcStr, destStr string, infer bool) (string, error) {
func MergeStrings(srcStr, destStr string) (string, error) {
src, err := yaml.Parse(srcStr)
if err != nil {
return "", err
@@ -27,15 +26,10 @@ func MergeStrings(srcStr, destStr string, infer bool) (string, error) {
return "", err
}
result, err := walk.Walker{
Sources: []*yaml.RNode{dest, src},
Visitor: Merger{},
InferAssociativeLists: infer,
}.Walk()
result, err := Merge(src, dest)
if err != nil {
return "", err
}
return result.String()
}
@@ -45,7 +39,7 @@ type Merger struct {
var _ walk.Visitor = Merger{}
func (m Merger) VisitMap(nodes walk.Sources, s *openapi.ResourceSchema) (*yaml.RNode, error) {
func (m Merger) VisitMap(nodes walk.Sources) (*yaml.RNode, error) {
if err := m.SetComments(nodes); err != nil {
return nil, err
}
@@ -64,7 +58,7 @@ func (m Merger) VisitMap(nodes walk.Sources, s *openapi.ResourceSchema) (*yaml.R
return nodes.Dest(), nil
}
func (m Merger) VisitScalar(nodes walk.Sources, s *openapi.ResourceSchema) (*yaml.RNode, error) {
func (m Merger) VisitScalar(nodes walk.Sources) (*yaml.RNode, error) {
if err := m.SetComments(nodes); err != nil {
return nil, err
}
@@ -79,7 +73,7 @@ func (m Merger) VisitScalar(nodes walk.Sources, s *openapi.ResourceSchema) (*yam
return nodes.Dest(), nil
}
func (m Merger) VisitList(nodes walk.Sources, s *openapi.ResourceSchema, kind walk.ListKind) (*yaml.RNode, error) {
func (m Merger) VisitList(nodes walk.Sources, kind walk.ListKind) (*yaml.RNode, error) {
if err := m.SetComments(nodes); err != nil {
return nil, err
}

View File

@@ -365,7 +365,7 @@ a:
b:
# header comment
c: d
`, true)
`)
if !assert.NoError(t, err) {
return
}
@@ -385,7 +385,7 @@ a:
b:
c: d
# footer comment
`, true)
`)
if !assert.NoError(t, err) {
return
}
@@ -404,7 +404,7 @@ a:
a:
b:
c: d # line comment
`, true)
`)
if !assert.NoError(t, err) {
return
}
@@ -426,7 +426,7 @@ a:
b:
# replace comment
c: d
`, true)
`)
if !assert.NoError(t, err) {
return
}
@@ -447,7 +447,7 @@ a:
b:
c: d
# replace comment
`, true)
`)
if !assert.NoError(t, err) {
return
}
@@ -466,7 +466,7 @@ a:
a:
b:
c: d # replace comment
`, true)
`)
if !assert.NoError(t, err) {
return
}
@@ -484,7 +484,7 @@ a:
a:
b:
c: d # replace comment
`, true)
`)
if !assert.NoError(t, err) {
return
}

View File

@@ -17,27 +17,24 @@ var testCases = [][]testCase{scalarTestCases, listTestCases, elementTestCases, m
func TestMerge(t *testing.T) {
for i := range testCases {
for j := range testCases[i] {
tc := testCases[i][j]
t.Run(tc.description, func(t *testing.T) {
actual, err := MergeStrings(tc.source, tc.dest, tc.infer)
if !assert.NoError(t, err, tc.description) {
t.FailNow()
}
e, err := filters.FormatInput(bytes.NewBufferString(tc.expected))
if !assert.NoError(t, err) {
t.FailNow()
}
estr := strings.TrimSpace(e.String())
a, err := filters.FormatInput(bytes.NewBufferString(actual))
if !assert.NoError(t, err) {
t.FailNow()
}
astr := strings.TrimSpace(a.String())
if !assert.Equal(t, estr, astr, tc.description) {
t.FailNow()
}
})
for _, tc := range testCases[i] {
actual, err := MergeStrings(tc.source, tc.dest)
if !assert.NoError(t, err, tc.description) {
t.FailNow()
}
e, err := filters.FormatInput(bytes.NewBufferString(tc.expected))
if !assert.NoError(t, err) {
t.FailNow()
}
estr := strings.TrimSpace(e.String())
a, err := filters.FormatInput(bytes.NewBufferString(actual))
if !assert.NoError(t, err) {
t.FailNow()
}
astr := strings.TrimSpace(a.String())
if !assert.Equal(t, estr, astr, tc.description) {
t.FailNow()
}
}
}
}
@@ -47,5 +44,4 @@ type testCase struct {
source string
dest string
expected string
infer bool
}

View File

@@ -4,30 +4,30 @@
package merge2_test
var scalarTestCases = []testCase{
{description: `replace scalar -- different value in dest`,
source: `
{`replace scalar -- different value in dest`,
`
kind: Deployment
field: value1
`,
dest: `
`
kind: Deployment
field: value0
`,
expected: `
`
kind: Deployment
field: value1
`,
},
{description: `replace scalar -- missing from dest`,
source: `
{`replace scalar -- missing from dest`,
`
kind: Deployment
field: value1
`,
dest: `
`
kind: Deployment
`,
expected: `
`
kind: Deployment
field: value1
`,
@@ -36,16 +36,16 @@ field: value1
//
// Test Case
//
{description: `keep scalar -- same value in src and dest`,
source: `
{`keep scalar -- same value in src and dest`,
`
kind: Deployment
field: value1
`,
dest: `
`
kind: Deployment
field: value1
`,
expected: `
`
kind: Deployment
field: value1
`,
@@ -54,15 +54,15 @@ field: value1
//
// Test Case
//
{description: `keep scalar -- unspecified in src`,
source: `
{`keep scalar -- unspecified in src`,
`
kind: Deployment
`,
dest: `
`
kind: Deployment
field: value1
`,
expected: `
`
kind: Deployment
field: value1
`,
@@ -71,16 +71,16 @@ field: value1
//
// Test Case
//
{description: `remove scalar -- null in src`,
source: `
{`remove scalar -- null in src`,
`
kind: Deployment
field: null
`,
dest: `
`
kind: Deployment
field: value1
`,
expected: `
`
kind: Deployment
`,
},
@@ -88,16 +88,16 @@ kind: Deployment
//
// Test Case
//
{description: `remove scalar -- empty in src`,
source: `
{`remove scalar -- empty in src`,
`
kind: Deployment
field: {}
`,
dest: `
`
kind: Deployment
field: value1
`,
expected: `
`
kind: Deployment
field: {}
`,
@@ -106,15 +106,15 @@ field: {}
//
// Test Case
//
{description: `remove scalar -- null in src, missing in dest`,
source: `
{`remove scalar -- null in src, missing in dest`,
`
kind: Deployment
field: null
`,
dest: `
`
kind: Deployment
`,
expected: `
`
kind: Deployment
`,
},
@@ -122,15 +122,15 @@ kind: Deployment
//
// Test Case
//
{description: `merge an empty value`,
source: `
{`merge an empty value`,
`
kind: Deployment
field: {}
`,
dest: `
`
kind: Deployment
`,
expected: `
`
kind: Deployment
field: {}
`,

File diff suppressed because it is too large Load Diff

View File

@@ -9,226 +9,224 @@ var listTestCases = []testCase{
//
// Test Case
//
{description: `Replace list`,
origin: `
{`Replace list`,
`
list:
- 1
- 2
- 3`,
update: `
`
list:
- 2
- 3
- 4`,
local: `
`
list:
- 1
- 2
- 3`,
expected: `
`
list:
- 2
- 3
- 4`},
- 4`, nil},
//
// Test Case
//
{description: `Add an updated list`,
origin: `
{`Add an updated list`,
`
apiVersion: apps/v1
list: # old value
- 1
- 2
- 3
`,
update: `
`
apiVersion: apps/v1
list: # new value
- 2
- 3
- 4
`,
local: `
`
apiVersion: apps/v1`,
expected: `
`
apiVersion: apps/v1
list:
- 2
- 3
- 4
`},
`, nil},
//
// Test Case
//
{description: `Add keep an omitted field`,
origin: `
{`Add keep an omitted field`,
`
apiVersion: apps/v1
kind: Deployment`,
update: `
`
apiVersion: apps/v1
kind: StatefulSet`,
local: `
`
apiVersion: apps/v1
list: # not present in sources
- 2
- 3
- 4
`,
expected: `
`
apiVersion: apps/v1
list: # not present in sources
- 2
- 3
- 4
kind: StatefulSet
`},
`, nil},
//
// Test Case
//
// TODO(#36): consider making this an error
{description: `Change an updated field`,
origin: `
{`Change an updated field`,
`
apiVersion: apps/v1
list: # old value
- 1
- 2
- 3`,
update: `
`
apiVersion: apps/v1
list: # new value
- 2
- 3
- 4`,
local: `
`
apiVersion: apps/v1
list: # conflicting value
- a
- b
- c`,
expected: `
`
apiVersion: apps/v1
list: # conflicting value
- 2
- 3
- 4
`},
`, nil},
//
// Test Case
//
{description: `Ignore a field -- set`,
origin: `
{`Ignore a field -- set`,
`
apiVersion: apps/v1
list: # ignore value
- 1
- 2
- 3
`,
update: `
`
apiVersion: apps/v1
list: # ignore value
- 1
- 2
- 3`,
local: `
- 3`, `
apiVersion: apps/v1
list:
- 2
- 3
- 4
`,
expected: `
`, `
apiVersion: apps/v1
list:
- 2
- 3
- 4
`},
`, nil},
//
// Test Case
//
{description: `Ignore a field -- empty`,
origin: `
{`Ignore a field -- empty`,
`
apiVersion: apps/v1
list: # ignore value
- 1
- 2
- 3`,
update: `
`
apiVersion: apps/v1
list: # ignore value
- 1
- 2
- 3`,
local: `
`
apiVersion: apps/v1
`,
expected: `
`
apiVersion: apps/v1
`},
`, nil},
//
// Test Case
//
{description: `Explicitly clear a field`,
origin: `
{`Explicitly clear a field`,
`
apiVersion: apps/v1`,
update: `
`
apiVersion: apps/v1
list: null # clear`,
local: `
`
apiVersion: apps/v1
list: # value to clear
- 1
- 2
- 3`,
expected: `
apiVersion: apps/v1`},
`
apiVersion: apps/v1`, nil},
//
// Test Case
//
{description: `Implicitly clear a field`,
origin: `
{`Implicitly clear a field`,
`
apiVersion: apps/v1
list: # clear value
- 1
- 2
- 3`,
update: `
`
apiVersion: apps/v1`,
local: `
`
apiVersion: apps/v1
list: # old value
- 1
- 2
- 3`,
expected: `
apiVersion: apps/v1`},
`
apiVersion: apps/v1`, nil},
//
// Test Case
//
// TODO(#36): consider making this an error
{description: `Implicitly clear a changed field`,
origin: `
{`Implicitly clear a changed field`,
`
apiVersion: apps/v1
list: # old value
- 1
- 2
- 3`,
update: `
`
apiVersion: apps/v1`,
local: `
`
apiVersion: apps/v1
list: # old value
- a
- b
- c`,
expected: `
apiVersion: apps/v1`},
`
apiVersion: apps/v1`, nil},
}

View File

@@ -7,267 +7,267 @@ var mapTestCases = []testCase{
//
// Test Case
//
{description: `Add the annotations map field`,
origin: `
{`Add the annotations map field`,
`
kind: Deployment`,
update: `
`
kind: Deployment
metadata:
annotations:
d: e # add these annotations
`,
local: `
`
kind: Deployment`,
expected: `
`
kind: Deployment
metadata:
annotations:
d: e # add these annotations`},
d: e # add these annotations`, nil},
//
// Test Case
//
{description: `Add an annotation to the field`,
origin: `
{`Add an annotation to the field`,
`
kind: Deployment
metadata:
annotations:
a: b`,
update: `
`
kind: Deployment
metadata:
annotations:
a: b
d: e # add these annotations`,
local: `
`
kind: Deployment
metadata:
annotations:
g: h # keep these annotations`,
expected: `
`
kind: Deployment
metadata:
annotations:
g: h # keep these annotations
d: e # add these annotations`},
d: e # add these annotations`, nil},
//
// Test Case
//
{description: `Add an annotation to the field, field missing from dest`,
origin: `
{`Add an annotation to the field, field missing from dest`,
`
kind: Deployment
metadata:
annotations:
a: b # ignored because unchanged`,
update: `
`
kind: Deployment
metadata:
annotations:
a: b # ignore because unchanged
d: e`,
local: `
`
kind: Deployment`,
expected: `
`
kind: Deployment
metadata:
annotations:
d: e`},
d: e`, nil},
//
// Test Case
//
{description: `Update an annotation on the field, field messing rom the dest`,
origin: `
{`Update an annotation on the field, field messing rom the dest`,
`
kind: Deployment
metadata:
annotations:
a: b
d: c`,
update: `
`
kind: Deployment
metadata:
annotations:
a: b
d: e # set these annotations`,
local: `
`
kind: Deployment
metadata:
annotations:
g: h # keep these annotations`,
expected: `
`
kind: Deployment
metadata:
annotations:
g: h # keep these annotations
d: e # set these annotations`},
d: e # set these annotations`, nil},
//
// Test Case
//
{description: `Add an annotation to the field, field missing from dest`,
origin: `
{`Add an annotation to the field, field missing from dest`,
`
kind: Deployment
metadata:
annotations:
a: b # ignored because unchanged`,
update: `
`
kind: Deployment
metadata:
annotations:
a: b # ignore because unchanged
d: e`,
local: `
`
kind: Deployment`,
expected: `
`
kind: Deployment
metadata:
annotations:
d: e`},
d: e`, nil},
//
// Test Case
//
{description: `Remove an annotation`,
origin: `
{`Remove an annotation`,
`
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
a: b`,
update: `
`
apiVersion: apps/v1
kind: Deployment
metadata:
annotations: {}`,
local: `
`
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
c: d
a: b`,
expected: `
`
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
c: d`},
c: d`, nil},
//
// Test Case
//
// TODO(#36) support ~annotations~: {} deletion
{description: `Specify a field as empty that isn't present in the source`,
origin: `
{`Specify a field as empty that isn't present in the source`,
`
apiVersion: apps/v1
kind: Deployment
metadata:
name: foo`,
update: `
`
apiVersion: apps/v1
kind: Deployment
metadata:
name: foo
annotations: null`,
local: `
`
apiVersion: apps/v1
kind: Deployment
metadata:
name: foo
annotations:
a: b`,
expected: `
`
apiVersion: apps/v1
kind: Deployment
metadata:
name: foo`},
name: foo`, nil},
//
// Test Case
//
{description: `Remove an annotation`,
origin: `
{`Remove an annotation`,
`
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
a: b`,
update: `
`
apiVersion: apps/v1
kind: Deployment`,
local: `
`
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
c: d
a: b`,
expected: `
`
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
c: d`},
c: d`, nil},
//
// Test Case
//
{description: `Remove annotations field`,
origin: `
{`Remove annotations field`,
`
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
a: b`,
update: `
`
apiVersion: apps/v1
kind: Deployment`,
local: `
`
apiVersion: apps/v1
kind: Deployment
metadata:
name: foo`,
expected: `
`
apiVersion: apps/v1
kind: Deployment
metadata:
name: foo
`},
`, nil},
//
// Test Case
//
{description: `Remove annotations field, but keep in dest`,
origin: `
{`Remove annotations field, but keep in dest`,
`
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
a: b`,
update: `
`
apiVersion: apps/v1
kind: Deployment`,
local: `
`
apiVersion: apps/v1
kind: Deployment
metadata:
name: foo
annotations:
foo: bar # keep this annotation even though the parent field was removed`,
expected: `
`
apiVersion: apps/v1
kind: Deployment
metadata:
name: foo
annotations:
foo: bar # keep this annotation even though the parent field was removed`},
foo: bar # keep this annotation even though the parent field was removed`, nil},
//
// Test Case
//
{description: `Remove annotations, but they are already empty`,
origin: `
{`Remove annotations, but they are already empty`,
`
apiVersion: apps/v1
kind: Deployment
metadata:
@@ -275,24 +275,24 @@ metadata:
annotations:
a: b
`,
update: `
`
apiVersion: apps/v1
kind: Deployment
metadata:
name: foo
`,
local: `
`
apiVersion: apps/v1
kind: Deployment
metadata:
name: foo
annotations: {}
`,
expected: `
`
apiVersion: apps/v1
kind: Deployment
metadata:
name: foo
annotations: {}
`},
`, nil},
}

View File

@@ -13,12 +13,11 @@ import (
func Merge(dest, original, update *yaml.RNode) (*yaml.RNode, error) {
// if update == nil && original != nil => declarative deletion
return walk.Walker{
Visitor: Visitor{},
return walk.Walker{Visitor: Visitor{},
Sources: []*yaml.RNode{dest, original, update}}.Walk()
}
func MergeStrings(dest, original, update string, infer bool) (string, error) {
func MergeStrings(dest, original, update string) (string, error) {
srcOriginal, err := yaml.Parse(original)
if err != nil {
return "", err
@@ -32,10 +31,7 @@ func MergeStrings(dest, original, update string, infer bool) (string, error) {
return "", err
}
result, err := walk.Walker{
InferAssociativeLists: infer,
Visitor: Visitor{},
Sources: []*yaml.RNode{d, srcOriginal, srcUpdated}}.Walk()
result, err := Merge(d, srcOriginal, srcUpdated)
if err != nil {
return "", err
}

View File

@@ -15,27 +15,24 @@ var testCases = [][]testCase{scalarTestCases, listTestCases, mapTestCases, eleme
func TestMerge(t *testing.T) {
for i := range testCases {
for j := range testCases[i] {
tc := testCases[i][j]
t.Run(tc.description, func(t *testing.T) {
actual, err := MergeStrings(tc.local, tc.origin, tc.update, tc.infer)
if tc.err == nil {
if !assert.NoError(t, err, tc.description) {
t.FailNow()
}
if !assert.Equal(t,
strings.TrimSpace(tc.expected), strings.TrimSpace(actual), tc.description) {
t.FailNow()
}
} else {
if !assert.Errorf(t, err, tc.description) {
t.FailNow()
}
if !assert.Contains(t, tc.err.Error(), err.Error()) {
t.FailNow()
}
for _, tc := range testCases[i] {
actual, err := MergeStrings(tc.local, tc.origin, tc.update)
if tc.err == nil {
if !assert.NoError(t, err, tc.description) {
t.FailNow()
}
})
if !assert.Equal(t,
strings.TrimSpace(tc.expected), strings.TrimSpace(actual), tc.description) {
t.FailNow()
}
} else {
if !assert.Errorf(t, err, tc.description) {
t.FailNow()
}
if !assert.Contains(t, tc.err.Error(), err.Error()) {
t.FailNow()
}
}
}
}
}
@@ -47,5 +44,4 @@ type testCase struct {
local string
expected string
err error
infer bool
}

View File

@@ -8,128 +8,128 @@ var scalarTestCases = []testCase{
//
// Test Case
//
{description: `Set and updated a field`,
origin: `kind: Deployment`,
update: `kind: StatefulSet`,
local: `kind: Deployment`,
expected: `kind: StatefulSet`},
{`Set and updated a field`,
`kind: Deployment`,
`kind: StatefulSet`,
`kind: Deployment`,
`kind: StatefulSet`, nil},
{description: `Add an updated field`,
origin: `
{`Add an updated field`,
`
apiVersion: apps/v1
kind: Deployment # old value`,
update: `
`
apiVersion: apps/v1
kind: StatefulSet # new value`,
local: `
`
apiVersion: apps/v1`,
expected: `
`
apiVersion: apps/v1
kind: StatefulSet # new value`},
kind: StatefulSet # new value`, nil},
{description: `Add keep an omitted field`,
origin: `
{`Add keep an omitted field`,
`
apiVersion: apps/v1
kind: Deployment`,
update: `
`
apiVersion: apps/v1
kind: StatefulSet`,
local: `
`
apiVersion: apps/v1
spec: foo # field not present in source
`,
expected: `
`
apiVersion: apps/v1
spec: foo # field not present in source
kind: StatefulSet
`},
`, nil},
//
// Test Case
//
// TODO(#36): consider making this an error
{description: `Change an updated field`,
origin: `
{`Change an updated field`,
`
apiVersion: apps/v1
kind: Deployment # old value`,
update: `
`
apiVersion: apps/v1
kind: StatefulSet # new value`,
local: `
`
apiVersion: apps/v1
kind: Service # conflicting value`,
expected: `
`
apiVersion: apps/v1
kind: StatefulSet # new value`},
kind: StatefulSet # new value`, nil},
{description: `Ignore a field`,
origin: `
{`Ignore a field`,
`
apiVersion: apps/v1
kind: Deployment # ignore this field`,
update: `
`
apiVersion: apps/v1
kind: Deployment # ignore this field`,
local: `
`
apiVersion: apps/v1`,
expected: `
apiVersion: apps/v1`},
`
apiVersion: apps/v1`, nil},
{description: `Explicitly clear a field`,
origin: `
{`Explicitly clear a field`,
`
apiVersion: apps/v1`,
update: `
`
apiVersion: apps/v1
kind: null # clear this value`,
local: `
`
apiVersion: apps/v1
kind: Deployment # value to be cleared`,
expected: `
apiVersion: apps/v1`},
`
apiVersion: apps/v1`, nil},
{description: `Implicitly clear a field`,
origin: `
{`Implicitly clear a field`,
`
apiVersion: apps/v1
kind: Deployment # clear this field`,
update: `
`
apiVersion: apps/v1`,
local: `
`
apiVersion: apps/v1
kind: Deployment # clear this field`,
expected: `
apiVersion: apps/v1`},
`
apiVersion: apps/v1`, nil},
//
// Test Case
//
// TODO(#36): consider making this an error
{description: `Implicitly clear a changed field`,
origin: `
{`Implicitly clear a changed field`,
`
apiVersion: apps/v1
kind: Deployment`,
update: `
`
apiVersion: apps/v1`,
local: `
`
apiVersion: apps/v1
kind: StatefulSet`,
expected: `
apiVersion: apps/v1`},
`
apiVersion: apps/v1`, nil},
//
// Test Case
//
{description: `Merge an empty scalar value`,
origin: `
{`Merge an empty scalar value`,
`
apiVersion: apps/v1
`,
update: `
`
apiVersion: apps/v1
kind: {}
`,
local: `
`
apiVersion: apps/v1
`,
expected: `
`
apiVersion: apps/v1
kind: {}
`},
`, nil},
}

View File

@@ -4,7 +4,6 @@
package merge3
import (
"sigs.k8s.io/kustomize/kyaml/openapi"
"sigs.k8s.io/kustomize/kyaml/yaml"
"sigs.k8s.io/kustomize/kyaml/yaml/walk"
)
@@ -18,7 +17,7 @@ const (
type Visitor struct{}
func (m Visitor) VisitMap(nodes walk.Sources, s *openapi.ResourceSchema) (*yaml.RNode, error) {
func (m Visitor) VisitMap(nodes walk.Sources) (*yaml.RNode, error) {
if yaml.IsNull(nodes.Updated()) || yaml.IsNull(nodes.Dest()) {
// explicitly cleared from either dest or update
return walk.ClearNode, nil
@@ -37,7 +36,7 @@ func (m Visitor) VisitMap(nodes walk.Sources, s *openapi.ResourceSchema) (*yaml.
return nodes.Dest(), nil
}
func (m Visitor) visitAList(nodes walk.Sources, _ *openapi.ResourceSchema) (*yaml.RNode, error) {
func (m Visitor) visitAList(nodes walk.Sources) (*yaml.RNode, error) {
if yaml.IsEmpty(nodes.Updated()) && !yaml.IsEmpty(nodes.Origin()) {
// implicitly cleared from update -- element was deleted
return walk.ClearNode, nil
@@ -52,7 +51,7 @@ func (m Visitor) visitAList(nodes walk.Sources, _ *openapi.ResourceSchema) (*yam
return nodes.Dest(), nil
}
func (m Visitor) VisitScalar(nodes walk.Sources, s *openapi.ResourceSchema) (*yaml.RNode, error) {
func (m Visitor) VisitScalar(nodes walk.Sources) (*yaml.RNode, error) {
if yaml.IsNull(nodes.Updated()) || yaml.IsNull(nodes.Dest()) {
// explicitly cleared from either dest or update
return nil, nil
@@ -104,9 +103,9 @@ func (m Visitor) visitNAList(nodes walk.Sources) (*yaml.RNode, error) {
return nodes.Dest(), nil
}
func (m Visitor) VisitList(nodes walk.Sources, s *openapi.ResourceSchema, kind walk.ListKind) (*yaml.RNode, error) {
func (m Visitor) VisitList(nodes walk.Sources, kind walk.ListKind) (*yaml.RNode, error) {
if kind == walk.AssociativeList {
return m.visitAList(nodes, s)
return m.visitAList(nodes)
}
// non-associative list
return m.visitNAList(nodes)

View File

@@ -1,34 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package schema contains libraries for working with the yaml and openapi packages.
package schema
import (
"sigs.k8s.io/kustomize/kyaml/openapi"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
// IsAssociative returns true if all elements in the list contain an AssociativeSequenceKey
// as a field.
func IsAssociative(schema *openapi.ResourceSchema, nodes []*yaml.RNode, infer bool) bool {
if schema != nil {
// use the schema to identify if the list is associative
s, _ := schema.PatchStrategyAndKey()
return s == "merge"
}
if !infer {
return false
}
for i := range nodes {
node := nodes[i]
if yaml.IsEmpty(node) {
continue
}
if node.IsAssociative() {
return true
}
}
return false
}

View File

@@ -651,8 +651,24 @@ func (rn *RNode) VisitElements(fn func(node *RNode) error) error {
// The order sets the precedence of the merge keys -- if multiple keys are present
// in Resources in a list, then the FIRST key which ALL elements in the list have is used as the
// associative key for merging that list.
// Only infer name as a merge key.
var AssociativeSequenceKeys = []string{"name"}
var AssociativeSequenceKeys = []string{
"mountPath", "devicePath", "ip", "type", "topologyKey", "name", "containerPort",
}
// IsAssociative returns true if all elements in the list contain an AssociativeSequenceKey
// as a field.
func IsAssociative(nodes []*RNode) bool {
for i := range nodes {
node := nodes[i]
if IsEmpty(node) {
continue
}
if node.IsAssociative() {
return true
}
}
return false
}
// IsAssociative returns true if the RNode contains an AssociativeSequenceKey as a field.
func (rn *RNode) IsAssociative() bool {

View File

@@ -7,44 +7,28 @@ import (
"strings"
"github.com/go-errors/errors"
"sigs.k8s.io/kustomize/kyaml/openapi"
"sigs.k8s.io/kustomize/kyaml/sets"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
func (l *Walker) walkAssociativeSequence() (*yaml.RNode, error) {
// may require initializing the dest node
dest, err := l.Sources.setDestNode(l.VisitList(l.Sources, l.Schema, AssociativeList))
dest, err := l.Sources.setDestNode(l.VisitList(l.Sources, AssociativeList))
if dest == nil || err != nil {
return nil, err
}
var key string
if l.Schema != nil {
_, key = l.Schema.PatchStrategyAndKey()
// find the list of elements we need to recursively walk
key, err := l.elementKey()
if err != nil {
return nil, err
}
if key == "" { // no key from the schema, try to infer one
// find the list of elements we need to recursively walk
key, err = l.elementKey()
if err != nil {
return nil, err
}
}
values := l.elementValues(key)
// recursively set the elements in the list
var s *openapi.ResourceSchema
if l.Schema != nil {
s = l.Schema.Elements()
}
for _, value := range values {
val, err := Walker{
InferAssociativeLists: l.InferAssociativeLists,
Visitor: l,
Schema: s,
Sources: l.elementValue(key, value),
}.Walk()
val, err := Walker{Visitor: l,
Sources: l.elementValue(key, value)}.Walk()
if err != nil {
return nil, err
}

View File

@@ -6,8 +6,6 @@ package walk
import (
"sort"
"sigs.k8s.io/kustomize/kyaml/fieldmeta"
"sigs.k8s.io/kustomize/kyaml/openapi"
"sigs.k8s.io/kustomize/kyaml/sets"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
@@ -20,27 +18,15 @@ import (
// - set each source field value on l.Dest
func (l Walker) walkMap() (*yaml.RNode, error) {
// get the new map value
dest, err := l.Sources.setDestNode(l.VisitMap(l.Sources, l.Schema))
dest, err := l.Sources.setDestNode(l.VisitMap(l.Sources))
if dest == nil || err != nil {
return nil, err
}
// recursively set the field values on the map
for _, key := range l.fieldNames() {
var s *openapi.ResourceSchema
if l.Schema != nil {
s = l.Schema.Field(key)
}
fv, commentSch := l.fieldValue(key)
if commentSch != nil {
s = commentSch
}
val, err := Walker{
InferAssociativeLists: l.InferAssociativeLists,
Visitor: l,
Schema: s,
Sources: fv,
Path: append(l.Path, key)}.Walk()
val, err := Walker{Visitor: l,
Sources: l.fieldValue(key), Path: append(l.Path, key)}.Walk()
if err != nil {
return nil, err
}
@@ -56,40 +42,11 @@ func (l Walker) walkMap() (*yaml.RNode, error) {
}
// valueIfPresent returns node.Value if node is non-nil, otherwise returns nil
func (l Walker) valueIfPresent(node *yaml.MapNode) (*yaml.RNode, *openapi.ResourceSchema) {
func (l Walker) valueIfPresent(node *yaml.MapNode) *yaml.RNode {
if node == nil {
return nil, nil
return nil
}
// parse the schema for the field if present
var s *openapi.ResourceSchema
fm := fieldmeta.FieldMeta{}
var err error
// check the value for a schema
if err = fm.Read(node.Value); err == nil {
s = &openapi.ResourceSchema{Schema: &fm.Schema}
if fm.Schema.Ref.String() != "" {
r, err := openapi.Resolve(&fm.Schema.Ref)
if err == nil && r != nil {
s.Schema = r
}
}
}
// check the key for a schema -- this will be used
// when the value is a Sequence (comments are attached)
// to the key
if fm.IsEmpty() {
if err = fm.Read(node.Key); err == nil {
s = &openapi.ResourceSchema{Schema: &fm.Schema}
}
if fm.Schema.Ref.String() != "" {
r, err := openapi.Resolve(&fm.Schema.Ref)
if err == nil && r != nil {
s.Schema = r
}
}
}
return node.Value, s
return node.Value
}
// fieldNames returns a sorted slice containing the names of all fields that appear in any of
@@ -110,20 +67,15 @@ func (l Walker) fieldNames() []string {
}
// fieldValue returns a slice containing each source's value for fieldName
func (l Walker) fieldValue(fieldName string) ([]*yaml.RNode, *openapi.ResourceSchema) {
func (l Walker) fieldValue(fieldName string) []*yaml.RNode {
var fields []*yaml.RNode
var sch *openapi.ResourceSchema
for i := range l.Sources {
if l.Sources[i] == nil {
fields = append(fields, nil)
continue
}
field := l.Sources[i].Field(fieldName)
f, s := l.valueIfPresent(field)
fields = append(fields, f)
if sch == nil && !s.IsEmpty() {
sch = s
}
fields = append(fields, l.valueIfPresent(field))
}
return fields, sch
return fields
}

View File

@@ -9,5 +9,5 @@ import (
// walkNonAssociativeSequence returns the value of VisitList
func (l Walker) walkNonAssociativeSequence() (*yaml.RNode, error) {
return l.VisitList(l.Sources, l.Schema, NonAssociateList)
return l.VisitList(l.Sources, NonAssociateList)
}

View File

@@ -7,5 +7,5 @@ import "sigs.k8s.io/kustomize/kyaml/yaml"
// walkScalar returns the value of VisitScalar
func (l Walker) walkScalar() (*yaml.RNode, error) {
return l.VisitScalar(l.Sources, l.Schema)
return l.VisitScalar(l.Sources)
}

View File

@@ -4,7 +4,6 @@
package walk
import (
"sigs.k8s.io/kustomize/kyaml/openapi"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
@@ -17,11 +16,11 @@ const (
// Visitor is invoked by walk with source and destination node pairs
type Visitor interface {
VisitMap(Sources, *openapi.ResourceSchema) (*yaml.RNode, error)
VisitMap(nodes Sources) (*yaml.RNode, error)
VisitScalar(Sources, *openapi.ResourceSchema) (*yaml.RNode, error)
VisitScalar(nodes Sources) (*yaml.RNode, error)
VisitList(Sources, *openapi.ResourceSchema, ListKind) (*yaml.RNode, error)
VisitList(nodes Sources, kind ListKind) (*yaml.RNode, error)
}
// ClearNode is returned if GrepFilter should do nothing after calling Set

View File

@@ -8,30 +8,20 @@ import (
"os"
"strings"
"sigs.k8s.io/kustomize/kyaml/fieldmeta"
"sigs.k8s.io/kustomize/kyaml/openapi"
"sigs.k8s.io/kustomize/kyaml/yaml"
"sigs.k8s.io/kustomize/kyaml/yaml/schema"
)
// Walker walks the Source RNode and modifies the RNode provided to GrepFilter.
// Filter walks the Source RNode and modifies the RNode provided to GrepFilter.
type Walker struct {
// Visitor is invoked by GrepFilter
Visitor
Schema *openapi.ResourceSchema
// Source is the RNode to walk. All Source fields and associative list elements
// will be visited.
Sources Sources
// Path is the field path to the current Source Node.
Path []string
// InferAssociativeLists if set to true will infer merge strategies for
// fields which it doesn't have the schema based on the fields in the
// list elements.
InferAssociativeLists bool
}
func (l Walker) Kind() yaml.Kind {
@@ -45,8 +35,6 @@ func (l Walker) Kind() yaml.Kind {
// GrepFilter implements yaml.GrepFilter
func (l Walker) Walk() (*yaml.RNode, error) {
l.Schema = l.GetSchema()
// invoke the handler for the corresponding node type
switch l.Kind() {
case yaml.MappingNode:
@@ -58,7 +46,7 @@ func (l Walker) Walk() (*yaml.RNode, error) {
if err := yaml.ErrorIfAnyInvalidAndNonNull(yaml.SequenceNode, l.Sources...); err != nil {
return nil, err
}
if schema.IsAssociative(l.Schema, l.Sources, l.InferAssociativeLists) {
if yaml.IsAssociative(l.Sources) {
return l.walkAssociativeSequence()
}
return l.walkNonAssociativeSequence()
@@ -76,49 +64,6 @@ func (l Walker) Walk() (*yaml.RNode, error) {
}
}
func (l Walker) GetSchema() *openapi.ResourceSchema {
for i := range l.Sources {
r := l.Sources[i]
if yaml.IsEmpty(r) {
continue
}
fm := fieldmeta.FieldMeta{}
if err := fm.Read(r); err == nil && !fm.IsEmpty() {
// per-field schema, this is fine
if fm.Schema.Ref.String() != "" {
// resolve the reference
s, err := openapi.Resolve(&fm.Schema.Ref)
if err == nil && s != nil {
fm.Schema = *s
}
}
return &openapi.ResourceSchema{Schema: &fm.Schema}
}
}
if l.Schema != nil {
return l.Schema
}
for i := range l.Sources {
r := l.Sources[i]
if yaml.IsEmpty(r) {
continue
}
m, _ := r.GetMeta()
if m.Kind == "" || m.APIVersion == "" {
continue
}
s := openapi.SchemaForResourceType(yaml.TypeMeta{Kind: m.Kind, APIVersion: m.APIVersion})
if s != nil {
return s
}
}
return nil
}
const (
DestIndex = iota
OriginIndex

View File

@@ -148,10 +148,8 @@ func (p *plugin) findContainers(obj map[string]interface{}) error {
}
func isImageMatched(s, t string) bool {
// Tag values are limited to [a-zA-Z0-9_.{}-].
// Some tools like Bazel rules_k8s allow tag patterns with {} characters.
// More info: https://github.com/bazelbuild/rules_k8s/pull/423
pattern, _ := regexp.Compile("^" + t + "(@sha256)?(:[a-zA-Z0-9_.{}-]*)?$")
// Tag values are limited to [a-zA-Z0-9_.-].
pattern, _ := regexp.Compile("^" + t + "(@sha256)?(:[a-zA-Z0-9_.-]*)?$")
return pattern.MatchString(s)
}

View File

@@ -5,8 +5,8 @@
# kyaml version
export kyaml_major=0
export kyaml_minor=1
export kyaml_patch=0
export kyaml_minor=0
export kyaml_patch=11
# kstatus version
export kstatus_major=0
@@ -16,12 +16,12 @@ export kstatus_patch=1
# kustomize api version
export api_major=0
export api_minor=3
export api_patch=3
export api_patch=2
# cmd/config version
export cmd_config_major=0
export cmd_config_minor=1
export cmd_config_patch=0
export cmd_config_minor=0
export cmd_config_patch=11
# cmd/kubectl version
export cmd_kubectl_major=0

View File

@@ -5,7 +5,7 @@
set -e
# run all tests for kyaml and related commands
targets="kyaml cmd/config cmd/kubectl functions/examples/injection-tshirt-sizes functions/examples/template-go-nginx functions/examples/template-heredoc-cockroachdb functions/examples/validator-kubeval functions/examples/validator-resource-requests functions/examples/application-cr"
targets="kyaml cmd/config cmd/kubectl functions/examples/injection-tshirt-sizes functions/examples/template-go-nginx functions/examples/template-heredoc-cockroachdb functions/examples/validator-kubeval functions/examples/validator-resource-requests"
for target in $targets; do
pushd .
cd $target