diff --git a/.gitignore b/.gitignore index d32d1b6dc..8f2ae2c9b 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ _dist/ bin/ vendor/ +# Ignores charts pulled for dependency build tests +cmd/helm/testdata/testcharts/issue-7233/charts/* diff --git a/ADOPTERS.md b/ADOPTERS.md new file mode 100644 index 000000000..46b42b8a0 --- /dev/null +++ b/ADOPTERS.md @@ -0,0 +1,15 @@ + To add your organization to this list, open a pull request that adds your + organization's name, optionally with a link. The list is in alphabetical order. + + (Remember to use `git commit --signoff` to comply with the DCO) + +# Organizations Using Helm + +- [Blood Orange](https://bloodorange.io) +- [IBM](https://www.ibm.com) +- [Microsoft](https://microsoft.com) +- [Qovery](https://www.qovery.com/) +- [Samsung SDS](https://www.samsungsds.com/) +- [Ville de Montreal](https://montreal.ca) + +_This file is part of the CNCF official documentation for projects._ diff --git a/Makefile b/Makefile index 7d254e919..27404bca8 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ BINDIR := $(CURDIR)/bin DIST_DIRS := find * -type d -exec TARGETS := darwin/amd64 linux/amd64 linux/386 linux/arm linux/arm64 linux/ppc64le linux/s390x windows/amd64 -TARGET_OBJS ?= darwin-amd64.tar.gz darwin-amd64.tar.gz.sha256 linux-amd64.tar.gz linux-amd64.tar.gz.sha256 linux-386.tar.gz linux-386.tar.gz.sha256 linux-arm.tar.gz linux-arm.tar.gz.sha256 linux-arm64.tar.gz linux-arm64.tar.gz.sha256 linux-ppc64le.tar.gz linux-ppc64le.tar.gz.sha256 linux-s390x.tar.gz linux-s390x.tar.gz.sha256 windows-amd64.zip windows-amd64.zip.sha256 +TARGET_OBJS ?= darwin-amd64.tar.gz darwin-amd64.tar.gz.sha256 darwin-amd64.tar.gz.sha256sum linux-amd64.tar.gz linux-amd64.tar.gz.sha256 linux-amd64.tar.gz.sha256sum linux-386.tar.gz linux-386.tar.gz.sha256 linux-386.tar.gz.sha256sum linux-arm.tar.gz linux-arm.tar.gz.sha256 linux-arm.tar.gz.sha256sum linux-arm64.tar.gz linux-arm64.tar.gz.sha256 linux-arm64.tar.gz.sha256sum linux-ppc64le.tar.gz linux-ppc64le.tar.gz.sha256 linux-ppc64le.tar.gz.sha256sum linux-s390x.tar.gz linux-s390x.tar.gz.sha256 linux-s390x.tar.gz.sha256sum windows-amd64.zip windows-amd64.zip.sha256 windows-amd64.zip.sha256sum BINNAME ?= helm GOPATH = $(shell go env GOPATH) @@ -24,7 +24,7 @@ GOFLAGS := SRC := $(shell find . -type f -name '*.go' -print) # Required for globs to work correctly -SHELL = /bin/bash +SHELL = /usr/bin/env bash GIT_COMMIT = $(shell git rev-parse HEAD) GIT_SHA = $(shell git rev-parse --short HEAD) @@ -157,14 +157,22 @@ fetch-dist: .PHONY: sign sign: - for f in _dist/*.{gz,zip,sha256} ; do \ + for f in _dist/*.{gz,zip,sha256,sha256sum} ; do \ gpg --armor --detach-sign $${f} ; \ done +# The contents of the .sha256sum file are compatible with tools like +# shasum. For example, using the following command will verify +# the file helm-3.1.0-rc.1-darwin-amd64.tar.gz: +# shasum -a 256 -c helm-3.1.0-rc.1-darwin-amd64.tar.gz.sha256sum +# The .sha256 files hold only the hash and are not compatible with +# verification tools like shasum or sha256sum. This method and file can be +# removed in Helm v4. .PHONY: checksum checksum: for f in _dist/*.{gz,zip} ; do \ - shasum -a 256 "$${f}" | awk '{print $$1}' > "$${f}.sha256" ; \ + shasum -a 256 "$${f}" | sed 's/_dist\///' > "$${f}.sha256sum" ; \ + shasum -a 256 "$${f}" | awk '{print $$1}' > "$${f}.sha256" ; \ done # ------------------------------------------------------------------------------ diff --git a/cmd/helm/dependency_build_test.go b/cmd/helm/dependency_build_test.go index 58ef3d3a1..eeca12fa6 100644 --- a/cmd/helm/dependency_build_test.go +++ b/cmd/helm/dependency_build_test.go @@ -100,3 +100,16 @@ func TestDependencyBuildCmd(t *testing.T) { t.Errorf("mismatched versions. Expected %q, got %q", "0.1.0", v) } } + +func TestDependencyBuildCmdWithHelmV2Hash(t *testing.T) { + chartName := "testdata/testcharts/issue-7233" + + cmd := fmt.Sprintf("dependency build '%s'", chartName) + _, out, err := executeActionCommand(cmd) + + // Want to make sure the build can verify Helm v2 hash + if err != nil { + t.Logf("Output: %s", out) + t.Fatal(err) + } +} diff --git a/cmd/helm/flags.go b/cmd/helm/flags.go index 65575a5c1..246cb0dd5 100644 --- a/cmd/helm/flags.go +++ b/cmd/helm/flags.go @@ -27,9 +27,11 @@ import ( "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/cli/output" "helm.sh/helm/v3/pkg/cli/values" + "helm.sh/helm/v3/pkg/postrender" ) const outputFlag = "output" +const postRenderFlag = "post-renderer" func addValueOptionsFlags(f *pflag.FlagSet, v *values.Options) { f.StringSliceVarP(&v.ValueFiles, "values", "f", []string{}, "specify values in a YAML file or a URL (can specify multiple)") @@ -94,3 +96,31 @@ func (o *outputValue) Set(s string) error { *o = outputValue(outfmt) return nil } + +func bindPostRenderFlag(cmd *cobra.Command, varRef *postrender.PostRenderer) { + cmd.Flags().Var(&postRenderer{varRef}, postRenderFlag, "the path to an executable to be used for post rendering. If it exists in $PATH, the binary will be used, otherwise it will try to look for the executable at the given path") +} + +type postRenderer struct { + renderer *postrender.PostRenderer +} + +func (p postRenderer) String() string { + return "exec" +} + +func (p postRenderer) Type() string { + return "postrenderer" +} + +func (p postRenderer) Set(s string) error { + if s == "" { + return nil + } + pr, err := postrender.NewExec(s) + if err != nil { + return err + } + *p.renderer = pr + return nil +} diff --git a/cmd/helm/helm.go b/cmd/helm/helm.go index 112d5123f..257387547 100644 --- a/cmd/helm/helm.go +++ b/cmd/helm/helm.go @@ -19,6 +19,7 @@ package main // import "helm.sh/helm/v3/cmd/helm" import ( "flag" "fmt" + "io/ioutil" "log" "os" "strings" @@ -26,13 +27,18 @@ import ( "github.com/spf13/cobra" "github.com/spf13/pflag" "k8s.io/klog" + "sigs.k8s.io/yaml" // Import to initialize client auth plugins. _ "k8s.io/client-go/plugin/pkg/client/auth" + "helm.sh/helm/v3/internal/completion" "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/cli" "helm.sh/helm/v3/pkg/gates" + kubefake "helm.sh/helm/v3/pkg/kube/fake" + "helm.sh/helm/v3/pkg/release" + "helm.sh/helm/v3/pkg/storage/driver" ) // FeatureGateOCI is the feature gate for checking if `helm chart` and `helm registry` commands should work @@ -67,9 +73,23 @@ func main() { actionConfig := new(action.Configuration) cmd := newRootCmd(actionConfig, os.Stdout, os.Args[1:]) - if err := actionConfig.Init(settings.RESTClientGetter(), settings.Namespace(), os.Getenv("HELM_DRIVER"), debug); err != nil { + if calledCmd, _, err := cmd.Find(os.Args[1:]); err == nil && calledCmd.Name() == completion.CompRequestCmd { + // If completion is being called, we have to check if the completion is for the "--kube-context" + // value; if it is, we cannot call the action.Init() method with an incomplete kube-context value + // or else it will fail immediately. So, we simply unset the invalid kube-context value. + if args := os.Args[1:]; len(args) > 2 && args[len(args)-2] == "--kube-context" { + // We are completing the kube-context value! Reset it as the current value is not valid. + settings.KubeContext = "" + } + } + + helmDriver := os.Getenv("HELM_DRIVER") + if err := actionConfig.Init(settings.RESTClientGetter(), settings.Namespace(), helmDriver, debug); err != nil { log.Fatal(err) } + if helmDriver == "memory" { + loadReleasesInMemory(actionConfig) + } if err := cmd.Execute(); err != nil { debug("%+v", err) @@ -95,3 +115,41 @@ func checkOCIFeatureGate() func(_ *cobra.Command, _ []string) error { return nil } } + +// This function loads releases into the memory storage if the +// environment variable is properly set. +func loadReleasesInMemory(actionConfig *action.Configuration) { + filePaths := strings.Split(os.Getenv("HELM_MEMORY_DRIVER_DATA"), ":") + if len(filePaths) == 0 { + return + } + + store := actionConfig.Releases + mem, ok := store.Driver.(*driver.Memory) + if !ok { + // For an unexpected reason we are not dealing with the memory storage driver. + return + } + + actionConfig.KubeClient = &kubefake.PrintingKubeClient{Out: ioutil.Discard} + + for _, path := range filePaths { + b, err := ioutil.ReadFile(path) + if err != nil { + log.Fatal("Unable to read memory driver data", err) + } + + releases := []*release.Release{} + if err := yaml.Unmarshal(b, &releases); err != nil { + log.Fatal("Unable to unmarshal memory driver data: ", err) + } + + for _, rel := range releases { + if err := store.Create(rel); err != nil { + log.Fatal(err) + } + } + } + // Must reset namespace to the proper one + mem.SetNamespace(settings.Namespace()) +} diff --git a/cmd/helm/helm_test.go b/cmd/helm/helm_test.go index 5f9d80a3a..94646a5a3 100644 --- a/cmd/helm/helm_test.go +++ b/cmd/helm/helm_test.go @@ -18,7 +18,6 @@ package main import ( "bytes" - "fmt" "io/ioutil" "os" "os/exec" @@ -97,39 +96,11 @@ func storageFixture() *storage.Storage { return storage.Init(driver.NewMemory()) } -// go-shellwords does not handle empty arguments properly -// https://github.com/mattn/go-shellwords/issues/5#issuecomment-573431458 -// -// This method checks if the last argument was an empty one, -// and if go-shellwords missed it, we add it ourselves. -// -// This is important for completion tests as completion often -// uses an empty last parameter. -func checkLastEmpty(in string, out []string) []string { - lastIndex := len(in) - 1 - - if lastIndex >= 1 && (in[lastIndex] == '"' && in[lastIndex-1] == '"' || - in[lastIndex] == '\'' && in[lastIndex-1] == '\'') { - // The last parameter of 'in' was empty ("" or ''), let's make sure it was detected. - if len(out) > 0 && out[len(out)-1] != "" { - // Bug from go-shellwords: - // 'out' does not have the empty parameter. We add it ourselves as a workaround. - out = append(out, "") - } else { - fmt.Println("WARNING: go-shellwords seems to have been fixed. This workaround can be removed.") - } - } - return out -} - func executeActionCommandC(store *storage.Storage, cmd string) (*cobra.Command, string, error) { args, err := shellwords.Parse(cmd) if err != nil { return nil, "", err } - // Workaround the bug in shellwords - args = checkLastEmpty(cmd, args) - buf := new(bytes.Buffer) actionConfig := &action.Configuration{ @@ -143,6 +114,9 @@ func executeActionCommandC(store *storage.Storage, cmd string) (*cobra.Command, root.SetOutput(buf) root.SetArgs(args) + if mem, ok := store.Driver.(*driver.Memory); ok { + mem.SetNamespace(settings.Namespace()) + } c, err := root.ExecuteC() return c, buf.String(), err diff --git a/cmd/helm/install.go b/cmd/helm/install.go index 0f548c90c..719dc9014 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -130,11 +130,13 @@ func newInstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { addInstallFlags(cmd.Flags(), client, valueOpts) bindOutputFlag(cmd, &outfmt) + bindPostRenderFlag(cmd, &client.PostRenderer) return cmd } func addInstallFlags(f *pflag.FlagSet, client *action.Install, valueOpts *values.Options) { + f.BoolVar(&client.CreateNamespace, "create-namespace", false, "create the release namespace if not present") f.BoolVar(&client.DryRun, "dry-run", false, "simulate an install") f.BoolVar(&client.DisableHooks, "no-hooks", false, "prevent hooks from running during install") f.BoolVar(&client.Replace, "replace", false, "re-use the given name, only if that name is a deleted release which remains in the history. This is unsafe in production") @@ -145,6 +147,7 @@ func addInstallFlags(f *pflag.FlagSet, client *action.Install, valueOpts *values f.StringVar(&client.Description, "description", "", "add a custom description") f.BoolVar(&client.Devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored") f.BoolVar(&client.DependencyUpdate, "dependency-update", false, "run helm dependency update before installing the chart") + f.BoolVar(&client.DisableOpenAPIValidation, "disable-openapi-validation", false, "if set, the installation process will not validate rendered templates against the Kubernetes OpenAPI Schema") f.BoolVar(&client.Atomic, "atomic", false, "if set, installation process purges chart on fail. The --wait flag will be set automatically if --atomic is used") f.BoolVar(&client.SkipCRDs, "skip-crds", false, "if set, no CRDs will be installed. By default, CRDs are installed if not already present") f.BoolVar(&client.SubNotes, "render-subchart-notes", false, "if set, render subchart notes along with the parent") diff --git a/cmd/helm/lint.go b/cmd/helm/lint.go index 9a2e8d31c..bc0d1852b 100644 --- a/cmd/helm/lint.go +++ b/cmd/helm/lint.go @@ -19,6 +19,8 @@ package main import ( "fmt" "io" + "os" + "path/filepath" "strings" "github.com/pkg/errors" @@ -51,6 +53,21 @@ func newLintCmd(out io.Writer) *cobra.Command { if len(args) > 0 { paths = args } + if client.WithSubcharts { + for _, p := range paths { + filepath.Walk(filepath.Join(p, "charts"), func(path string, info os.FileInfo, err error) error { + if info != nil { + if info.Name() == "Chart.yaml" { + paths = append(paths, filepath.Dir(path)) + } else if strings.HasSuffix(path, ".tgz") || strings.HasSuffix(path, ".tar.gz") { + paths = append(paths, path) + } + } + return nil + }) + } + } + client.Namespace = settings.Namespace() vals, err := valueOpts.MergeValues(getter.All(settings)) if err != nil { @@ -102,6 +119,7 @@ func newLintCmd(out io.Writer) *cobra.Command { f := cmd.Flags() f.BoolVar(&client.Strict, "strict", false, "fail on lint warnings") + f.BoolVar(&client.WithSubcharts, "with-subcharts", false, "lint dependent charts") addValueOptionsFlags(f, valueOpts) return cmd diff --git a/cmd/helm/lint_test.go b/cmd/helm/lint_test.go new file mode 100644 index 000000000..7638acb84 --- /dev/null +++ b/cmd/helm/lint_test.go @@ -0,0 +1,38 @@ +/* +Copyright The Helm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "fmt" + "testing" +) + +func TestLintCmdWithSubchartsFlag(t *testing.T) { + testChart := "testdata/testcharts/chart-with-bad-subcharts" + tests := []cmdTestCase{{ + name: "lint good chart with bad subcharts", + cmd: fmt.Sprintf("lint %s", testChart), + golden: "output/lint-chart-with-bad-subcharts.txt", + wantError: false, + }, { + name: "lint good chart with bad subcharts using --with-subcharts flag", + cmd: fmt.Sprintf("lint --with-subcharts %s", testChart), + golden: "output/lint-chart-with-bad-subcharts-with-subcharts.txt", + wantError: true, + }} + runTestCmd(t, tests) +} diff --git a/cmd/helm/list_test.go b/cmd/helm/list_test.go index 127a8a980..fe773a803 100644 --- a/cmd/helm/list_test.go +++ b/cmd/helm/list_test.go @@ -131,6 +131,16 @@ func TestListCmd(t *testing.T) { }, Chart: chartInfo, }, + { + Name: "starlord", + Version: 2, + Namespace: "milano", + Info: &release.Info{ + LastDeployed: timestamp1, + Status: release.StatusDeployed, + }, + Chart: chartInfo, + }, } tests := []cmdTestCase{{ @@ -203,6 +213,11 @@ func TestListCmd(t *testing.T) { cmd: "list --uninstalling", golden: "output/list-uninstalling.txt", rels: releaseFixture, + }, { + name: "list releases in another namespace", + cmd: "list -n milano", + golden: "output/list-namespace.txt", + rels: releaseFixture, }} runTestCmd(t, tests) } diff --git a/cmd/helm/load_plugins.go b/cmd/helm/load_plugins.go index f2fb5c01d..e56feab40 100644 --- a/cmd/helm/load_plugins.go +++ b/cmd/helm/load_plugins.go @@ -16,20 +16,31 @@ limitations under the License. package main import ( + "bytes" "fmt" "io" + "io/ioutil" + "log" "os" "os/exec" "path/filepath" + "strconv" "strings" "syscall" "github.com/pkg/errors" "github.com/spf13/cobra" + "sigs.k8s.io/yaml" + "helm.sh/helm/v3/internal/completion" "helm.sh/helm/v3/pkg/plugin" ) +const ( + pluginStaticCompletionFile = "completion.yaml" + pluginDynamicCompletionExecutable = "plugin.complete" +) + type pluginError struct { error code int @@ -61,6 +72,13 @@ func loadPlugins(baseCmd *cobra.Command, out io.Writer) { return u, nil } + // If we are dealing with the completion command, we try to load more details about the plugins + // if available, so as to allow for command and flag completion + if subCmd, _, err := baseCmd.Find(os.Args[1:]); err == nil && subCmd.Name() == "completion" { + loadPluginsForCompletion(baseCmd, found) + return + } + // Now we create commands for all of these. for _, plug := range found { plug := plug @@ -69,6 +87,33 @@ func loadPlugins(baseCmd *cobra.Command, out io.Writer) { md.Usage = fmt.Sprintf("the %q plugin", md.Name) } + // This function is used to setup the environment for the plugin and then + // call the executable specified by the parameter 'main' + callPluginExecutable := func(cmd *cobra.Command, main string, argv []string, out io.Writer) error { + env := os.Environ() + for k, v := range settings.EnvVars() { + env = append(env, fmt.Sprintf("%s=%s", k, v)) + } + + prog := exec.Command(main, argv...) + prog.Env = env + prog.Stdin = os.Stdin + prog.Stdout = out + prog.Stderr = os.Stderr + if err := prog.Run(); err != nil { + if eerr, ok := err.(*exec.ExitError); ok { + os.Stderr.Write(eerr.Stderr) + status := eerr.Sys().(syscall.WaitStatus) + return pluginError{ + error: errors.Errorf("plugin %q exited with error", md.Name), + code: status.ExitStatus(), + } + } + return err + } + return nil + } + c := &cobra.Command{ Use: md.Name, Short: md.Usage, @@ -89,33 +134,59 @@ func loadPlugins(baseCmd *cobra.Command, out io.Writer) { return errors.Errorf("plugin %q exited with error", md.Name) } - env := os.Environ() - for k, v := range settings.EnvVars() { - env = append(env, fmt.Sprintf("%s=%s", k, v)) - } - - prog := exec.Command(main, argv...) - prog.Env = env - prog.Stdin = os.Stdin - prog.Stdout = out - prog.Stderr = os.Stderr - if err := prog.Run(); err != nil { - if eerr, ok := err.(*exec.ExitError); ok { - os.Stderr.Write(eerr.Stderr) - status := eerr.Sys().(syscall.WaitStatus) - return pluginError{ - error: errors.Errorf("plugin %q exited with error", md.Name), - code: status.ExitStatus(), - } - } - return err - } - return nil + return callPluginExecutable(cmd, main, argv, out) }, // This passes all the flags to the subcommand. DisableFlagParsing: true, } + // Setup dynamic completion for the plugin + completion.RegisterValidArgsFunc(c, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { + u, err := processParent(cmd, args) + if err != nil { + return nil, completion.BashCompDirectiveError + } + + // We will call the dynamic completion script of the plugin + main := strings.Join([]string{plug.Dir, pluginDynamicCompletionExecutable}, string(filepath.Separator)) + + argv := []string{} + if !md.IgnoreFlags { + argv = append(argv, u...) + argv = append(argv, toComplete) + } + plugin.SetupPluginEnv(settings, md.Name, plug.Dir) + + completion.CompDebugln(fmt.Sprintf("calling %s with args %v", main, argv)) + buf := new(bytes.Buffer) + if err := callPluginExecutable(cmd, main, argv, buf); err != nil { + return nil, completion.BashCompDirectiveError + } + + var completions []string + for _, comp := range strings.Split(buf.String(), "\n") { + // Remove any empty lines + if len(comp) > 0 { + completions = append(completions, comp) + } + } + + // Check if the last line of output is of the form :, which + // indicates the BashCompletionDirective. + directive := completion.BashCompDirectiveDefault + if len(completions) > 0 { + lastLine := completions[len(completions)-1] + if len(lastLine) > 1 && lastLine[0] == ':' { + if strInt, err := strconv.Atoi(lastLine[1:]); err == nil { + directive = completion.BashCompDirective(strInt) + completions = completions[:len(completions)-1] + } + } + } + + return completions, directive + }) + // TODO: Make sure a command with this name does not already exist. baseCmd.AddCommand(c) } @@ -127,7 +198,7 @@ func loadPlugins(baseCmd *cobra.Command, out io.Writer) { func manuallyProcessArgs(args []string) ([]string, []string) { known := []string{} unknown := []string{} - kvargs := []string{"--kube-context", "--namespace", "-n", "--kubeconfig", "--registry-config", "--repository-cache", "--repository-config"} + kvargs := []string{"--kube-context", "--namespace", "-n", "--kubeconfig", "--kube-apiserver", "--kube-token", "--registry-config", "--repository-cache", "--repository-config"} knownArg := func(a string) bool { for _, pre := range kvargs { if strings.HasPrefix(a, pre+"=") { @@ -180,3 +251,119 @@ func findPlugins(plugdirs string) ([]*plugin.Plugin, error) { } return found, nil } + +// pluginCommand represents the optional completion.yaml file of a plugin +type pluginCommand struct { + Name string `json:"name"` + ValidArgs []string `json:"validArgs"` + Flags []string `json:"flags"` + Commands []pluginCommand `json:"commands"` +} + +// loadPluginsForCompletion will load and parse any completion.yaml provided by the plugins +func loadPluginsForCompletion(baseCmd *cobra.Command, plugins []*plugin.Plugin) { + for _, plug := range plugins { + // Parse the yaml file providing the plugin's subcmds and flags + cmds, err := loadFile(strings.Join( + []string{plug.Dir, pluginStaticCompletionFile}, string(filepath.Separator))) + + if err != nil { + // The file could be missing or invalid. Either way, we at least create the command + // for the plugin name. + if settings.Debug { + log.Output(2, fmt.Sprintf("[info] %s\n", err.Error())) + } + cmds = &pluginCommand{Name: plug.Metadata.Name} + } + + // We know what the plugin name must be. + // Let's set it in case the Name field was not specified correctly in the file. + // This insures that we will at least get the plugin name to complete, even if + // there is a problem with the completion.yaml file + cmds.Name = plug.Metadata.Name + + addPluginCommands(baseCmd, cmds) + } +} + +// addPluginCommands is a recursive method that adds the different levels +// of sub-commands and flags for the plugins that provide such information +func addPluginCommands(baseCmd *cobra.Command, cmds *pluginCommand) { + if cmds == nil { + return + } + + if len(cmds.Name) == 0 { + // Missing name for a command + if settings.Debug { + log.Output(2, fmt.Sprintf("[info] sub-command name field missing for %s", baseCmd.CommandPath())) + } + return + } + + // Create a fake command just so the completion script will include it + c := &cobra.Command{ + Use: cmds.Name, + ValidArgs: cmds.ValidArgs, + // A Run is required for it to be a valid command without subcommands + Run: func(cmd *cobra.Command, args []string) {}, + } + baseCmd.AddCommand(c) + + // Create fake flags. + if len(cmds.Flags) > 0 { + // The flags can be created with any type, since we only need them for completion. + // pflag does not allow to create short flags without a corresponding long form + // so we look for all short flags and match them to any long flag. This will allow + // plugins to provide short flags without a long form. + // If there are more short-flags than long ones, we'll create an extra long flag with + // the same single letter as the short form. + shorts := []string{} + longs := []string{} + for _, flag := range cmds.Flags { + if len(flag) == 1 { + shorts = append(shorts, flag) + } else { + longs = append(longs, flag) + } + } + + f := c.Flags() + if len(longs) >= len(shorts) { + for i := range longs { + if i < len(shorts) { + f.BoolP(longs[i], shorts[i], false, "") + } else { + f.Bool(longs[i], false, "") + } + } + } else { + for i := range shorts { + if i < len(longs) { + f.BoolP(longs[i], shorts[i], false, "") + } else { + // Create a long flag with the same name as the short flag. + // Not a perfect solution, but its better than ignoring the extra short flags. + f.BoolP(shorts[i], shorts[i], false, "") + } + } + } + } + + // Recursively add any sub-commands + for _, cmd := range cmds.Commands { + addPluginCommands(c, &cmd) + } +} + +// loadFile takes a yaml file at the given path, parses it and returns a pluginCommand object +func loadFile(path string) (*pluginCommand, error) { + cmds := new(pluginCommand) + b, err := ioutil.ReadFile(path) + if err != nil { + return cmds, errors.New(fmt.Sprintf("File (%s) not provided by plugin. No plugin auto-completion possible.", path)) + } + + err = yaml.Unmarshal(b, cmds) + return cmds, err +} diff --git a/cmd/helm/plugin_test.go b/cmd/helm/plugin_test.go index 3fd3a4197..e43f277a5 100644 --- a/cmd/helm/plugin_test.go +++ b/cmd/helm/plugin_test.go @@ -19,10 +19,14 @@ import ( "bytes" "os" "runtime" + "sort" "strings" "testing" "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "helm.sh/helm/v3/pkg/release" ) func TestManuallyProcessArgs(t *testing.T) { @@ -151,6 +155,134 @@ func TestLoadPlugins(t *testing.T) { } } +type staticCompletionDetails struct { + use string + validArgs []string + flags []string + next []staticCompletionDetails +} + +func TestLoadPluginsForCompletion(t *testing.T) { + settings.PluginsDirectory = "testdata/helmhome/helm/plugins" + + var out bytes.Buffer + + cmd := &cobra.Command{ + Use: "completion", + } + + loadPlugins(cmd, &out) + + tests := []staticCompletionDetails{ + {"args", []string{}, []string{}, []staticCompletionDetails{}}, + {"echo", []string{}, []string{}, []staticCompletionDetails{}}, + {"env", []string{}, []string{"global"}, []staticCompletionDetails{ + {"list", []string{}, []string{"a", "all", "log"}, []staticCompletionDetails{}}, + {"remove", []string{"all", "one"}, []string{}, []staticCompletionDetails{}}, + }}, + {"exitwith", []string{}, []string{}, []staticCompletionDetails{ + {"code", []string{}, []string{"a", "b"}, []staticCompletionDetails{}}, + }}, + {"fullenv", []string{}, []string{"q", "z"}, []staticCompletionDetails{ + {"empty", []string{}, []string{}, []staticCompletionDetails{}}, + {"full", []string{}, []string{}, []staticCompletionDetails{ + {"less", []string{}, []string{"a", "all"}, []staticCompletionDetails{}}, + {"more", []string{"one", "two"}, []string{"b", "ball"}, []staticCompletionDetails{}}, + }}, + }}, + } + checkCommand(t, cmd.Commands(), tests) +} + +func checkCommand(t *testing.T, plugins []*cobra.Command, tests []staticCompletionDetails) { + if len(plugins) != len(tests) { + t.Fatalf("Expected commands %v, got %v", tests, plugins) + } + + for i := 0; i < len(plugins); i++ { + pp := plugins[i] + tt := tests[i] + if pp.Use != tt.use { + t.Errorf("%s: Expected Use=%q, got %q", pp.Name(), tt.use, pp.Use) + } + + targs := tt.validArgs + pargs := pp.ValidArgs + if len(targs) != len(pargs) { + t.Fatalf("%s: expected args %v, got %v", pp.Name(), targs, pargs) + } + + sort.Strings(targs) + sort.Strings(pargs) + for j := range targs { + if targs[j] != pargs[j] { + t.Errorf("%s: expected validArg=%q, got %q", pp.Name(), targs[j], pargs[j]) + } + } + + tflags := tt.flags + var pflags []string + pp.LocalFlags().VisitAll(func(flag *pflag.Flag) { + pflags = append(pflags, flag.Name) + if len(flag.Shorthand) > 0 && flag.Shorthand != flag.Name { + pflags = append(pflags, flag.Shorthand) + } + }) + if len(tflags) != len(pflags) { + t.Fatalf("%s: expected flags %v, got %v", pp.Name(), tflags, pflags) + } + + sort.Strings(tflags) + sort.Strings(pflags) + for j := range tflags { + if tflags[j] != pflags[j] { + t.Errorf("%s: expected flag=%q, got %q", pp.Name(), tflags[j], pflags[j]) + } + } + // Check the next level + checkCommand(t, pp.Commands(), tt.next) + } +} + +func TestPluginDynamicCompletion(t *testing.T) { + + tests := []cmdTestCase{{ + name: "completion for plugin", + cmd: "__complete args ''", + golden: "output/plugin_args_comp.txt", + rels: []*release.Release{}, + }, { + name: "completion for plugin with flag", + cmd: "__complete args --myflag ''", + golden: "output/plugin_args_flag_comp.txt", + rels: []*release.Release{}, + }, { + name: "completion for plugin with global flag", + cmd: "__complete args --namespace mynamespace ''", + golden: "output/plugin_args_ns_comp.txt", + rels: []*release.Release{}, + }, { + name: "completion for plugin with multiple args", + cmd: "__complete args --myflag --namespace mynamespace start", + golden: "output/plugin_args_many_args_comp.txt", + rels: []*release.Release{}, + }, { + name: "completion for plugin no directive", + cmd: "__complete echo -n mynamespace ''", + golden: "output/plugin_echo_no_directive.txt", + rels: []*release.Release{}, + }, { + name: "completion for plugin bad directive", + cmd: "__complete echo ''", + golden: "output/plugin_echo_bad_directive.txt", + rels: []*release.Release{}, + }} + for _, test := range tests { + settings.PluginsDirectory = "testdata/helmhome/helm/plugins" + runTestCmd(t, []cmdTestCase{test}) + } +} + func TestLoadPlugins_HelmNoPlugins(t *testing.T) { settings.PluginsDirectory = "testdata/helmhome/helm/plugins" settings.RepositoryConfig = "testdata/helmhome/helm/repository" diff --git a/cmd/helm/pull_test.go b/cmd/helm/pull_test.go index 1aca66100..d4661f928 100644 --- a/cmd/helm/pull_test.go +++ b/cmd/helm/pull_test.go @@ -20,7 +20,6 @@ import ( "fmt" "os" "path/filepath" - "regexp" "testing" "helm.sh/helm/v3/pkg/repo/repotest" @@ -37,6 +36,10 @@ func TestPullCmd(t *testing.T) { t.Fatal(err) } + helmTestKeyOut := "Signed by: Helm Testing (This key should only be used for testing. DO NOT TRUST.) \n" + + "Using Key With Fingerprint: 5E615389B53CA37F0EE60BD3843BBF981FC18762\n" + + "Chart Hash Verified: " + // all flags will get "-d outdir" appended. tests := []struct { name string @@ -49,6 +52,7 @@ func TestPullCmd(t *testing.T) { expectFile string expectDir bool expectVerify bool + expectSha string }{ { name: "Basic chart fetch", @@ -77,6 +81,7 @@ func TestPullCmd(t *testing.T) { args: "test/signtest --verify --keyring testdata/helm-test-key.pub", expectFile: "./signtest-0.1.0.tgz", expectVerify: true, + expectSha: "sha256:e5ef611620fb97704d8751c16bab17fedb68883bfb0edc76f78a70e9173f9b55", }, { name: "Fetch and fail verify", @@ -110,6 +115,7 @@ func TestPullCmd(t *testing.T) { expectFile: "./signtest2", expectDir: true, expectVerify: true, + expectSha: "sha256:e5ef611620fb97704d8751c16bab17fedb68883bfb0edc76f78a70e9173f9b55", }, { name: "Chart fetch using repo URL", @@ -171,13 +177,11 @@ func TestPullCmd(t *testing.T) { } if tt.expectVerify { - pointerAddressPattern := "0[xX][A-Fa-f0-9]+" - sha256Pattern := "[A-Fa-f0-9]{64}" - verificationRegex := regexp.MustCompile( - fmt.Sprintf("Verification: &{%s sha256:%s signtest-0.1.0.tgz}\n", pointerAddressPattern, sha256Pattern)) - if !verificationRegex.MatchString(out) { - t.Errorf("%q: expected match for regex %s, got %s", tt.name, verificationRegex, out) + outString := helmTestKeyOut + tt.expectSha + "\n" + if out != outString { + t.Errorf("%q: expected verification output %q, got %q", tt.name, outString, out) } + } ef := filepath.Join(outdir, tt.expectFile) diff --git a/cmd/helm/repo_index_test.go b/cmd/helm/repo_index_test.go index 51c5db80a..e04ae1b59 100644 --- a/cmd/helm/repo_index_test.go +++ b/cmd/helm/repo_index_test.go @@ -119,7 +119,7 @@ func TestRepoIndexCmd(t *testing.T) { t.Error(err) } - _, err = repo.LoadIndexFile(destIndex) + index, err = repo.LoadIndexFile(destIndex) if err != nil { t.Fatal(err) } @@ -130,8 +130,8 @@ func TestRepoIndexCmd(t *testing.T) { } vs = index.Entries["compressedchart"] - if len(vs) != 3 { - t.Errorf("expected 3 versions, got %d: %#v", len(vs), vs) + if len(vs) != 1 { + t.Errorf("expected 1 versions, got %d: %#v", len(vs), vs) } expectedVersion = "0.3.0" diff --git a/cmd/helm/root.go b/cmd/helm/root.go index 6ce1dcbf4..3ebea3bae 100644 --- a/cmd/helm/root.go +++ b/cmd/helm/root.go @@ -24,37 +24,13 @@ import ( "github.com/spf13/cobra" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/tools/clientcmd" - "helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v3/internal/completion" "helm.sh/helm/v3/internal/experimental/registry" "helm.sh/helm/v3/pkg/action" ) -const ( - contextCompFunc = ` -__helm_get_contexts() -{ - __helm_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" - local template out - template="{{ range .contexts }}{{ .name }} {{ end }}" - if out=$(kubectl config -o template --template="${template}" view 2>/dev/null); then - COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) ) - fi -} -` -) - -var ( - // Mapping of global flags that can have dynamic completion and the - // completion function to be used. - bashCompletionFlags = map[string]string{ - // Cannot convert the kube-context flag to Go completion yet because - // an incomplete kube-context will make actionConfig.Init() fail at the very start - "kube-context": "__helm_get_contexts", - } -) - var globalUsage = `The Kubernetes package manager Common actions for Helm: @@ -100,15 +76,14 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string Short: "The Helm package manager for Kubernetes.", Long: globalUsage, SilenceUsage: true, - Args: require.NoArgs, - BashCompletionFunction: fmt.Sprintf("%s%s", contextCompFunc, completion.GetBashCustomFunction()), + BashCompletionFunction: completion.GetBashCustomFunction(), } flags := cmd.PersistentFlags() settings.AddFlags(flags) - flag := flags.Lookup("namespace") // Setup shell completion for the namespace flag + flag := flags.Lookup("namespace") completion.RegisterFlagCompletionFunc(flag, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { if client, err := actionConfig.KubernetesClientSet(); err == nil { // Choose a long enough timeout that the user notices somethings is not working @@ -129,6 +104,29 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string return nil, completion.BashCompDirectiveDefault }) + // Setup shell completion for the kube-context flag + flag = flags.Lookup("kube-context") + completion.RegisterFlagCompletionFunc(flag, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { + completion.CompDebugln("About to get the different kube-contexts") + + loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() + if len(settings.KubeConfig) > 0 { + loadingRules = &clientcmd.ClientConfigLoadingRules{ExplicitPath: settings.KubeConfig} + } + if config, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( + loadingRules, + &clientcmd.ConfigOverrides{}).RawConfig(); err == nil { + ctxs := []string{} + for name := range config.Contexts { + if strings.HasPrefix(name, toComplete) { + ctxs = append(ctxs, name) + } + } + return ctxs, completion.BashCompDirectiveNoFileComp + } + return nil, completion.BashCompDirectiveNoFileComp + }) + // We can safely ignore any errors that flags.Parse encounters since // those errors will be caught later during the call to cmd.Execution. // This call is required to gather configuration information prior to @@ -173,19 +171,6 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string completion.NewCompleteCmd(settings, out), ) - // Add annotation to flags for which we can generate completion choices - for name, completion := range bashCompletionFlags { - if cmd.Flag(name) != nil { - if cmd.Flag(name).Annotations == nil { - cmd.Flag(name).Annotations = map[string][]string{} - } - cmd.Flag(name).Annotations[cobra.BashCompCustom] = append( - cmd.Flag(name).Annotations[cobra.BashCompCustom], - completion, - ) - } - } - // Add *experimental* subcommands registryClient, err := registry.NewClient( registry.ClientOptDebug(settings.Debug), diff --git a/cmd/helm/root_test.go b/cmd/helm/root_test.go index df592a96d..e1fa1fc27 100644 --- a/cmd/helm/root_test.go +++ b/cmd/helm/root_test.go @@ -95,3 +95,11 @@ func TestRootCmd(t *testing.T) { }) } } + +func TestUnknownSubCmd(t *testing.T) { + _, _, err := executeActionCommand("foobar") + + if err == nil || err.Error() != `unknown command "foobar" for "helm"` { + t.Errorf("Expect unknown command error, got %q", err) + } +} diff --git a/cmd/helm/search_repo.go b/cmd/helm/search_repo.go index 9f5af1e3c..8a8ac379d 100644 --- a/cmd/helm/search_repo.go +++ b/cmd/helm/search_repo.go @@ -22,6 +22,7 @@ import ( "fmt" "io" "io/ioutil" + "os" "path/filepath" "strings" @@ -102,7 +103,7 @@ func newSearchRepoCmd(out io.Writer) *cobra.Command { func (o *searchRepoOptions) run(out io.Writer, args []string) error { o.setupSearchedVersion() - index, err := o.buildIndex(out) + index, err := o.buildIndex() if err != nil { return err } @@ -171,7 +172,7 @@ func (o *searchRepoOptions) applyConstraint(res []*search.Result) ([]*search.Res return data, nil } -func (o *searchRepoOptions) buildIndex(out io.Writer) (*search.Index, error) { +func (o *searchRepoOptions) buildIndex() (*search.Index, error) { // Load the repositories.yaml rf, err := repo.LoadFile(o.repoFile) if isNotExist(err) || len(rf.Repositories) == 0 { @@ -184,8 +185,7 @@ func (o *searchRepoOptions) buildIndex(out io.Writer) (*search.Index, error) { f := filepath.Join(o.repoCacheDir, helmpath.CacheIndexFile(n)) ind, err := repo.LoadIndexFile(f) if err != nil { - // TODO should print to stderr - fmt.Fprintf(out, "WARNING: Repo %q is corrupt or missing. Try 'helm repo update'.", n) + fmt.Fprintf(os.Stderr, "WARNING: Repo %q is corrupt or missing. Try 'helm repo update'.", n) continue } diff --git a/cmd/helm/template.go b/cmd/helm/template.go index dc62c6e95..bd14cde1d 100644 --- a/cmd/helm/template.go +++ b/cmd/helm/template.go @@ -24,8 +24,6 @@ import ( "regexp" "strings" - "helm.sh/helm/v3/pkg/releaseutil" - "github.com/spf13/cobra" "helm.sh/helm/v3/cmd/helm/require" @@ -33,6 +31,7 @@ import ( "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/chartutil" "helm.sh/helm/v3/pkg/cli/values" + "helm.sh/helm/v3/pkg/releaseutil" ) const templateDesc = ` @@ -53,7 +52,7 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { cmd := &cobra.Command{ Use: "template [NAME] [CHART]", - Short: fmt.Sprintf("locally render templates"), + Short: "locally render templates", Long: templateDesc, Args: require.MinimumNArgs(1), RunE: func(_ *cobra.Command, args []string) error { @@ -62,65 +61,67 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { client.Replace = true // Skip the name check client.ClientOnly = !validate client.APIVersions = chartutil.VersionSet(extraAPIs) + client.IncludeCRDs = includeCrds rel, err := runInstall(args, client, valueOpts, out) - if err != nil { - return err - } - var manifests bytes.Buffer - - if includeCrds { - for _, f := range rel.Chart.CRDs() { - fmt.Fprintf(&manifests, "---\n# Source: %s\n%s\n", f.Name, f.Data) + if err != nil && !settings.Debug { + if rel != nil { + return fmt.Errorf("%w\n\nUse --debug flag to render out invalid YAML", err) } + return err } - fmt.Fprintln(&manifests, strings.TrimSpace(rel.Manifest)) + // We ignore a potential error here because, when the --debug flag was specified, + // we always want to print the YAML, even if it is not valid. The error is still returned afterwards. + if rel != nil { + var manifests bytes.Buffer + fmt.Fprintln(&manifests, strings.TrimSpace(rel.Manifest)) - if !client.DisableHooks { - for _, m := range rel.Hooks { - fmt.Fprintf(&manifests, "---\n# Source: %s\n%s\n", m.Path, m.Manifest) + if !client.DisableHooks { + for _, m := range rel.Hooks { + fmt.Fprintf(&manifests, "---\n# Source: %s\n%s\n", m.Path, m.Manifest) + } } - } - // if we have a list of files to render, then check that each of the - // provided files exists in the chart. - if len(showFiles) > 0 { - splitManifests := releaseutil.SplitManifests(manifests.String()) - manifestNameRegex := regexp.MustCompile("# Source: [^/]+/(.+)") - var manifestsToRender []string - for _, f := range showFiles { - missing := true - for _, manifest := range splitManifests { - submatch := manifestNameRegex.FindStringSubmatch(manifest) - if len(submatch) == 0 { - continue + // if we have a list of files to render, then check that each of the + // provided files exists in the chart. + if len(showFiles) > 0 { + splitManifests := releaseutil.SplitManifests(manifests.String()) + manifestNameRegex := regexp.MustCompile("# Source: [^/]+/(.+)") + var manifestsToRender []string + for _, f := range showFiles { + missing := true + for _, manifest := range splitManifests { + submatch := manifestNameRegex.FindStringSubmatch(manifest) + if len(submatch) == 0 { + continue + } + manifestName := submatch[1] + // manifest.Name is rendered using linux-style filepath separators on Windows as + // well as macOS/linux. + manifestPathSplit := strings.Split(manifestName, "/") + manifestPath := filepath.Join(manifestPathSplit...) + + // if the filepath provided matches a manifest path in the + // chart, render that manifest + if f == manifestPath { + manifestsToRender = append(manifestsToRender, manifest) + missing = false + } } - manifestName := submatch[1] - // manifest.Name is rendered using linux-style filepath separators on Windows as - // well as macOS/linux. - manifestPathSplit := strings.Split(manifestName, "/") - manifestPath := filepath.Join(manifestPathSplit...) - - // if the filepath provided matches a manifest path in the - // chart, render that manifest - if f == manifestPath { - manifestsToRender = append(manifestsToRender, manifest) - missing = false + if missing { + return fmt.Errorf("could not find template %s in chart", f) } } - if missing { - return fmt.Errorf("could not find template %s in chart", f) + for _, m := range manifestsToRender { + fmt.Fprintf(out, "---\n%s\n", m) } + } else { + fmt.Fprintf(out, "%s", manifests.String()) } - for _, m := range manifestsToRender { - fmt.Fprintf(out, "---\n%s\n", m) - } - } else { - fmt.Fprintf(out, "%s", manifests.String()) } - return nil + return err }, } @@ -137,6 +138,8 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { f.BoolVar(&includeCrds, "include-crds", false, "include CRDs in the templated output") f.BoolVar(&client.IsUpgrade, "is-upgrade", false, "set .Release.IsUpgrade instead of .Release.IsInstall") f.StringArrayVarP(&extraAPIs, "api-versions", "a", []string{}, "Kubernetes api versions used for Capabilities.APIVersions") + f.BoolVar(&client.UseReleaseName, "release-name", false, "use release name in the output-dir path.") + bindPostRenderFlag(cmd, &client.PostRenderer) return cmd } diff --git a/cmd/helm/template_test.go b/cmd/helm/template_test.go index dc7987d01..3fd139fad 100644 --- a/cmd/helm/template_test.go +++ b/cmd/helm/template_test.go @@ -102,6 +102,18 @@ func TestTemplateCmd(t *testing.T) { // don't accidentally get the expected result. repeat: 10, }, + { + name: "chart with template with invalid yaml", + cmd: fmt.Sprintf("template '%s'", "testdata/testcharts/chart-with-template-with-invalid-yaml"), + wantError: true, + golden: "output/template-with-invalid-yaml.txt", + }, + { + name: "chart with template with invalid yaml (--debug)", + cmd: fmt.Sprintf("template '%s' --debug", "testdata/testcharts/chart-with-template-with-invalid-yaml"), + wantError: true, + golden: "output/template-with-invalid-yaml-debug.txt", + }, } runTestCmd(t, tests) } diff --git a/cmd/helm/testdata/helmhome/helm/plugins/args/plugin.complete b/cmd/helm/testdata/helmhome/helm/plugins/args/plugin.complete new file mode 100755 index 000000000..2b00c2281 --- /dev/null +++ b/cmd/helm/testdata/helmhome/helm/plugins/args/plugin.complete @@ -0,0 +1,13 @@ +#!/usr/bin/env sh + +echo "plugin.complete was called" +echo "Namespace: ${HELM_NAMESPACE:-NO_NS}" +echo "Num args received: ${#}" +echo "Args received: ${@}" + +# Final printout is the optional completion directive of the form : +if [ "$HELM_NAMESPACE" = "default" ]; then + echo ":4" +else + echo ":2" +fi diff --git a/cmd/helm/testdata/helmhome/helm/plugins/echo/completion.yaml b/cmd/helm/testdata/helmhome/helm/plugins/echo/completion.yaml new file mode 100644 index 000000000..e69de29bb diff --git a/cmd/helm/testdata/helmhome/helm/plugins/echo/plugin.complete b/cmd/helm/testdata/helmhome/helm/plugins/echo/plugin.complete new file mode 100755 index 000000000..6bc73d130 --- /dev/null +++ b/cmd/helm/testdata/helmhome/helm/plugins/echo/plugin.complete @@ -0,0 +1,14 @@ +#!/usr/bin/env sh + +echo "echo plugin.complete was called" +echo "Namespace: ${HELM_NAMESPACE:-NO_NS}" +echo "Num args received: ${#}" +echo "Args received: ${@}" + +# Final printout is the optional completion directive of the form : +if [ "$HELM_NAMESPACE" = "default" ]; then + # Output an invalid directive, which should be ignored + echo ":2222" +# else + # Don't include the directive, to test it is really optional +fi diff --git a/cmd/helm/testdata/helmhome/helm/plugins/env/completion.yaml b/cmd/helm/testdata/helmhome/helm/plugins/env/completion.yaml new file mode 100644 index 000000000..e479a0503 --- /dev/null +++ b/cmd/helm/testdata/helmhome/helm/plugins/env/completion.yaml @@ -0,0 +1,13 @@ +name: env +commands: + - name: list + flags: + - a + - all + - log + - name: remove + validArgs: + - all + - one +flags: +- global diff --git a/cmd/helm/testdata/helmhome/helm/plugins/exitwith/completion.yaml b/cmd/helm/testdata/helmhome/helm/plugins/exitwith/completion.yaml new file mode 100644 index 000000000..e5bf440f6 --- /dev/null +++ b/cmd/helm/testdata/helmhome/helm/plugins/exitwith/completion.yaml @@ -0,0 +1,5 @@ +commands: + - name: code + flags: + - a + - b diff --git a/cmd/helm/testdata/helmhome/helm/plugins/fullenv/completion.yaml b/cmd/helm/testdata/helmhome/helm/plugins/fullenv/completion.yaml new file mode 100644 index 000000000..e0b161c69 --- /dev/null +++ b/cmd/helm/testdata/helmhome/helm/plugins/fullenv/completion.yaml @@ -0,0 +1,19 @@ +name: wrongname +commands: + - name: empty + - name: full + commands: + - name: more + validArgs: + - one + - two + flags: + - b + - ball + - name: less + flags: + - a + - all +flags: +- z +- q diff --git a/cmd/helm/testdata/output/lint-chart-with-bad-subcharts-with-subcharts.txt b/cmd/helm/testdata/output/lint-chart-with-bad-subcharts-with-subcharts.txt new file mode 100644 index 000000000..cda011b57 --- /dev/null +++ b/cmd/helm/testdata/output/lint-chart-with-bad-subcharts-with-subcharts.txt @@ -0,0 +1,16 @@ +==> Linting testdata/testcharts/chart-with-bad-subcharts +[INFO] Chart.yaml: icon is recommended +[WARNING] templates/: directory not found + +==> Linting testdata/testcharts/chart-with-bad-subcharts/charts/bad-subchart +[ERROR] Chart.yaml: name is required +[ERROR] Chart.yaml: apiVersion is required. The value must be either "v1" or "v2" +[ERROR] Chart.yaml: version is required +[INFO] Chart.yaml: icon is recommended +[WARNING] templates/: directory not found + +==> Linting testdata/testcharts/chart-with-bad-subcharts/charts/good-subchart +[INFO] Chart.yaml: icon is recommended +[WARNING] templates/: directory not found + +Error: 3 chart(s) linted, 1 chart(s) failed diff --git a/cmd/helm/testdata/output/lint-chart-with-bad-subcharts.txt b/cmd/helm/testdata/output/lint-chart-with-bad-subcharts.txt new file mode 100644 index 000000000..51f3f3718 --- /dev/null +++ b/cmd/helm/testdata/output/lint-chart-with-bad-subcharts.txt @@ -0,0 +1,5 @@ +==> Linting testdata/testcharts/chart-with-bad-subcharts +[INFO] Chart.yaml: icon is recommended +[WARNING] templates/: directory not found + +1 chart(s) linted, 0 chart(s) failed diff --git a/cmd/helm/testdata/output/list-namespace.txt b/cmd/helm/testdata/output/list-namespace.txt new file mode 100644 index 000000000..9382327d6 --- /dev/null +++ b/cmd/helm/testdata/output/list-namespace.txt @@ -0,0 +1,2 @@ +NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION +starlord milano 2 2016-01-16 00:00:01 +0000 UTC deployed chickadee-1.0.0 0.0.1 diff --git a/cmd/helm/testdata/output/plugin_args_comp.txt b/cmd/helm/testdata/output/plugin_args_comp.txt new file mode 100644 index 000000000..8fb01cc23 --- /dev/null +++ b/cmd/helm/testdata/output/plugin_args_comp.txt @@ -0,0 +1,5 @@ +plugin.complete was called +Namespace: default +Num args received: 1 +Args received: +:4 diff --git a/cmd/helm/testdata/output/plugin_args_flag_comp.txt b/cmd/helm/testdata/output/plugin_args_flag_comp.txt new file mode 100644 index 000000000..92f0e58a8 --- /dev/null +++ b/cmd/helm/testdata/output/plugin_args_flag_comp.txt @@ -0,0 +1,5 @@ +plugin.complete was called +Namespace: default +Num args received: 2 +Args received: --myflag +:4 diff --git a/cmd/helm/testdata/output/plugin_args_many_args_comp.txt b/cmd/helm/testdata/output/plugin_args_many_args_comp.txt new file mode 100644 index 000000000..86fa768bb --- /dev/null +++ b/cmd/helm/testdata/output/plugin_args_many_args_comp.txt @@ -0,0 +1,5 @@ +plugin.complete was called +Namespace: mynamespace +Num args received: 2 +Args received: --myflag start +:2 diff --git a/cmd/helm/testdata/output/plugin_args_ns_comp.txt b/cmd/helm/testdata/output/plugin_args_ns_comp.txt new file mode 100644 index 000000000..e12867daa --- /dev/null +++ b/cmd/helm/testdata/output/plugin_args_ns_comp.txt @@ -0,0 +1,5 @@ +plugin.complete was called +Namespace: mynamespace +Num args received: 1 +Args received: +:2 diff --git a/cmd/helm/testdata/output/plugin_echo_bad_directive.txt b/cmd/helm/testdata/output/plugin_echo_bad_directive.txt new file mode 100644 index 000000000..f4b86cd47 --- /dev/null +++ b/cmd/helm/testdata/output/plugin_echo_bad_directive.txt @@ -0,0 +1,5 @@ +echo plugin.complete was called +Namespace: default +Num args received: 1 +Args received: +:0 diff --git a/cmd/helm/testdata/output/plugin_echo_no_directive.txt b/cmd/helm/testdata/output/plugin_echo_no_directive.txt new file mode 100644 index 000000000..6266dd4d9 --- /dev/null +++ b/cmd/helm/testdata/output/plugin_echo_no_directive.txt @@ -0,0 +1,5 @@ +echo plugin.complete was called +Namespace: mynamespace +Num args received: 1 +Args received: +:0 diff --git a/cmd/helm/testdata/output/template-with-invalid-yaml-debug.txt b/cmd/helm/testdata/output/template-with-invalid-yaml-debug.txt new file mode 100644 index 000000000..c1f51185c --- /dev/null +++ b/cmd/helm/testdata/output/template-with-invalid-yaml-debug.txt @@ -0,0 +1,13 @@ +--- +# Source: chart-with-template-with-invalid-yaml/templates/alpine-pod.yaml +apiVersion: v1 +kind: Pod +metadata: + name: "RELEASE-NAME-my-alpine" +spec: + containers: + - name: waiter + image: "alpine:3.9" + command: ["/bin/sleep","9000"] +invalid +Error: YAML parse error on chart-with-template-with-invalid-yaml/templates/alpine-pod.yaml: error converting YAML to JSON: yaml: line 11: could not find expected ':' diff --git a/cmd/helm/testdata/output/template-with-invalid-yaml.txt b/cmd/helm/testdata/output/template-with-invalid-yaml.txt new file mode 100644 index 000000000..687227b90 --- /dev/null +++ b/cmd/helm/testdata/output/template-with-invalid-yaml.txt @@ -0,0 +1,3 @@ +Error: YAML parse error on chart-with-template-with-invalid-yaml/templates/alpine-pod.yaml: error converting YAML to JSON: yaml: line 11: could not find expected ':' + +Use --debug flag to render out invalid YAML diff --git a/cmd/helm/testdata/output/version-client-shorthand.txt b/cmd/helm/testdata/output/version-client-shorthand.txt index 4b493d31c..8f9ed6136 100644 --- a/cmd/helm/testdata/output/version-client-shorthand.txt +++ b/cmd/helm/testdata/output/version-client-shorthand.txt @@ -1 +1 @@ -version.BuildInfo{Version:"v3.0", GitCommit:"", GitTreeState:"", GoVersion:""} +version.BuildInfo{Version:"v3.1", GitCommit:"", GitTreeState:"", GoVersion:""} diff --git a/cmd/helm/testdata/output/version-client.txt b/cmd/helm/testdata/output/version-client.txt index 4b493d31c..8f9ed6136 100644 --- a/cmd/helm/testdata/output/version-client.txt +++ b/cmd/helm/testdata/output/version-client.txt @@ -1 +1 @@ -version.BuildInfo{Version:"v3.0", GitCommit:"", GitTreeState:"", GoVersion:""} +version.BuildInfo{Version:"v3.1", GitCommit:"", GitTreeState:"", GoVersion:""} diff --git a/cmd/helm/testdata/output/version-short.txt b/cmd/helm/testdata/output/version-short.txt index d9fb9c736..861668947 100644 --- a/cmd/helm/testdata/output/version-short.txt +++ b/cmd/helm/testdata/output/version-short.txt @@ -1 +1 @@ -v3.0 +v3.1 diff --git a/cmd/helm/testdata/output/version-template.txt b/cmd/helm/testdata/output/version-template.txt index 776c1919b..e5a779bbf 100644 --- a/cmd/helm/testdata/output/version-template.txt +++ b/cmd/helm/testdata/output/version-template.txt @@ -1 +1 @@ -Version: v3.0 \ No newline at end of file +Version: v3.1 \ No newline at end of file diff --git a/cmd/helm/testdata/output/version.txt b/cmd/helm/testdata/output/version.txt index 4b493d31c..8f9ed6136 100644 --- a/cmd/helm/testdata/output/version.txt +++ b/cmd/helm/testdata/output/version.txt @@ -1 +1 @@ -version.BuildInfo{Version:"v3.0", GitCommit:"", GitTreeState:"", GoVersion:""} +version.BuildInfo{Version:"v3.1", GitCommit:"", GitTreeState:"", GoVersion:""} diff --git a/cmd/helm/testdata/testcharts/alpine/README.md b/cmd/helm/testdata/testcharts/alpine/README.md index fcf7ee017..05d39dbbc 100644 --- a/cmd/helm/testdata/testcharts/alpine/README.md +++ b/cmd/helm/testdata/testcharts/alpine/README.md @@ -1,4 +1,4 @@ -#Alpine: A simple Helm chart +# Alpine: A simple Helm chart Run a single pod of Alpine Linux. diff --git a/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/Chart.yaml b/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/Chart.yaml new file mode 100644 index 000000000..a575aa9f8 --- /dev/null +++ b/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/Chart.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +description: Chart with bad subcharts +name: chart-with-bad-subcharts +version: 0.0.1 diff --git a/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/charts/bad-subchart/Chart.yaml b/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/charts/bad-subchart/Chart.yaml new file mode 100644 index 000000000..0daa5c188 --- /dev/null +++ b/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/charts/bad-subchart/Chart.yaml @@ -0,0 +1 @@ +description: Bad subchart \ No newline at end of file diff --git a/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/charts/bad-subchart/values.yaml b/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/charts/bad-subchart/values.yaml new file mode 100644 index 000000000..e69de29bb diff --git a/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/charts/good-subchart/Chart.yaml b/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/charts/good-subchart/Chart.yaml new file mode 100644 index 000000000..895433e31 --- /dev/null +++ b/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/charts/good-subchart/Chart.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +description: Good subchart +name: good-subchart +version: 0.0.1 \ No newline at end of file diff --git a/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/charts/good-subchart/values.yaml b/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/charts/good-subchart/values.yaml new file mode 100644 index 000000000..e69de29bb diff --git a/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/requirements.yaml b/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/requirements.yaml new file mode 100644 index 000000000..de2fbb4dd --- /dev/null +++ b/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/requirements.yaml @@ -0,0 +1,5 @@ +dependencies: + - name: good-subchart + version: 0.0.1 + - name: bad-subchart + version: 0.0.1 \ No newline at end of file diff --git a/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/values.yaml b/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/values.yaml new file mode 100644 index 000000000..e69de29bb diff --git a/cmd/helm/testdata/testcharts/chart-with-template-with-invalid-yaml/Chart.yaml b/cmd/helm/testdata/testcharts/chart-with-template-with-invalid-yaml/Chart.yaml new file mode 100644 index 000000000..29b477b06 --- /dev/null +++ b/cmd/helm/testdata/testcharts/chart-with-template-with-invalid-yaml/Chart.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +description: Deploy a basic Alpine Linux pod +home: https://helm.sh/helm +name: chart-with-template-with-invalid-yaml +sources: + - https://github.com/helm/helm +version: 0.1.0 +type: application diff --git a/cmd/helm/testdata/testcharts/chart-with-template-with-invalid-yaml/README.md b/cmd/helm/testdata/testcharts/chart-with-template-with-invalid-yaml/README.md new file mode 100644 index 000000000..fcf7ee017 --- /dev/null +++ b/cmd/helm/testdata/testcharts/chart-with-template-with-invalid-yaml/README.md @@ -0,0 +1,13 @@ +#Alpine: A simple Helm chart + +Run a single pod of Alpine Linux. + +This example was generated using the command `helm create alpine`. + +The `templates/` directory contains a very simple pod resource with a +couple of parameters. + +The `values.yaml` file contains the default values for the +`alpine-pod.yaml` template. + +You can install this example using `helm install ./alpine`. diff --git a/cmd/helm/testdata/testcharts/chart-with-template-with-invalid-yaml/templates/alpine-pod.yaml b/cmd/helm/testdata/testcharts/chart-with-template-with-invalid-yaml/templates/alpine-pod.yaml new file mode 100644 index 000000000..697cb50fe --- /dev/null +++ b/cmd/helm/testdata/testcharts/chart-with-template-with-invalid-yaml/templates/alpine-pod.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{.Release.Name}}-{{.Values.Name}}" +spec: + containers: + - name: waiter + image: "alpine:3.9" + command: ["/bin/sleep","9000"] +invalid diff --git a/cmd/helm/testdata/testcharts/chart-with-template-with-invalid-yaml/values.yaml b/cmd/helm/testdata/testcharts/chart-with-template-with-invalid-yaml/values.yaml new file mode 100644 index 000000000..807e12aea --- /dev/null +++ b/cmd/helm/testdata/testcharts/chart-with-template-with-invalid-yaml/values.yaml @@ -0,0 +1 @@ +Name: my-alpine diff --git a/cmd/helm/testdata/testcharts/issue-7233/.helmignore b/cmd/helm/testdata/testcharts/issue-7233/.helmignore new file mode 100644 index 000000000..50af03172 --- /dev/null +++ b/cmd/helm/testdata/testcharts/issue-7233/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/cmd/helm/testdata/testcharts/issue-7233/Chart.yaml b/cmd/helm/testdata/testcharts/issue-7233/Chart.yaml new file mode 100644 index 000000000..b31997acb --- /dev/null +++ b/cmd/helm/testdata/testcharts/issue-7233/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: issue-7233 +version: 0.1.0 diff --git a/cmd/helm/testdata/testcharts/issue-7233/requirements.lock b/cmd/helm/testdata/testcharts/issue-7233/requirements.lock new file mode 100644 index 000000000..62744125b --- /dev/null +++ b/cmd/helm/testdata/testcharts/issue-7233/requirements.lock @@ -0,0 +1,6 @@ +dependencies: +- name: alpine + repository: file://../alpine + version: 0.1.0 +digest: sha256:7b380b1a826e7be1eecb089f66209d6d3df54be4bf879d4a8e6f8a9e871710e5 +generated: "2020-01-31T11:30:21.911547651Z" diff --git a/cmd/helm/testdata/testcharts/issue-7233/requirements.yaml b/cmd/helm/testdata/testcharts/issue-7233/requirements.yaml new file mode 100644 index 000000000..f0195cb15 --- /dev/null +++ b/cmd/helm/testdata/testcharts/issue-7233/requirements.yaml @@ -0,0 +1,4 @@ +dependencies: +- name: alpine + version: 0.1.0 + repository: file://../alpine diff --git a/cmd/helm/testdata/testcharts/issue-7233/templates/configmap.yaml b/cmd/helm/testdata/testcharts/issue-7233/templates/configmap.yaml new file mode 100644 index 000000000..53880b25d --- /dev/null +++ b/cmd/helm/testdata/testcharts/issue-7233/templates/configmap.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Release.Name }}-configmap +data: + myvalue: "Hello World" + drink: {{ .Values.favoriteDrink }} diff --git a/cmd/helm/testdata/testcharts/issue-7233/values.yaml b/cmd/helm/testdata/testcharts/issue-7233/values.yaml new file mode 100644 index 000000000..b1aa168d7 --- /dev/null +++ b/cmd/helm/testdata/testcharts/issue-7233/values.yaml @@ -0,0 +1 @@ +favoriteDrink: coffee diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go index 6c967b796..dea866e4d 100644 --- a/cmd/helm/upgrade.go +++ b/cmd/helm/upgrade.go @@ -65,6 +65,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { client := action.NewUpgrade(cfg) valueOpts := &values.Options{} var outfmt output.Format + var createNamespace bool cmd := &cobra.Command{ Use: "upgrade [RELEASE] [CHART]", @@ -100,6 +101,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { fmt.Fprintf(out, "Release %q does not exist. Installing it now.\n", args[0]) } instClient := action.NewInstall(cfg) + instClient.CreateNamespace = createNamespace instClient.ChartPathOptions = client.ChartPathOptions instClient.DryRun = client.DryRun instClient.DisableHooks = client.DisableHooks @@ -108,6 +110,8 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { instClient.Devel = client.Devel instClient.Namespace = client.Namespace instClient.Atomic = client.Atomic + instClient.PostRenderer = client.PostRenderer + instClient.DisableOpenAPIValidation = client.DisableOpenAPIValidation rel, err := runInstall(args, instClient, valueOpts, out) if err != nil { @@ -157,6 +161,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { }) f := cmd.Flags() + f.BoolVar(&createNamespace, "create-namespace", false, "if --install is set, create the release namespace if not present") f.BoolVarP(&client.Install, "install", "i", false, "if a release by this name doesn't already exist, run an install") f.BoolVar(&client.Devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored") f.BoolVar(&client.DryRun, "dry-run", false, "simulate an upgrade") @@ -164,6 +169,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { f.MarkDeprecated("recreate-pods", "functionality will no longer be updated. Consult the documentation for other methods to recreate pods") f.BoolVar(&client.Force, "force", false, "force resource updates through a replacement strategy") f.BoolVar(&client.DisableHooks, "no-hooks", false, "disable pre/post upgrade hooks") + f.BoolVar(&client.DisableOpenAPIValidation, "disable-openapi-validation", false, "if set, the upgrade process will not validate rendered templates against the Kubernetes OpenAPI Schema") f.DurationVar(&client.Timeout, "timeout", 300*time.Second, "time to wait for any individual Kubernetes operation (like Jobs for hooks)") f.BoolVar(&client.ResetValues, "reset-values", false, "when upgrading, reset the values to the ones built into the chart") f.BoolVar(&client.ReuseValues, "reuse-values", false, "when upgrading, reuse the last release's values and merge in any overrides from the command line via --set and -f. If '--reset-values' is specified, this is ignored") @@ -176,6 +182,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { addChartPathOptionsFlags(f, &client.ChartPathOptions) addValueOptionsFlags(f, valueOpts) bindOutputFlag(cmd, &outfmt) + bindPostRenderFlag(cmd, &client.PostRenderer) return cmd } diff --git a/cmd/helm/verify.go b/cmd/helm/verify.go index d3ae517c9..f26fb377f 100644 --- a/cmd/helm/verify.go +++ b/cmd/helm/verify.go @@ -16,6 +16,7 @@ limitations under the License. package main import ( + "fmt" "io" "github.com/spf13/cobra" @@ -44,7 +45,14 @@ func newVerifyCmd(out io.Writer) *cobra.Command { Long: verifyDesc, Args: require.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - return client.Run(args[0]) + err := client.Run(args[0]) + if err != nil { + return err + } + + fmt.Fprint(out, client.Out) + + return nil }, } diff --git a/cmd/helm/verify_test.go b/cmd/helm/verify_test.go index a70051ff6..ccbcb3cf2 100644 --- a/cmd/helm/verify_test.go +++ b/cmd/helm/verify_test.go @@ -65,7 +65,7 @@ func TestVerifyCmd(t *testing.T) { { name: "verify validates a properly signed chart", cmd: "verify testdata/testcharts/signtest-0.1.0.tgz --keyring testdata/helm-test-key.pub", - expect: "", + expect: "Signed by: Helm Testing (This key should only be used for testing. DO NOT TRUST.) \nUsing Key With Fingerprint: 5E615389B53CA37F0EE60BD3843BBF981FC18762\nChart Hash Verified: sha256:e5ef611620fb97704d8751c16bab17fedb68883bfb0edc76f78a70e9173f9b55\n", wantError: false, }, } diff --git a/go.mod b/go.mod index c7b25ac13..7ba7a5542 100644 --- a/go.mod +++ b/go.mod @@ -4,79 +4,42 @@ go 1.13 require ( github.com/BurntSushi/toml v0.3.1 - github.com/MakeNowJust/heredoc v0.0.0-20171113091838-e9091a26100e // indirect github.com/Masterminds/semver/v3 v3.0.3 github.com/Masterminds/sprig/v3 v3.0.2 - github.com/Masterminds/vcs v1.13.0 - github.com/Microsoft/go-winio v0.4.12 // indirect - github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a - github.com/containerd/containerd v1.3.0 + github.com/Masterminds/vcs v1.13.1 + github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496 + github.com/containerd/containerd v1.3.2 github.com/cyphar/filepath-securejoin v0.2.2 - github.com/deislabs/oras v0.7.0 + github.com/deislabs/oras v0.8.1 github.com/docker/distribution v2.7.1+incompatible - github.com/docker/docker v1.4.2-0.20181221150755-2cb26cfe9cbf + github.com/docker/docker v1.4.2-0.20200203170920-46ec8731fbce github.com/docker/go-units v0.4.0 - github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c // indirect - github.com/emicklei/go-restful v2.11.1+incompatible // indirect github.com/evanphx/json-patch v4.5.0+incompatible - github.com/go-openapi/spec v0.19.4 // indirect github.com/gobwas/glob v0.2.3 github.com/gofrs/flock v0.7.1 - github.com/gogo/protobuf v1.3.1 // indirect - github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9 // indirect - github.com/google/go-cmp v0.3.1 // indirect - github.com/googleapis/gnostic v0.3.1 // indirect - github.com/gosuri/uitable v0.0.1 - github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f // indirect - github.com/hashicorp/golang-lru v0.5.3 // indirect - github.com/imdario/mergo v0.3.8 // indirect - github.com/mattn/go-runewidth v0.0.4 // indirect - github.com/mattn/go-shellwords v1.0.5 + github.com/gosuri/uitable v0.0.4 + github.com/mattn/go-shellwords v1.0.10 github.com/mitchellh/copystructure v1.0.0 github.com/opencontainers/go-digest v1.0.0-rc1 github.com/opencontainers/image-spec v1.0.1 - github.com/pkg/errors v0.8.1 - github.com/prometheus/client_golang v1.2.1 // indirect + github.com/pkg/errors v0.9.1 github.com/sirupsen/logrus v1.4.2 github.com/spf13/cobra v0.0.5 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.4.0 - github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect - github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.1.0 - github.com/xenolf/lego v0.3.2-0.20160613233155-a9d8cec0e656 // indirect - golang.org/x/crypto v0.0.0-20191028145041-f83a4685e152 - golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271 // indirect - golang.org/x/sys v0.0.0-20191028164358-195ce5e7f934 // indirect - golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect - google.golang.org/appengine v1.6.5 // indirect - google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6 // indirect - google.golang.org/grpc v1.24.0 // indirect - k8s.io/api v0.17.1 - k8s.io/apiextensions-apiserver v0.17.1 - k8s.io/apimachinery v0.17.1 - k8s.io/cli-runtime v0.17.1 - k8s.io/client-go v0.17.1 + golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d + k8s.io/api v0.17.3 + k8s.io/apiextensions-apiserver v0.17.3 + k8s.io/apimachinery v0.17.3 + k8s.io/cli-runtime v0.17.3 + k8s.io/client-go v0.17.3 k8s.io/klog v1.0.0 - k8s.io/kubectl v0.17.1 + k8s.io/kubectl v0.17.3 sigs.k8s.io/yaml v1.1.0 ) replace ( - // github.com/Azure/go-autorest/autorest has different versions for the Go - // modules than it does for releases on the repository. Note the correct - // version when updating. - github.com/Azure/go-autorest/autorest => github.com/Azure/go-autorest/autorest v0.9.0 - github.com/docker/docker => github.com/moby/moby v0.7.3-0.20190826074503-38ab9da00309 - - // Kubernetes imports github.com/miekg/dns at a newer version but it is used - // by a package Helm does not need. Go modules resolves all packages rather - // than just those in use (like Glide and dep do). This sets the version - // to the one oras needs. If oras is updated the version should be updated - // as well. - github.com/miekg/dns => github.com/miekg/dns v0.0.0-20181005163659-0d29b283ac0f - gopkg.in/inf.v0 v0.9.1 => github.com/go-inf/inf v0.9.1 - gopkg.in/square/go-jose.v2 v2.3.0 => github.com/square/go-jose v2.3.0+incompatible - - rsc.io/letsencrypt => github.com/dmcgowan/letsencrypt v0.0.0-20160928181947-1847a81d2087 + github.com/Azure/go-autorest => github.com/Azure/go-autorest v13.3.2+incompatible + github.com/docker/distribution => github.com/docker/distribution v0.0.0-20191216044856-a8371794149d ) diff --git a/go.sum b/go.sum index 312152e1f..39b57b4f2 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,13 @@ +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0 h1:ROfEUZz+Gh5pa62DJWXSaonyu3StP6EA6lPEXPI6mCo= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v13.3.2+incompatible h1:VxzPyuhtnlBOzc4IWCZHqpyH2d+QMLQEuy3wREyY4oc= +github.com/Azure/go-autorest v13.3.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.9.0 h1:MRvx8gncNaXJqOoLmhNjUAKh33JJF8LyxPhomEtOsjs= 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 h1:q2gDruN08/guU9vAjuPWff0+QIrpH6ediguzdAzXAUU= @@ -20,23 +24,20 @@ github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbt github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= 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/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd h1:sjQovDkwrZp8u+gxLtPgKGjk5hCxuy2hrRejBTA9xFU= github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= -github.com/MakeNowJust/heredoc v0.0.0-20171113091838-e9091a26100e h1:eb0Pzkt15Bm7f2FFYv7sjY7NPFi3cPkS3tv1CcrFBWA= -github.com/MakeNowJust/heredoc v0.0.0-20171113091838-e9091a26100e/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg= github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver/v3 v3.0.3 h1:znjIyLfpXEDQjOIEWh+ehwpTU14UzUPub3c3sm36u14= github.com/Masterminds/semver/v3 v3.0.3/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/sprig/v3 v3.0.2 h1:wz22D0CiSctrliXiI9ZO3HoNApweeRGftyDN+BQa3B8= github.com/Masterminds/sprig/v3 v3.0.2/go.mod h1:oesJ8kPONMONaZgtiHNzUShJbksypC5kWczhZAf6+aU= -github.com/Masterminds/vcs v1.13.0 h1:USF5TvZGYgIpcbNAEMLfFhHqP08tFZVlUVrmTSpqnyA= -github.com/Masterminds/vcs v1.13.0/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA= -github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= -github.com/Microsoft/go-winio v0.4.12 h1:xAfWHN1IrQ0NJ9TBC0KBZoqLjzDTr1ML+4MywiUOryc= -github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= -github.com/Microsoft/hcsshim v0.8.6 h1:ZfF0+zZeYdzMIVMZHKtDKJvLHj76XCuVae/jNkjj0IA= -github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= -github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46 h1:lsxEuwrXEAokXB9qhlbKWPpo3KMLZQ5WB5WLQRW1uq0= +github.com/Masterminds/vcs v1.13.1 h1:NL3G1X7/7xduQtA2sJLpVpfHTNBALVNSjob6KEjPXNQ= +github.com/Masterminds/vcs v1.13.1/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA= +github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6trr62pF5DucadTWGdEB4mEyvzi0e2nbcmcyA= +github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= +github.com/Microsoft/hcsshim v0.8.7 h1:ptnOoufxGSzauVTsdE+wMYnCWA301PdoN4xg5oRdZpg= +github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= @@ -49,56 +50,58 @@ github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/O github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/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 h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= +github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496 h1:zV3ejI06GQ59hwDQAvmK1qxOQGB3WuVTRoY0okPTAv0= +github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= +github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= +github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y= github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= -github.com/blang/semver v3.5.0+incompatible h1:CGxCgetQ64DKk7rdZ++Vfnb1+ogGNnB17OJKJXD2Cfs= +github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bshuster-repo/logrus-logstash-hook v0.4.1 h1:pgAtgj+A31JBVtEHu2uHuEx0n+2ukqUJnS2vVe5pQNA= github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= -github.com/bugsnag/bugsnag-go v1.5.0 h1:tP8hiPv1pGGW3LA6LKy5lW6WG+y9J2xWUdPd3WC452k= -github.com/bugsnag/bugsnag-go v1.5.0/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= -github.com/bugsnag/panicwrap v1.2.0 h1:OzrKrRvXis8qEvOkfcxNcYbOd2O7xXS2nnKMEMABFQA= -github.com/bugsnag/panicwrap v1.2.0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= -github.com/cespare/xxhash/v2 v2.1.0 h1:yTUvW7Vhb89inJ+8irsUqiWjh8iT6sQPZiQzI6ReGkA= -github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM= -github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 h1:7aWHqerlJ41y6FOsEUvknqgXnGmJyJSbjhAWq5pO4F8= +github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd h1:rFt+Y/IK1aEZkEHchZRSq9OQbsSzIT/OrI8YFFmRIng= +github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= +github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembjv71DPz3uX/V/6MMlSyD9JBQ6kQ= +github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= +github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o= +github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/containerd/containerd v1.3.0-beta.2.0.20190823190603-4a2f61c4f2b4 h1:aMyA5J7j6D07U7pf8BFEY67BKoDcz0zWleAbQj3zVng= -github.com/containerd/containerd v1.3.0-beta.2.0.20190823190603-4a2f61c4f2b4/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.3.0 h1:xjvXQWABwS2uiv3TWgQt5Uth60Gu86LTGZXMJkjc7rY= -github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/continuity v0.0.0-20181203112020-004b46473808 h1:4BX8f882bXEDKfWIf0wa8HRvpnBoPszJJXL+TVbBw4M= -github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f h1:tSNMc+rJDfmYntojat8lljbt1mgKNpTxUZJsSzJ9Y1s= +github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= +github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.2 h1:ForxmXkA6tPIvffbrDAcPUIB32QgXkt2XFj+F0UxetA= +github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20200107194136-26c1120b8d41 h1:kIFnQBO7rQ0XkMe6xEwbybYHBEaWmh/f++laI6Emt7M= +github.com/containerd/continuity v0.0.0-20200107194136-26c1120b8d41/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY= +github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 h1:u9SHYsPQNyt5tgDm3YN7+9dYrpK96E5wFilTFWIDZOM= 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 h1:n2Ltr3SrfQlf/9nOna1DoGKxLx3qTSI8Ttl6Xrqp6mw= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= @@ -110,33 +113,33 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= -github.com/deislabs/oras v0.7.0 h1:RnDoFd3tQYODMiUqxgQ8JxlrlWL0/VMKIKRD01MmNYk= -github.com/deislabs/oras v0.7.0/go.mod h1:sqMKPG3tMyIX9xwXUBRLhZ24o+uT4y6jgBD2RzUTKDM= +github.com/deislabs/oras v0.8.1 h1:If674KraJVpujYR00rzdi0QAmW4BxzMJPVAZJKuhQ0c= +github.com/deislabs/oras v0.8.1/go.mod h1:Mx0rMSbBNaNfY9hjpccEnxkOqJL6KGjtxNHPLC4G4As= +github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= +github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dmcgowan/letsencrypt v0.0.0-20160928181947-1847a81d2087 h1:8AJxBXuUPcBVAvoz6fi3fpSyozBxvF2DgQ0f/yn9nkE= -github.com/dmcgowan/letsencrypt v0.0.0-20160928181947-1847a81d2087/go.mod h1:pRqVcLnLZeet910LRIAzx73MR48LxCRA84OcsivAkSs= -github.com/docker/cli v0.0.0-20190506213505-d88565df0c2d h1:qdD+BtyCE1XXpDyhvn0yZVcZOLILdj9Cw4pKu0kQbPQ= -github.com/docker/cli v0.0.0-20190506213505-d88565df0c2d/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= -github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker-credential-helpers v0.6.1 h1:Dq4iIfcM7cNtddhLVWe9h4QDjsi4OER3Z8voPu/I52g= -github.com/docker/docker-credential-helpers v0.6.1/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v0.0.0-20200130152716-5d0cf8839492 h1:FwssHbCDJD025h+BchanCwE1Q8fyMgqDr2mOQAWOLGw= +github.com/docker/cli v0.0.0-20200130152716-5d0cf8839492/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v0.0.0-20191216044856-a8371794149d h1:jC8tT/S0OGx2cswpeUTn4gOIea8P08lD3VFQT0cOZ50= +github.com/docker/distribution v0.0.0-20191216044856-a8371794149d/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= +github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.4.2-0.20200203170920-46ec8731fbce h1:KXS1Jg+ddGcWA8e1N7cupxaHHZhit5rB9tfDU+mfjyY= +github.com/docker/docker v1.4.2-0.20200203170920-46ec8731fbce/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ= +github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-metrics v0.0.0-20181218153428-b84716841b82 h1:X0fj836zx99zFu83v/M79DuBn84IL/Syx1SY6Y5ZEMA= -github.com/docker/go-metrics v0.0.0-20181218153428-b84716841b82/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= -github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk= +github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916 h1:yWHOI+vFjEsAakUTSrtqc/SAHrhSkmn48pqjidZX3QA= +github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4= -github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= +github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 h1:ZClxb8laGDf5arXfYcAtECDFgAgHklGI8CxgjHnXKJ4= +github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96 h1:cenwrSVm+Z7QLSV/BsnenAOcDXdX4cMv4wP0B/5QbPg= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= -github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c h1:ZfSZ3P3BedhKGUhzj7BQlPSU4OvT6tfOKe3DVHzOA7s= -github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/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 h1:p1yVGRW3nmb85p1Sh1ZJSDm4A4iKLS5QNbvUHMgGu/M= @@ -144,116 +147,95 @@ github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkg github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful v2.11.1+incompatible h1:CjKsv3uWcCMvySPQYKxO8XX3f9zD4FeZRsW4G0B4ffE= -github.com/emicklei/go-restful v2.11.1+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/evanphx/json-patch v4.2.0+incompatible h1:fUDGZCv/7iAN7u0puUVhvKCcsR6vRfwrJatElLBEf0I= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M= github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= +github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/garyburd/redigo v1.6.0 h1:0VruCpn7yAIIu7pWVClQC8wxCJEcG3nyzpMSHKi1PQc= -github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7 h1:LofdAjjjqCSXMwLGgOgnE+rdPuvX9DxCqaHwKy7i/ko= +github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 h1:DujepqpGd1hyOd7aW59XpK7Qymp8iy83xq74fLr21is= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/go-inf/inf v0.9.1 h1:F4sloU4SED74gTeM3mWLrf8yyMAgVCV0puw3vhtKWrk= -github.com/go-inf/inf v0.9.1/go.mod h1:ZWwB6rTV+0pO94RdIMKue59tExzQp6/pj/BMuPQkXaA= +github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-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 h1:ophLETFestFZHk3ji7niPEL4d466QjW+0Tdg5VyDq7E= 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 h1:a2kIyV3w+OS3S97zxUndRVD46+FhGOUBDFY7nmu4CsY= github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonpointer v0.19.2 h1:A9+F4Dc/MCNB5jibxf6rRvOvR/iFgQdyNx9eIhnGqq0= 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 h1:rf5ArTHmIJxyV5Oiks+Su0mUens1+AjpkPoWr5xFRcI= 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 h1:sU6pp4dSV2sGlNKKyHxZzi1m1kG4WnYtWcJ+HYbygjE= 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 h1:SStNd1jRcYtfKCN7R0laGNs80WYYvn5CbBjM2sOmCrE= github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= +github.com/go-openapi/spec v0.19.3 h1:0XRyw8kguri6Yw4SxhsQA/atC88yqrk0+G4YhI2wabc= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= -github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo= -github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= -github.com/go-openapi/strfmt v0.19.0 h1:0Dn9qy1G9+UJfRU7TR8bmdGxb4uifB7HNrJjOnV0yPk= 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 h1:jvO6bCMBEilGwMfHhrd61zIID4oIFdwb76V17SM88dE= 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 h1:ky5l57HjyVRrsJfd2+Ro5Z9PjGuKbsmftwyMtk8H7js= 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 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/gofrs/flock v0.7.1 h1:DP+LD/t0njgoPBvT5MJLeliUIVQR03hiKR6vezdwHlc= github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= -github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE= -github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/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 h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903 h1:LbsanbbD6LieFkXbj9YNNBupiGHJgFeLpO0j0Fza1h8= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9 h1:uHTyIjqVhYRhLbJ8nIiOJHkEZZ+5YoOsAbD3sk82NiE= -github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= 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= @@ -264,10 +246,9 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -277,32 +258,29 @@ github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ 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 h1:7XGaL1e6bYS1yIonGp9761ExpPPV1ui0SAC59Yube9k= 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 h1:P/nh25+rzXouhytV2pUHBb65fnds26Ghl8/391+sT5o= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= -github.com/gorilla/handlers v1.4.0 h1:XulKRWSQK5uChr4pEgSE4Tc/OcmnU9GJuSwdog/tZsA= -github.com/gorilla/handlers v1.4.0/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= -github.com/gorilla/mux v1.7.0 h1:tOSd0UKHQd6urX6ApfOn4XdBMY6Sh1MfxV3kmaazO+U= -github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33 h1:893HsJqtxp9z1SF76gg6hY70hRY1wVlTSnC/h1yUDCo= +github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/mux v1.7.2 h1:zoNxOV7WjqXptQOVngLmcSQgXmgk4NMz1HibBchjl/I= +github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gosuri/uitable v0.0.1 h1:M9sMNgSZPyAu1FJZJLpJ16ofL8q5ko2EDUkICsynvlY= -github.com/gosuri/uitable v0.0.1/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= +github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY= +github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f h1:ShTPMJQes6tubcjzGMODIVG5hlrCeImaBnZzKF2N8SM= -github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= 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 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= 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/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= -github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= 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= @@ -311,22 +289,19 @@ github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63 github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI= github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ= -github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= +github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/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 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 h1:PJPDf8OUfOK1bb/NeTKd4f1QXZItOX389VN3B6qC8ro= -github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= 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= @@ -346,33 +321,33 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP 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 h1:nTT4s92Dgz2HlrB2NaMgvlfqHH39OgMhA7z3PK7PGD4= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= +github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-runewidth v0.0.2 h1:UnlwIPBGaTZfPQ6T1IGzPI0EkYAQmT9fAEJ/poFC63o= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= -github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-shellwords v1.0.5 h1:JhhFTIOslh5ZsPrpa3Wdg8bF0WI3b44EMblmU9wIsXc= -github.com/mattn/go-shellwords v1.0.5/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= +github.com/mattn/go-shellwords v1.0.9 h1:eaB5JspOwiKKcHdqcjbfe5lA9cNn/4NRRtddXJCimqk= +github.com/mattn/go-shellwords v1.0.9/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= +github.com/mattn/go-shellwords v1.0.10 h1:Y7Xqm8piKOO3v10Thp7Z36h4FYFjt5xB//6XvOrs2Gw= +github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= 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/miekg/dns v0.0.0-20181005163659-0d29b283ac0f h1:wVzAD6PG9MIDNQMZ6zc2YpzE/9hhJ3EN+b+a4B1thVs= -github.com/miekg/dns v0.0.0-20181005163659-0d29b283ac0f/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= -github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f h1:2+myh5ml7lgEU/51gbeLHfKGNfgEQQIWrlbdaOsidbQ= +github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/moby/moby v0.7.3-0.20190826074503-38ab9da00309 h1:cvy4lBOYN3gKfKj8Lzz5Q9TfviP+L7koMHY7SvkyTKs= -github.com/moby/moby v0.7.3-0.20190826074503-38ab9da00309/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc= 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= @@ -380,13 +355,13 @@ github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lN github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c h1:nXxl5PrvVm2L/wCy8dQu6DMTwH4oIuGN8GJDAlqDdVE= -github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -395,50 +370,47 @@ github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+ github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= +github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/phayes/freeport v0.0.0-20171002181615-b8543db493a5 h1:rZQtoozkfsiNs36c7Tdv/gyGNzD1X1XWKO8rptVNZuM= -github.com/phayes/freeport v0.0.0-20171002181615-b8543db493a5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= +github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc= +github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib 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.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.2 h1:awm861/B8OKDd2I/6o1dy3ra4BamzKhYOiGItCeZ740= -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_golang v1.2.1 h1:JnMpQc6ppsNgw9QPAGF6Dod479itz7lvlsMzzNayLOI= -github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U= +github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.2.0 h1:kUZDBDTdBVBYBj5Tmh2NZLlF60mfjA27rM34b+cVwNU= -github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.0.0-20180110214958-89604d197083/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/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY= -github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190129233650-316cf8ccfec5 h1:Etei0Wx6pooT/DeOKcGTr1M/01ggz95Ajq8BBwCOKBU= -github.com/prometheus/procfs v0.0.0-20190129233650-316cf8ccfec5/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/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8= github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= @@ -446,23 +418,28 @@ github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uY github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s= 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-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= 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= @@ -472,32 +449,30 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ 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 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= 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/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8 h1:ndzgwNDnKIqyCvHTXaCqh9KlOWKvBry6nuXMJmonVsE= 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 v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= github.com/xeipuuv/gojsonschema v1.1.0 h1:ngVtJC9TY/lg0AA/1k48FYhBrhRoFlEmWzsehpNAaZg= github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= -github.com/xenolf/lego v0.0.0-20160613233155-a9d8cec0e656/go.mod h1:fwiGnfsIjG7OHPfOvgK7Y/Qo6+2Ox0iozjNTkZICKbY= -github.com/xenolf/lego v0.3.2-0.20160613233155-a9d8cec0e656 h1:BTvU+npm3/yjuBd53EvgiFLl5+YLikf2WvHsjRQ4KrY= -github.com/xenolf/lego v0.3.2-0.20160613233155-a9d8cec0e656/go.mod h1:fwiGnfsIjG7OHPfOvgK7Y/Qo6+2Ox0iozjNTkZICKbY= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yvasiyarov/go-metrics v0.0.0-20150112132944-c25f46c4b940 h1:p7OofyZ509h8DmPLh8Hn+EIIZm/xYhdZHJ9GnXHdr6U= -github.com/yvasiyarov/go-metrics v0.0.0-20150112132944-c25f46c4b940/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= -github.com/yvasiyarov/gorelic v0.0.6 h1:qMJQYPNdtJ7UNYHjX38KXZtltKTqimMuoQjNnSVIuJg= -github.com/yvasiyarov/gorelic v0.0.6/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= +github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI= +github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= +github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMztlGpl/VA+Zm1AcTPHYkHJPbHqE6WJUXE= +github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1:ERexzlUfuTvpE74urLSbIQW0Z/6hF9t8U4NsJLaioAY= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= @@ -506,27 +481,27 @@ go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qL go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 h1:1wopBVtVdWnn03fZelqdXTqk7U7zPQCb+T4rbU9ZEoU= 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/crypto v0.0.0-20191028145041-f83a4685e152 h1:ZC1Xn5A1nlpSmQCIva4bZ3ob3lmhYIefc+GU+DLg1Ow= -golang.org/x/crypto v0.0.0-20191028145041-f83a4685e152/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d h1:9FCpayM9Egr1baVnV1SX0H87m+XB0B8S0hAMi99X/3U= +golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-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-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 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= @@ -537,23 +512,21 @@ golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73r 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-20181106065722-10aee1819953/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-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/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-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271 h1:N66aaryRB3Ax92gH0v3hp1QYZ3zWWCCUR/j8Ifh45Ss= -golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271/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= @@ -561,10 +534,10 @@ golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4Iltr 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 h1:bjcUS9ztw9kFmmIxJInhon/0Is3p+EHBKNgquIzo1OI= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -578,25 +551,23 @@ golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7w 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 h1:25KHgbfyiSm6vwQLbM3zZIe1v9p/3ea4Rz+nnM5K/i4= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191028164358-195ce5e7f934 h1:u/E0NqCIWRDAo9WCFo6Ko49njPFDLSd3z+X1HgWDMpE= -golang.org/x/sys v0.0.0-20191028164358-195ce5e7f934/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3 h1:7TYNF4UdlohbFwpNH04CoPMp1cHUZgO1Ebq5r2hIjfo= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c h1:fqgJT0MGcGpPgpWU7VRdRjuArfcOvC4AoJmILihzhDg= 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/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/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-20180828015842-6cd1fcedba52/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= @@ -607,82 +578,82 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485 h1:OB/uP/Puiu5vS5QMRPrXCDWUPb+kt8f1KW8oQzFejQw= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190128161407-8ac453e89fca/go.mod h1:L3J43x8/uS+qIUoksaLKe6OS3nUKxOKuIFz1sl2/jx4= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7 h1:ZUjXAXmrAyrmmCPHgCA/vChHcpsX27MZ3yBonD/z1KE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873 h1:nfPFGzJkUDX6uBmpN/pSw7MbOAWegH5QDQuoXFHedLg= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6 h1:UXl+Zk3jqqcbEVV7ace5lrt4YdA4tXiz3f/KbmD29Vo= -google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1 h1:Hz2g2wirWK7H0qIIhGIqRGTuMwTE8HEKFnDZZ7lm9NU= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.24.0 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s= -google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= +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.v1 v1.1.2 h1:/5jmADZB+RiKtZGr4HxsEFOEfbfsjTKsVnqpThUpE30= -gopkg.in/square/go-jose.v1 v1.1.2/go.mod h1:QpYS+a4WhS+DTlyQIi6Ka7MS3SuR9a055rgXNEe6EiA= -gopkg.in/square/go-jose.v2 v2.2.2 h1:orlkJ3myw8CN1nVQHBFfloD+L3egixIa4FvUP6RosSA= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= 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.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= -honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 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.17.1 h1:i46MidoDOE9tvQ0TTEYggf3ka/pziP1+tHI/GFVeJao= -k8s.io/api v0.17.1/go.mod h1:zxiAc5y8Ngn4fmhWUtSxuUlkfz1ixT7j9wESokELzOg= -k8s.io/apiextensions-apiserver v0.17.1 h1:Gw6zQgmKyyNrFMtVpRBNEKE8p35sDBI7Tq1ImxGS+zU= -k8s.io/apiextensions-apiserver v0.17.1/go.mod h1:DRIFH5x3jalE4rE7JP0MQKby9zdYk9lUJQuMmp+M/L0= -k8s.io/apimachinery v0.17.1 h1:zUjS3szTxoUjTDYNvdFkYt2uMEXLcthcbp+7uZvWhYM= -k8s.io/apimachinery v0.17.1/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= -k8s.io/apiserver v0.17.1/go.mod h1:BQEUObJv8H6ZYO7DeKI5vb50tjk6paRJ4ZhSyJsiSco= -k8s.io/cli-runtime v0.17.1 h1:VoZRWJNRyrxuM5SIRozYhT/EtcZ6jiS+KBCxRw66p1g= -k8s.io/cli-runtime v0.17.1/go.mod h1:e5847Iy85W9uWH3rZofXTG/9nOUyGKGTVnObYF7zSik= -k8s.io/client-go v0.17.1 h1:LbbuZ5tI7OYx4et5DfRFcJuoojvpYO0c7vps2rgJsHY= -k8s.io/client-go v0.17.1/go.mod h1:HZtHJSC/VuSHcETN9QA5QDZky1tXiYrkF/7t7vRpO1A= -k8s.io/code-generator v0.17.1/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= -k8s.io/component-base v0.17.1 h1:lK/lUzZZQK+DlH0XD+gq610OUEmjWOyDuUYOTGetw10= -k8s.io/component-base v0.17.1/go.mod h1:LrBPZkXtlvGjBzDJa0+b7E5Ij4VoAAKrOGudRC5z2eY= +k8s.io/api v0.17.3 h1:XAm3PZp3wnEdzekNkcmj/9Y1zdmQYJ1I4GKSBBZ8aG0= +k8s.io/api v0.17.3/go.mod h1:YZ0OTkuw7ipbe305fMpIdf3GLXZKRigjtZaV5gzC2J0= +k8s.io/apiextensions-apiserver v0.17.3 h1:WDZWkPcbgvchEdDd7ysL21GGPx3UKZQLDZXEkevT6n4= +k8s.io/apiextensions-apiserver v0.17.3/go.mod h1:CJbCyMfkKftAd/X/V6OTHYhVn7zXnDdnkUjS1h0GTeY= +k8s.io/apimachinery v0.17.3 h1:f+uZV6rm4/tHE7xXgLyToprg6xWairaClGVkm2t8omg= +k8s.io/apimachinery v0.17.3/go.mod h1:gxLnyZcGNdZTCLnq3fgzyg2A5BVCHTNDFrw8AmuJ+0g= +k8s.io/apiserver v0.17.3/go.mod h1:iJtsPpu1ZpEnHaNawpSV0nYTGBhhX2dUlnn7/QS7QiY= +k8s.io/cli-runtime v0.17.3 h1:0ZlDdJgJBKsu77trRUynNiWsRuAvAVPBNaQfnt/1qtc= +k8s.io/cli-runtime v0.17.3/go.mod h1:X7idckYphH4SZflgNpOOViSxetiMj6xI0viMAjM81TA= +k8s.io/client-go v0.17.3 h1:deUna1Ksx05XeESH6XGCyONNFfiQmDdqeqUvicvP6nU= +k8s.io/client-go v0.17.3/go.mod h1:cLXlTMtWHkuK4tD360KpWz2gG2KtdWEr/OT02i3emRQ= +k8s.io/code-generator v0.17.3/go.mod h1:l8BLVwASXQZTo2xamW5mQNFCe1XPiAesVq7Y1t7PiQQ= +k8s.io/component-base v0.17.3 h1:hQzTSshY14aLSR6WGIYvmw+w+u6V4d+iDR2iDGMrlUg= +k8s.io/component-base v0.17.3/go.mod h1:GeQf4BrgelWm64PXkIXiPh/XS0hnO42d9gx9BtbZRp8= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20190822140433-26a664648505 h1:ZY6yclUKVbZ+SdWnkfY+Je5vrMpKOxmGeKRbsXVmqYM= 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= @@ -690,9 +661,10 @@ k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= -k8s.io/kubectl v0.17.1 h1:+gI5hPZVEXN5wWybrzX3tu3f9af54sUNcALhg86upCY= -k8s.io/kubectl v0.17.1/go.mod h1:ZmbAdEQm+SLA/3s3eWJ3g+liXb5eT6mA85jYj52LMXw= -k8s.io/metrics v0.17.1/go.mod h1:dphDhzjA1KR/nQXtXEQzoQyQXk5ViSJO85Ky8QKwBPM= +k8s.io/kubectl v0.17.3 h1:9HHYj07kuFkM+sMJMOyQX29CKWq4lvKAG1UIPxNPMQ4= +k8s.io/kubectl v0.17.3/go.mod h1:NUn4IBY7f7yCMwSop2HCXlw/MVYP4HJBiUmOR3n9w28= +k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= +k8s.io/metrics v0.17.3/go.mod h1:HEJGy1fhHOjHggW9rMDBJBD3YuGroH3Y1pnIRw9FFaI= 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= diff --git a/internal/completion/complete.go b/internal/completion/complete.go index a24390fc0..eaea4e914 100644 --- a/internal/completion/complete.go +++ b/internal/completion/complete.go @@ -35,9 +35,9 @@ import ( // This should ultimately be pushed down into Cobra. // ================================================================================== -// compRequestCmd Hidden command to request completion results from the program. +// CompRequestCmd Hidden command to request completion results from the program. // Used by the shell completion script. -const compRequestCmd = "__complete" +const CompRequestCmd = "__complete" // Global map allowing to find completion functions for commands or flags. var validArgsFunctions = map[interface{}]func(cmd *cobra.Command, args []string, toComplete string) ([]string, BashCompDirective){} @@ -123,7 +123,7 @@ __helm_custom_func() done < <(compgen -W "${out[*]}" -- "$cur") fi } -`, compRequestCmd, BashCompDirectiveError, BashCompDirectiveNoSpace, BashCompDirectiveNoFileComp) +`, CompRequestCmd, BashCompDirectiveError, BashCompDirectiveNoSpace, BashCompDirectiveNoFileComp) } // RegisterValidArgsFunc should be called to register a function to provide argument completion for a command @@ -177,40 +177,58 @@ func (d BashCompDirective) string() string { func NewCompleteCmd(settings *cli.EnvSettings, out io.Writer) *cobra.Command { debug = settings.Debug return &cobra.Command{ - Use: fmt.Sprintf("%s [command-line]", compRequestCmd), + Use: fmt.Sprintf("%s [command-line]", CompRequestCmd), DisableFlagsInUseLine: true, Hidden: true, DisableFlagParsing: true, Args: require.MinimumNArgs(1), Short: "Request shell completion choices for the specified command-line", Long: fmt.Sprintf("%s is a special command that is used by the shell completion logic\n%s", - compRequestCmd, "to request completion choices for the specified command-line."), + CompRequestCmd, "to request completion choices for the specified command-line."), Run: func(cmd *cobra.Command, args []string) { CompDebugln(fmt.Sprintf("%s was called with args %v", cmd.Name(), args)) - flag, trimmedArgs, toComplete, err := checkIfFlagCompletion(cmd.Root(), args[:len(args)-1], args[len(args)-1]) - if err != nil { - // Error while attempting to parse flags - CompErrorln(err.Error()) - return - } + // The last argument, which is not complete, should not be part of the list of arguments + toComplete := args[len(args)-1] + trimmedArgs := args[:len(args)-1] + // Find the real command for which completion must be performed finalCmd, finalArgs, err := cmd.Root().Find(trimmedArgs) if err != nil { // Unable to find the real command. E.g., helm invalidCmd + CompDebugln(fmt.Sprintf("Unable to find a command for arguments: %v", trimmedArgs)) return } CompDebugln(fmt.Sprintf("Found final command '%s', with finalArgs %v", finalCmd.Name(), finalArgs)) + var flag *pflag.Flag + if !finalCmd.DisableFlagParsing { + // We only do flag completion if we are allowed to parse flags + // This is important for helm plugins which need to do their own flag completion. + flag, finalArgs, toComplete, err = checkIfFlagCompletion(finalCmd, finalArgs, toComplete) + if err != nil { + // Error while attempting to parse flags + CompErrorln(err.Error()) + return + } + } + // Parse the flags and extract the arguments to prepare for calling the completion function if err = finalCmd.ParseFlags(finalArgs); err != nil { CompErrorln(fmt.Sprintf("Error while parsing flags from args %v: %s", finalArgs, err.Error())) return } - argsWoFlags := finalCmd.Flags().Args() - CompDebugln(fmt.Sprintf("Args without flags are '%v' with length %d", argsWoFlags, len(argsWoFlags))) + // We only remove the flags from the arguments if DisableFlagParsing is not set. + // This is important for helm plugins, which need to receive all flags. + // The plugin completion code will do its own flag parsing. + if !finalCmd.DisableFlagParsing { + finalArgs = finalCmd.Flags().Args() + CompDebugln(fmt.Sprintf("Args without flags are '%v' with length %d", finalArgs, len(finalArgs))) + } + + // Find completion function for the flag or command var key interface{} var keyStr string if flag != nil { @@ -220,26 +238,28 @@ func NewCompleteCmd(settings *cli.EnvSettings, out io.Writer) *cobra.Command { key = finalCmd keyStr = finalCmd.Name() } - - // Find completion function for the flag or command completionFn, ok := validArgsFunctions[key] if !ok { CompErrorln(fmt.Sprintf("Dynamic completion not supported/needed for flag or command: %s", keyStr)) return } - CompDebugln(fmt.Sprintf("Calling completion method for subcommand '%s' with args '%v' and toComplete '%s'", finalCmd.Name(), argsWoFlags, toComplete)) - completions, directive := completionFn(finalCmd, argsWoFlags, toComplete) + CompDebugln(fmt.Sprintf("Calling completion method for subcommand '%s' with args '%v' and toComplete '%s'", finalCmd.Name(), finalArgs, toComplete)) + completions, directive := completionFn(finalCmd, finalArgs, toComplete) for _, comp := range completions { // Print each possible completion to stdout for the completion script to consume. fmt.Fprintln(out, comp) } + if directive > BashCompDirectiveError+BashCompDirectiveNoSpace+BashCompDirectiveNoFileComp { + directive = BashCompDirectiveDefault + } + // As the last printout, print the completion directive for the // completion script to parse. // The directive integer must be that last character following a single : // The completion script expects :directive - fmt.Fprintln(out, fmt.Sprintf(":%d", directive)) + fmt.Fprintf(out, ":%d\n", directive) // Print some helpful info to stderr for the user to understand. // Output from stderr should be ignored from the completion script. @@ -252,7 +272,7 @@ func isFlag(arg string) bool { return len(arg) > 0 && arg[0] == '-' } -func checkIfFlagCompletion(rootCmd *cobra.Command, args []string, lastArg string) (*pflag.Flag, []string, string, error) { +func checkIfFlagCompletion(finalCmd *cobra.Command, args []string, lastArg string) (*pflag.Flag, []string, string, error) { var flagName string trimmedArgs := args flagWithEqual := false @@ -287,19 +307,10 @@ func checkIfFlagCompletion(rootCmd *cobra.Command, args []string, lastArg string return nil, trimmedArgs, lastArg, nil } - // Find the real command for which completion must be performed - finalCmd, _, err := rootCmd.Find(trimmedArgs) - if err != nil { - // Unable to find the real command. E.g., helm invalidCmd - return nil, nil, "", errors.New("Unable to find final command for completion") - } - - CompDebugln(fmt.Sprintf("checkIfFlagCompletion: found final command '%s'", finalCmd.Name())) - flag := findFlag(finalCmd, flagName) if flag == nil { // Flag not supported by this command, nothing to complete - err = fmt.Errorf("Subcommand '%s' does not support flag '%s'", finalCmd.Name(), flagName) + err := fmt.Errorf("Subcommand '%s' does not support flag '%s'", finalCmd.Name(), flagName) return nil, nil, "", err } diff --git a/internal/experimental/registry/client.go b/internal/experimental/registry/client.go index d52d9f3e0..f664c9f38 100644 --- a/internal/experimental/registry/client.go +++ b/internal/experimental/registry/client.go @@ -21,6 +21,7 @@ import ( "fmt" "io" "io/ioutil" + "net/http" "sort" auth "github.com/deislabs/oras/pkg/auth/docker" @@ -69,7 +70,7 @@ func NewClient(opts ...ClientOption) (*Client, error) { } } if client.resolver == nil { - resolver, err := client.authorizer.Resolver(context.Background()) + resolver, err := client.authorizer.Resolver(context.Background(), http.DefaultClient, false) if err != nil { return nil, err } diff --git a/internal/experimental/registry/client_test.go b/internal/experimental/registry/client_test.go index 0861c8984..33799f5fa 100644 --- a/internal/experimental/registry/client_test.go +++ b/internal/experimental/registry/client_test.go @@ -23,6 +23,7 @@ import ( "io" "io/ioutil" "net" + "net/http" "os" "path/filepath" "testing" @@ -66,7 +67,7 @@ func (suite *RegistryClientTestSuite) SetupSuite() { client, err := auth.NewClient(credentialsFile) suite.Nil(err, "no error creating auth client") - resolver, err := client.Resolver(context.Background()) + resolver, err := client.Resolver(context.Background(), http.DefaultClient, false) suite.Nil(err, "no error creating resolver") // create cache diff --git a/internal/resolver/resolver.go b/internal/resolver/resolver.go index e4dbab227..cec29c947 100644 --- a/internal/resolver/resolver.go +++ b/internal/resolver/resolver.go @@ -157,6 +157,22 @@ func HashReq(req, lock []*chart.Dependency) (string, error) { return "sha256:" + s, err } +// HashV2Req generates a hash of requirements generated in Helm v2. +// +// This should be used only to compare against another hash generated by the +// Helm v2 hash function. It is to handle issue: +// https://github.com/helm/helm/issues/7233 +func HashV2Req(req []*chart.Dependency) (string, error) { + dep := make(map[string][]*chart.Dependency) + dep["dependencies"] = req + data, err := json.Marshal(dep) + if err != nil { + return "", err + } + s, err := provenance.Digest(bytes.NewBuffer(data)) + return "sha256:" + s, err +} + // GetLocalPath generates absolute local path when use // "file://" in repository of dependencies func GetLocalPath(repo, chartpath string) (string, error) { diff --git a/internal/resolver/resolver_test.go b/internal/resolver/resolver_test.go index d93d616ee..bb3d3e6ac 100644 --- a/internal/resolver/resolver_test.go +++ b/internal/resolver/resolver_test.go @@ -227,8 +227,8 @@ func TestGetLocalPath(t *testing.T) { }{ { name: "absolute path", - repo: "file:////proc", - expect: "/proc", + repo: "file:////tmp", + expect: "/tmp", }, { name: "relative path", diff --git a/internal/version/version.go b/internal/version/version.go index 22439d11b..fd0616920 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -23,14 +23,14 @@ import ( ) var ( - // version is the current version of the Helm. + // version is the current version of Helm. // Update this whenever making a new release. // The version is of the format Major.Minor.Patch[-Prerelease][+BuildMetadata] // // Increment major number for new feature additions and behavioral changes. // Increment minor number for bug fixes and performance enhancements. // Increment patch number for critical fixes to existing releases. - version = "v3.0" + version = "v3.1" // metadata is extra build time data metadata = "" diff --git a/pkg/action/action.go b/pkg/action/action.go index 9405cc401..e4db942c8 100644 --- a/pkg/action/action.go +++ b/pkg/action/action.go @@ -135,6 +135,7 @@ func (c *Configuration) getCapabilities() (*chartutil.Capabilities, error) { return c.Capabilities, nil } +// KubernetesClientSet creates a new kubernetes ClientSet based on the configuration func (c *Configuration) KubernetesClientSet() (kubernetes.Interface, error) { conf, err := c.RESTClientGetter.ToRESTConfig() if err != nil { @@ -219,7 +220,7 @@ func (c *Configuration) recordRelease(r *release.Release) { } } -// InitActionConfig initializes the action configuration +// Init initializes the action configuration func (c *Configuration) Init(getter genericclioptions.RESTClientGetter, namespace string, helmDriver string, log DebugLog) error { kc := kube.New(getter) kc.Log = log @@ -240,7 +241,19 @@ func (c *Configuration) Init(getter genericclioptions.RESTClientGetter, namespac d.Log = log store = storage.Init(d) case "memory": - d := driver.NewMemory() + var d *driver.Memory + if c.Releases != nil { + if mem, ok := c.Releases.Driver.(*driver.Memory); ok { + // This function can be called more than once (e.g., helm list --all-namespaces). + // If a memory driver was already initialized, re-use it but set the possibly new namespace. + // We re-use it in case some releases where already created in the existing memory driver. + d = mem + } + } + if d == nil { + d = driver.NewMemory() + } + d.SetNamespace(namespace) store = storage.Init(d) default: // Not sure what to do here. diff --git a/pkg/action/action_test.go b/pkg/action/action_test.go index a5baec97d..36ef261a3 100644 --- a/pkg/action/action_test.go +++ b/pkg/action/action_test.go @@ -19,6 +19,7 @@ import ( "context" "flag" "io/ioutil" + "net/http" "path/filepath" "testing" @@ -45,7 +46,7 @@ func actionConfigFixture(t *testing.T) *Configuration { t.Fatal(err) } - resolver, err := client.Resolver(context.Background()) + resolver, err := client.Resolver(context.Background(), http.DefaultClient, false) if err != nil { t.Fatal(err) } @@ -229,6 +230,20 @@ func withSampleTemplates() chartOption { } } +func withSampleIncludingIncorrectTemplates() chartOption { + return func(opts *chartOptions) { + sampleTemplates := []*chart.File{ + // This adds basic templates and partials. + {Name: "templates/goodbye", Data: []byte("goodbye: world")}, + {Name: "templates/empty", Data: []byte("")}, + {Name: "templates/incorrect", Data: []byte("{{ .Values.bad.doh }}")}, + {Name: "templates/with-partials", Data: []byte(`hello: {{ template "_planet" . }}`)}, + {Name: "templates/partials/_planet", Data: []byte(`{{define "_planet"}}Earth{{end}}`)}, + } + opts.Templates = append(opts.Templates, sampleTemplates...) + } +} + func withMultipleManifestTemplate() chartOption { return func(opts *chartOptions) { sampleTemplates := []*chart.File{ diff --git a/pkg/action/install.go b/pkg/action/install.go index 292a7ec27..e7b481d47 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -29,8 +29,11 @@ import ( "github.com/Masterminds/sprig/v3" "github.com/pkg/errors" + v1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/cli-runtime/pkg/resource" + "sigs.k8s.io/yaml" "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chartutil" @@ -39,6 +42,7 @@ import ( "helm.sh/helm/v3/pkg/engine" "helm.sh/helm/v3/pkg/getter" kubefake "helm.sh/helm/v3/pkg/kube/fake" + "helm.sh/helm/v3/pkg/postrender" "helm.sh/helm/v3/pkg/release" "helm.sh/helm/v3/pkg/releaseutil" "helm.sh/helm/v3/pkg/repo" @@ -67,28 +71,35 @@ type Install struct { ChartPathOptions - ClientOnly bool - DryRun bool - DisableHooks bool - Replace bool - Wait bool - Devel bool - DependencyUpdate bool - Timeout time.Duration - Namespace string - ReleaseName string - GenerateName bool - NameTemplate string - Description string - OutputDir string - Atomic bool - SkipCRDs bool - SubNotes bool + ClientOnly bool + CreateNamespace bool + DryRun bool + DisableHooks bool + Replace bool + Wait bool + Devel bool + DependencyUpdate bool + Timeout time.Duration + Namespace string + ReleaseName string + GenerateName bool + NameTemplate string + Description string + OutputDir string + Atomic bool + SkipCRDs bool + SubNotes bool + DisableOpenAPIValidation bool + IncludeCRDs bool // APIVersions allows a manual set of supported API Versions to be passed // (for things like templating). These are ignored if ClientOnly is false APIVersions chartutil.VersionSet // Used by helm template to render charts with .Release.IsUpgrade. Ignored if Dry-Run is false IsUpgrade bool + // Used by helm template to add the release as part of OutputDir path + // OutputDir/ + UseReleaseName bool + PostRenderer postrender.PostRenderer } // ChartPathOptions captures common options used for controlling chart paths @@ -111,12 +122,12 @@ func NewInstall(cfg *Configuration) *Install { } } -func (i *Install) installCRDs(crds []*chart.File) error { +func (i *Install) installCRDs(crds []chart.CRD) error { // We do these one file at a time in the order they were read. totalItems := []*resource.Info{} for _, obj := range crds { // Read in the resources - res, err := i.cfg.KubeClient.Build(bytes.NewBuffer(obj.Data), false) + res, err := i.cfg.KubeClient.Build(bytes.NewBuffer(obj.File.Data), false) if err != nil { return errors.Wrapf(err, "failed to install CRD %s", obj.Name) } @@ -167,7 +178,7 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release. // Pre-install anything in the crd/ directory. We do this before Helm // contacts the upstream server and builds the capabilities object. - if crds := chrt.CRDs(); !i.ClientOnly && !i.SkipCRDs && len(crds) > 0 { + if crds := chrt.CRDObjects(); !i.ClientOnly && !i.SkipCRDs && len(crds) > 0 { // On dry run, bail here if i.DryRun { i.cfg.Log("WARNING: This chart or one of its subcharts contains CRDs. Rendering may fail or contain inaccuracies.") @@ -182,7 +193,10 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release. i.cfg.Capabilities = chartutil.DefaultCapabilities i.cfg.Capabilities.APIVersions = append(i.cfg.Capabilities.APIVersions, i.APIVersions...) i.cfg.KubeClient = &kubefake.PrintingKubeClient{Out: ioutil.Discard} - i.cfg.Releases = storage.Init(driver.NewMemory()) + + mem := driver.NewMemory() + mem.SetNamespace(i.Namespace) + i.cfg.Releases = storage.Init(mem) } else if !i.ClientOnly && len(i.APIVersions) > 0 { i.cfg.Log("API Version list given outside of client only mode, this list will be ignored") } @@ -217,7 +231,7 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release. rel := i.createRelease(chrt, vals) var manifestDoc *bytes.Buffer - rel.Hooks, manifestDoc, rel.Info.Notes, err = i.cfg.renderResources(chrt, valuesToRender, i.OutputDir, i.SubNotes) + rel.Hooks, manifestDoc, rel.Info.Notes, err = i.cfg.renderResources(chrt, valuesToRender, i.ReleaseName, i.OutputDir, i.SubNotes, i.UseReleaseName, i.IncludeCRDs, i.PostRenderer) // Even for errors, attach this if available if manifestDoc != nil { rel.Manifest = manifestDoc.String() @@ -232,7 +246,7 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release. // Mark this release as in-progress rel.SetStatus(release.StatusPendingInstall, "Initial install underway") - resources, err := i.cfg.KubeClient.Build(bytes.NewBufferString(rel.Manifest), true) + resources, err := i.cfg.KubeClient.Build(bytes.NewBufferString(rel.Manifest), !i.DisableOpenAPIValidation) if err != nil { return nil, errors.Wrap(err, "unable to build kubernetes objects from release manifest") } @@ -255,6 +269,32 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release. return rel, nil } + if i.CreateNamespace { + ns := &v1.Namespace{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "Namespace", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: i.Namespace, + Labels: map[string]string{ + "name": i.Namespace, + }, + }, + } + buf, err := yaml.Marshal(ns) + if err != nil { + return nil, err + } + resourceList, err := i.cfg.KubeClient.Build(bytes.NewBuffer(buf), true) + if err != nil { + return nil, err + } + if _, err := i.cfg.KubeClient.Create(resourceList); err != nil && !apierrors.IsAlreadyExists(err) { + return nil, err + } + } + // If Replace is true, we need to supercede the last release. if i.Replace { if err := i.replaceRelease(rel); err != nil { @@ -421,7 +461,7 @@ func (i *Install) replaceRelease(rel *release.Release) error { } // renderResources renders the templates in a chart -func (c *Configuration) renderResources(ch *chart.Chart, values chartutil.Values, outputDir string, subNotes bool) ([]*release.Hook, *bytes.Buffer, string, error) { +func (c *Configuration) renderResources(ch *chart.Chart, values chartutil.Values, releaseName, outputDir string, subNotes, useReleaseName, includeCrds bool, pr postrender.PostRenderer) ([]*release.Hook, *bytes.Buffer, string, error) { hs := []*release.Hook{} b := bytes.NewBuffer(nil) @@ -450,7 +490,7 @@ func (c *Configuration) renderResources(ch *chart.Chart, values chartutil.Values } if err2 != nil { - return hs, b, "", err + return hs, b, "", err2 } // NOTES.txt gets rendered like all the other files, but because it's not a hook nor a resource, @@ -494,11 +534,34 @@ func (c *Configuration) renderResources(ch *chart.Chart, values chartutil.Values // Aggregate all valid manifests into one big doc. fileWritten := make(map[string]bool) + + if includeCrds { + for _, crd := range ch.CRDObjects() { + if outputDir == "" { + fmt.Fprintf(b, "---\n# Source: %s\n%s\n", crd.Name, string(crd.File.Data[:])) + } else { + err = writeToFile(outputDir, crd.Filename, string(crd.File.Data[:]), fileWritten[crd.Name]) + if err != nil { + return hs, b, "", err + } + fileWritten[crd.Name] = true + } + } + } + for _, m := range manifests { if outputDir == "" { fmt.Fprintf(b, "---\n# Source: %s\n%s\n", m.Name, m.Content) } else { - err = writeToFile(outputDir, m.Name, m.Content, fileWritten[m.Name]) + newDir := outputDir + if useReleaseName { + newDir = filepath.Join(outputDir, releaseName) + } + // NOTE: We do not have to worry about the post-renderer because + // output dir is only used by `helm template`. In the next major + // release, we should move this logic to template only as it is not + // used by install or upgrade + err = writeToFile(newDir, m.Name, m.Content, fileWritten[m.Name]) if err != nil { return hs, b, "", err } @@ -506,6 +569,13 @@ func (c *Configuration) renderResources(ch *chart.Chart, values chartutil.Values } } + if pr != nil { + b, err = pr.Run(b) + if err != nil { + return hs, b, notes, errors.Wrap(err, "error while running post render on files") + } + } + return hs, b, notes, nil } diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go index d6f1c88cd..bf47895a1 100644 --- a/pkg/action/install_test.go +++ b/pkg/action/install_test.go @@ -240,6 +240,21 @@ func TestInstallRelease_DryRun(t *testing.T) { is.Equal(res.Info.Description, "Dry run complete") } +func TestInstallReleaseIncorrectTemplate_DryRun(t *testing.T) { + is := assert.New(t) + instAction := installAction(t) + instAction.DryRun = true + vals := map[string]interface{}{} + _, err := instAction.Run(buildChart(withSampleIncludingIncorrectTemplates()), vals) + expectedErr := "\"hello/templates/incorrect\" at <.Values.bad.doh>: nil pointer evaluating interface {}.doh" + if err == nil { + t.Fatalf("Install should fail containing error: %s", expectedErr) + } + if err != nil { + is.Contains(err.Error(), expectedErr) + } +} + func TestInstallRelease_NoHooks(t *testing.T) { is := assert.New(t) instAction := installAction(t) @@ -471,6 +486,46 @@ func TestInstallReleaseOutputDir(t *testing.T) { is.True(os.IsNotExist(err)) } +func TestInstallOutputDirWithReleaseName(t *testing.T) { + is := assert.New(t) + instAction := installAction(t) + vals := map[string]interface{}{} + + dir, err := ioutil.TempDir("", "output-dir") + if err != nil { + log.Fatal(err) + } + defer os.RemoveAll(dir) + + instAction.OutputDir = dir + instAction.UseReleaseName = true + instAction.ReleaseName = "madra" + + newDir := filepath.Join(dir, instAction.ReleaseName) + + _, err = instAction.Run(buildChart(withSampleTemplates(), withMultipleManifestTemplate()), vals) + if err != nil { + t.Fatalf("Failed install: %s", err) + } + + _, err = os.Stat(filepath.Join(newDir, "hello/templates/goodbye")) + is.NoError(err) + + _, err = os.Stat(filepath.Join(newDir, "hello/templates/hello")) + is.NoError(err) + + _, err = os.Stat(filepath.Join(newDir, "hello/templates/with-partials")) + is.NoError(err) + + _, err = os.Stat(filepath.Join(newDir, "hello/templates/rbac")) + is.NoError(err) + + test.AssertGoldenFile(t, filepath.Join(newDir, "hello/templates/rbac"), "rbac.txt") + + _, err = os.Stat(filepath.Join(newDir, "hello/templates/empty")) + is.True(os.IsNotExist(err)) +} + func TestNameAndChart(t *testing.T) { is := assert.New(t) instAction := installAction(t) diff --git a/pkg/action/lint.go b/pkg/action/lint.go index c216c5832..2292c14bf 100644 --- a/pkg/action/lint.go +++ b/pkg/action/lint.go @@ -33,10 +33,12 @@ import ( // // It provides the implementation of 'helm lint'. type Lint struct { - Strict bool - Namespace string + Strict bool + Namespace string + WithSubcharts bool } +// LintResult is the result of Lint type LintResult struct { TotalChartsLinted int Messages []support.Message diff --git a/pkg/action/list.go b/pkg/action/list.go index 5be60ac42..ac6fd1b75 100644 --- a/pkg/action/list.go +++ b/pkg/action/list.go @@ -165,6 +165,10 @@ func (l *List) Run() ([]*release.Release, error) { return true }) + if err != nil { + return nil, err + } + if results == nil { return results, nil } @@ -238,7 +242,7 @@ func filterList(releases []*release.Release) []*release.Release { return list } -// setStateMask calculates the state mask based on parameters. +// SetStateMask calculates the state mask based on parameters. func (l *List) SetStateMask() { if l.All { l.StateMask = ListAll diff --git a/pkg/action/package.go b/pkg/action/package.go index b48fc65f0..19d845cf3 100644 --- a/pkg/action/package.go +++ b/pkg/action/package.go @@ -112,6 +112,7 @@ func setVersion(ch *chart.Chart, ver string) error { return nil } +// Clearsign signs a chart func (p *Package) Clearsign(filename string) error { // Load keyring signer, err := provenance.NewFromKeyring(p.Keyring, p.Key) diff --git a/pkg/action/pull.go b/pkg/action/pull.go index 4ff5f5c3e..ee20bbe83 100644 --- a/pkg/action/pull.go +++ b/pkg/action/pull.go @@ -101,7 +101,11 @@ func (p *Pull) Run(chartRef string) (string, error) { } if p.Verify { - fmt.Fprintf(&out, "Verification: %v\n", v) + for name := range v.SignedBy.Identities { + fmt.Fprintf(&out, "Signed by: %v\n", name) + } + fmt.Fprintf(&out, "Using Key With Fingerprint: %X\n", v.SignedBy.PrimaryKey.Fingerprint) + fmt.Fprintf(&out, "Chart Hash Verified: %s\n", v.FileHash) } // After verification, untar the chart into the requested directory. diff --git a/pkg/action/show.go b/pkg/action/show.go index b29107d4e..14b59a5ea 100644 --- a/pkg/action/show.go +++ b/pkg/action/show.go @@ -27,12 +27,17 @@ import ( "helm.sh/helm/v3/pkg/chartutil" ) +// ShowOutputFormat is the format of the output of `helm show` type ShowOutputFormat string const ( - ShowAll ShowOutputFormat = "all" - ShowChart ShowOutputFormat = "chart" + // ShowAll is the format which shows all the information of a chart + ShowAll ShowOutputFormat = "all" + // ShowChart is the format which only shows the chart's definition + ShowChart ShowOutputFormat = "chart" + // ShowValues is the format which only shows the chart's values ShowValues ShowOutputFormat = "values" + // ShowReadme is the format which only shows the chart's README ShowReadme ShowOutputFormat = "readme" ) diff --git a/pkg/action/upgrade.go b/pkg/action/upgrade.go index 1db4184ff..08b638171 100644 --- a/pkg/action/upgrade.go +++ b/pkg/action/upgrade.go @@ -29,6 +29,7 @@ import ( "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chartutil" "helm.sh/helm/v3/pkg/kube" + "helm.sh/helm/v3/pkg/postrender" "helm.sh/helm/v3/pkg/release" "helm.sh/helm/v3/pkg/releaseutil" ) @@ -54,11 +55,13 @@ type Upgrade struct { // Recreate will (if true) recreate pods after a rollback. Recreate bool // MaxHistory limits the maximum number of revisions saved per release - MaxHistory int - Atomic bool - CleanupOnFail bool - SubNotes bool - Description string + MaxHistory int + Atomic bool + CleanupOnFail bool + SubNotes bool + Description string + PostRenderer postrender.PostRenderer + DisableOpenAPIValidation bool } // NewUpgrade creates a new Upgrade object with the given configuration. @@ -161,7 +164,7 @@ func (u *Upgrade) prepareUpgrade(name string, chart *chart.Chart, vals map[strin return nil, nil, err } - hooks, manifestDoc, notesTxt, err := u.cfg.renderResources(chart, valuesToRender, "", u.SubNotes) + hooks, manifestDoc, notesTxt, err := u.cfg.renderResources(chart, valuesToRender, "", "", u.SubNotes, false, false, u.PostRenderer) if err != nil { return nil, nil, err } @@ -186,7 +189,7 @@ func (u *Upgrade) prepareUpgrade(name string, chart *chart.Chart, vals map[strin if len(notesTxt) > 0 { upgradedRelease.Info.Notes = notesTxt } - err = validateManifest(u.cfg.KubeClient, manifestDoc.Bytes()) + err = validateManifest(u.cfg.KubeClient, manifestDoc.Bytes(), !u.DisableOpenAPIValidation) return currentRelease, upgradedRelease, err } @@ -195,7 +198,7 @@ func (u *Upgrade) performUpgrade(originalRelease, upgradedRelease *release.Relea if err != nil { return upgradedRelease, errors.Wrap(err, "unable to build kubernetes objects from current release manifest") } - target, err := u.cfg.KubeClient.Build(bytes.NewBufferString(upgradedRelease.Manifest), true) + target, err := u.cfg.KubeClient.Build(bytes.NewBufferString(upgradedRelease.Manifest), !u.DisableOpenAPIValidation) if err != nil { return upgradedRelease, errors.Wrap(err, "unable to build kubernetes objects from new release manifest") } @@ -381,8 +384,8 @@ func (u *Upgrade) reuseValues(chart *chart.Chart, current *release.Release, newV return newVals, nil } -func validateManifest(c kube.Interface, manifest []byte) error { - _, err := c.Build(bytes.NewReader(manifest), true) +func validateManifest(c kube.Interface, manifest []byte, openAPIValidation bool) error { + _, err := c.Build(bytes.NewReader(manifest), openAPIValidation) return err } diff --git a/pkg/action/verify.go b/pkg/action/verify.go index c66b14b47..f36239496 100644 --- a/pkg/action/verify.go +++ b/pkg/action/verify.go @@ -17,6 +17,9 @@ limitations under the License. package action import ( + "fmt" + "strings" + "helm.sh/helm/v3/pkg/downloader" ) @@ -25,6 +28,7 @@ import ( // It provides the implementation of 'helm verify'. type Verify struct { Keyring string + Out string } // NewVerify creates a new Verify object with the given configuration. @@ -34,6 +38,22 @@ func NewVerify() *Verify { // Run executes 'helm verify'. func (v *Verify) Run(chartfile string) error { - _, err := downloader.VerifyChart(chartfile, v.Keyring) - return err + var out strings.Builder + p, err := downloader.VerifyChart(chartfile, v.Keyring) + if err != nil { + return err + } + + for name := range p.SignedBy.Identities { + fmt.Fprintf(&out, "Signed by: %v\n", name) + } + fmt.Fprintf(&out, "Using Key With Fingerprint: %X\n", p.SignedBy.PrimaryKey.Fingerprint) + fmt.Fprintf(&out, "Chart Hash Verified: %s\n", p.FileHash) + + // TODO(mattfarina): The output is set as a property rather than returned + // to maintain the Go API. In Helm v4 this function should return the out + // and the property on the struct can be removed. + v.Out = out.String() + + return nil } diff --git a/pkg/chart/chart.go b/pkg/chart/chart.go index 5eb4d4d94..bd75375a4 100644 --- a/pkg/chart/chart.go +++ b/pkg/chart/chart.go @@ -15,7 +15,10 @@ limitations under the License. package chart -import "strings" +import ( + "path/filepath" + "strings" +) // APIVersionV1 is the API version number for version 1. const APIVersionV1 = "v1" @@ -49,6 +52,15 @@ type Chart struct { dependencies []*Chart } +type CRD struct { + // Name is the File.Name for the crd file + Name string + // Filename is the File obj Name including (sub-)chart.ChartFullPath + Filename string + // File is the File obj for the crd + File *File +} + // SetDependencies replaces the chart dependencies. func (ch *Chart) SetDependencies(charts ...*Chart) { ch.dependencies = nil @@ -118,11 +130,12 @@ func (ch *Chart) AppVersion() string { } // CRDs returns a list of File objects in the 'crds/' directory of a Helm chart. +// Deprecated: use CRDObjects() func (ch *Chart) CRDs() []*File { files := []*File{} // Find all resources in the crds/ directory for _, f := range ch.Files { - if strings.HasPrefix(f.Name, "crds/") { + if strings.HasPrefix(f.Name, "crds/") && hasManifestExtension(f.Name) { files = append(files, f) } } @@ -132,3 +145,25 @@ func (ch *Chart) CRDs() []*File { } return files } + +// CRDObjects returns a list of CRD objects in the 'crds/' directory of a Helm chart & subcharts +func (ch *Chart) CRDObjects() []CRD { + crds := []CRD{} + // Find all resources in the crds/ directory + for _, f := range ch.Files { + if strings.HasPrefix(f.Name, "crds/") && hasManifestExtension(f.Name) { + mycrd := CRD{Name: f.Name, Filename: filepath.Join(ch.ChartFullPath(), f.Name), File: f} + crds = append(crds, mycrd) + } + } + // Get CRDs from dependencies, too. + for _, dep := range ch.Dependencies() { + crds = append(crds, dep.CRDObjects()...) + } + return crds +} + +func hasManifestExtension(fname string) bool { + ext := filepath.Ext(fname) + return strings.EqualFold(ext, ".yaml") || strings.EqualFold(ext, ".yml") || strings.EqualFold(ext, ".json") +} diff --git a/pkg/chart/chart_test.go b/pkg/chart/chart_test.go index 724e52933..ef623fff6 100644 --- a/pkg/chart/chart_test.go +++ b/pkg/chart/chart_test.go @@ -41,6 +41,10 @@ func TestCRDs(t *testing.T) { Name: "crdsfoo/bar/baz.yaml", Data: []byte("hello"), }, + { + Name: "crds/README.md", + Data: []byte("# hello"), + }, }, } diff --git a/pkg/chartutil/create.go b/pkg/chartutil/create.go index 496f20166..24eb1e277 100644 --- a/pkg/chartutil/create.go +++ b/pkg/chartutil/create.go @@ -445,6 +445,15 @@ func CreateFrom(chartfile *chart.Metadata, dest, src string) error { } schart.Values = m + // SaveDir looks for the file values.yaml when saving rather than the values + // key in order to preserve the comments in the YAML. The name placeholder + // needs to be replaced on that file. + for _, f := range schart.Raw { + if f.Name == ValuesfileName { + f.Data = transform(string(f.Data), schart.Name()) + } + } + return SaveDir(schart, dest) } diff --git a/pkg/chartutil/create_test.go b/pkg/chartutil/create_test.go index 82fde586c..d2a3b0a20 100644 --- a/pkg/chartutil/create_test.go +++ b/pkg/chartutil/create_test.go @@ -17,6 +17,7 @@ limitations under the License. package chartutil import ( + "bytes" "io/ioutil" "os" "path/filepath" @@ -105,5 +106,14 @@ func TestCreateFrom(t *testing.T) { if _, err := os.Stat(filepath.Join(dir, f)); err != nil { t.Errorf("Expected %s file: %s", f, err) } + + // Check each file to make sure has been replaced + b, err := ioutil.ReadFile(filepath.Join(dir, f)) + if err != nil { + t.Errorf("Unable to read file %s: %s", f, err) + } + if bytes.Contains(b, []byte("")) { + t.Errorf("File %s contains ", f) + } } } diff --git a/pkg/chartutil/dependencies.go b/pkg/chartutil/dependencies.go index 4b389dc22..d2e7d6dc9 100644 --- a/pkg/chartutil/dependencies.go +++ b/pkg/chartutil/dependencies.go @@ -173,6 +173,14 @@ Loop: cd = append(cd, n) } } + // don't keep disabled charts in metadata + cdMetadata := []*chart.Dependency{} + copy(cdMetadata, c.Metadata.Dependencies[:0]) + for _, n := range c.Metadata.Dependencies { + if _, ok := rm[n.Name]; !ok { + cdMetadata = append(cdMetadata, n) + } + } // recursively call self to process sub dependencies for _, t := range cd { @@ -181,6 +189,9 @@ Loop: return err } } + // set the correct dependencies in metadata + c.Metadata.Dependencies = nil + c.Metadata.Dependencies = append(c.Metadata.Dependencies, cdMetadata...) c.SetDependencies(cd...) return nil @@ -233,7 +244,7 @@ func processImportValues(c *chart.Chart) error { // get child table vv, err := cvals.Table(r.Name + "." + child) if err != nil { - log.Printf("Warning: ImportValues missing table: %v", err) + log.Printf("Warning: ImportValues missing table from chart %s: %v", r.Name, err) continue } // create value map from child to be merged into parent diff --git a/pkg/chartutil/dependencies_test.go b/pkg/chartutil/dependencies_test.go index ecd632540..342d7fe87 100644 --- a/pkg/chartutil/dependencies_test.go +++ b/pkg/chartutil/dependencies_test.go @@ -239,6 +239,36 @@ func TestProcessDependencyImportValues(t *testing.T) { } } +func TestProcessDependencyImportValuesForEnabledCharts(t *testing.T) { + c := loadChart(t, "testdata/import-values-from-enabled-subchart/parent-chart") + nameOverride := "parent-chart-prod" + + if err := processDependencyImportValues(c); err != nil { + t.Fatalf("processing import values dependencies %v", err) + } + + if len(c.Dependencies()) != 2 { + t.Fatalf("expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) + } + + if err := processDependencyEnabled(c, c.Values, ""); err != nil { + t.Fatalf("expected no errors but got %q", err) + } + + if len(c.Dependencies()) != 1 { + t.Fatal("expected no changes in dependencies") + } + + if len(c.Metadata.Dependencies) != 1 { + t.Fatalf("expected 1 dependency specified in Chart.yaml, got %d", len(c.Metadata.Dependencies)) + } + + prodDependencyValues := c.Dependencies()[0].Values + if prodDependencyValues["nameOverride"] != nameOverride { + t.Fatalf("dependency chart name should be %s but got %s", nameOverride, prodDependencyValues["nameOverride"]) + } +} + func TestGetAliasDependency(t *testing.T) { c := loadChart(t, "testdata/frobnitz") req := c.Metadata.Dependencies diff --git a/pkg/chartutil/expand_test.go b/pkg/chartutil/expand_test.go index 0eb35aedb..9a85e3247 100644 --- a/pkg/chartutil/expand_test.go +++ b/pkg/chartutil/expand_test.go @@ -39,19 +39,6 @@ func TestExpand(t *testing.T) { t.Fatal(err) } - files, err := ioutil.ReadDir(dest) - if err != nil { - t.Fatalf("error reading output directory %s: %s", dest, err) - } - - if len(files) != 1 { - t.Fatalf("expected a single chart directory in output directory %s", dest) - } - - if !files[0].IsDir() { - t.Fatalf("expected a chart directory in output directory %s", dest) - } - expectedChartPath := filepath.Join(dest, "frobnitz") fi, err := os.Stat(expectedChartPath) if err != nil { @@ -81,8 +68,14 @@ func TestExpand(t *testing.T) { if err != nil { t.Fatal(err) } - if fi.Size() != expect.Size() { - t.Errorf("Expected %s to have size %d, got %d", fi.Name(), expect.Size(), fi.Size()) + // os.Stat can return different values for directories, based on the OS + // for Linux, for example, os.Stat alwaty returns the size of the directory + // (value-4096) regardless of the size of the contents of the directory + mode := expect.Mode() + if !mode.IsDir() { + if fi.Size() != expect.Size() { + t.Errorf("Expected %s to have size %d, got %d", fi.Name(), expect.Size(), fi.Size()) + } } } } @@ -127,8 +120,14 @@ func TestExpandFile(t *testing.T) { if err != nil { t.Fatal(err) } - if fi.Size() != expect.Size() { - t.Errorf("Expected %s to have size %d, got %d", fi.Name(), expect.Size(), fi.Size()) + // os.Stat can return different values for directories, based on the OS + // for Linux, for example, os.Stat alwaty returns the size of the directory + // (value-4096) regardless of the size of the contents of the directory + mode := expect.Mode() + if !mode.IsDir() { + if fi.Size() != expect.Size() { + t.Errorf("Expected %s to have size %d, got %d", fi.Name(), expect.Size(), fi.Size()) + } } } } diff --git a/pkg/chartutil/testdata/import-values-from-enabled-subchart/parent-chart/Chart.lock b/pkg/chartutil/testdata/import-values-from-enabled-subchart/parent-chart/Chart.lock new file mode 100644 index 000000000..b2f17fb39 --- /dev/null +++ b/pkg/chartutil/testdata/import-values-from-enabled-subchart/parent-chart/Chart.lock @@ -0,0 +1,9 @@ +dependencies: +- name: dev + repository: file://envs/dev + version: v0.1.0 +- name: prod + repository: file://envs/prod + version: v0.1.0 +digest: sha256:9403fc24f6cf9d6055820126cf7633b4bd1fed3c77e4880c674059f536346182 +generated: "2020-02-03T10:38:51.180474+01:00" diff --git a/pkg/chartutil/testdata/import-values-from-enabled-subchart/parent-chart/Chart.yaml b/pkg/chartutil/testdata/import-values-from-enabled-subchart/parent-chart/Chart.yaml new file mode 100644 index 000000000..24b26d9e5 --- /dev/null +++ b/pkg/chartutil/testdata/import-values-from-enabled-subchart/parent-chart/Chart.yaml @@ -0,0 +1,22 @@ +apiVersion: v2 +name: parent-chart +version: v0.1.0 +appVersion: v0.1.0 +dependencies: + - name: dev + repository: "file://envs/dev" + version: ">= 0.0.1" + condition: dev.enabled,global.dev.enabled + tags: + - dev + import-values: + - data + + - name: prod + repository: "file://envs/prod" + version: ">= 0.0.1" + condition: prod.enabled,global.prod.enabled + tags: + - prod + import-values: + - data \ No newline at end of file diff --git a/pkg/chartutil/testdata/import-values-from-enabled-subchart/parent-chart/charts/dev-v0.1.0.tgz b/pkg/chartutil/testdata/import-values-from-enabled-subchart/parent-chart/charts/dev-v0.1.0.tgz new file mode 100644 index 000000000..d28e1621c Binary files /dev/null and b/pkg/chartutil/testdata/import-values-from-enabled-subchart/parent-chart/charts/dev-v0.1.0.tgz differ diff --git a/pkg/chartutil/testdata/import-values-from-enabled-subchart/parent-chart/charts/prod-v0.1.0.tgz b/pkg/chartutil/testdata/import-values-from-enabled-subchart/parent-chart/charts/prod-v0.1.0.tgz new file mode 100644 index 000000000..a0c5aa84b Binary files /dev/null and b/pkg/chartutil/testdata/import-values-from-enabled-subchart/parent-chart/charts/prod-v0.1.0.tgz differ diff --git a/pkg/chartutil/testdata/import-values-from-enabled-subchart/parent-chart/envs/dev/Chart.yaml b/pkg/chartutil/testdata/import-values-from-enabled-subchart/parent-chart/envs/dev/Chart.yaml new file mode 100644 index 000000000..80a52f538 --- /dev/null +++ b/pkg/chartutil/testdata/import-values-from-enabled-subchart/parent-chart/envs/dev/Chart.yaml @@ -0,0 +1,4 @@ +apiVersion: v2 +name: dev +version: v0.1.0 +appVersion: v0.1.0 \ No newline at end of file diff --git a/pkg/chartutil/testdata/import-values-from-enabled-subchart/parent-chart/envs/dev/values.yaml b/pkg/chartutil/testdata/import-values-from-enabled-subchart/parent-chart/envs/dev/values.yaml new file mode 100644 index 000000000..38f03484d --- /dev/null +++ b/pkg/chartutil/testdata/import-values-from-enabled-subchart/parent-chart/envs/dev/values.yaml @@ -0,0 +1,9 @@ +# Dev values parent-chart +nameOverride: parent-chart-dev +exports: + data: + resources: + autoscaler: + minReplicas: 1 + maxReplicas: 3 + targetCPUUtilizationPercentage: 80 diff --git a/pkg/chartutil/testdata/import-values-from-enabled-subchart/parent-chart/envs/prod/Chart.yaml b/pkg/chartutil/testdata/import-values-from-enabled-subchart/parent-chart/envs/prod/Chart.yaml new file mode 100644 index 000000000..bda4be458 --- /dev/null +++ b/pkg/chartutil/testdata/import-values-from-enabled-subchart/parent-chart/envs/prod/Chart.yaml @@ -0,0 +1,4 @@ +apiVersion: v2 +name: prod +version: v0.1.0 +appVersion: v0.1.0 \ No newline at end of file diff --git a/pkg/chartutil/testdata/import-values-from-enabled-subchart/parent-chart/envs/prod/values.yaml b/pkg/chartutil/testdata/import-values-from-enabled-subchart/parent-chart/envs/prod/values.yaml new file mode 100644 index 000000000..10cc756b2 --- /dev/null +++ b/pkg/chartutil/testdata/import-values-from-enabled-subchart/parent-chart/envs/prod/values.yaml @@ -0,0 +1,9 @@ +# Prod values parent-chart +nameOverride: parent-chart-prod +exports: + data: + resources: + autoscaler: + minReplicas: 2 + maxReplicas: 5 + targetCPUUtilizationPercentage: 90 diff --git a/pkg/chartutil/testdata/import-values-from-enabled-subchart/parent-chart/templates/autoscaler.yaml b/pkg/chartutil/testdata/import-values-from-enabled-subchart/parent-chart/templates/autoscaler.yaml new file mode 100644 index 000000000..976e5a8f1 --- /dev/null +++ b/pkg/chartutil/testdata/import-values-from-enabled-subchart/parent-chart/templates/autoscaler.yaml @@ -0,0 +1,16 @@ +################################################################################################### +# parent-chart horizontal pod autoscaler +################################################################################################### +apiVersion: autoscaling/v1 +kind: HorizontalPodAutoscaler +metadata: + name: {{ .Release.Name }}-autoscaler + namespace: {{ .Release.Namespace }} +spec: + scaleTargetRef: + apiVersion: apps/v1beta1 + kind: Deployment + name: {{ .Release.Name }} + minReplicas: {{ required "A valid .Values.resources.autoscaler.minReplicas entry required!" .Values.resources.autoscaler.minReplicas }} + maxReplicas: {{ required "A valid .Values.resources.autoscaler.maxReplicas entry required!" .Values.resources.autoscaler.maxReplicas }} + targetCPUUtilizationPercentage: {{ required "A valid .Values.resources.autoscaler.targetCPUUtilizationPercentage!" .Values.resources.autoscaler.targetCPUUtilizationPercentage }} \ No newline at end of file diff --git a/pkg/chartutil/testdata/import-values-from-enabled-subchart/parent-chart/values.yaml b/pkg/chartutil/testdata/import-values-from-enabled-subchart/parent-chart/values.yaml new file mode 100644 index 000000000..b812f0a33 --- /dev/null +++ b/pkg/chartutil/testdata/import-values-from-enabled-subchart/parent-chart/values.yaml @@ -0,0 +1,10 @@ +# Default values for parent-chart. +nameOverride: parent-chart +tags: + dev: false + prod: true +resources: + autoscaler: + minReplicas: 0 + maxReplicas: 0 + targetCPUUtilizationPercentage: 99 \ No newline at end of file diff --git a/pkg/cli/environment.go b/pkg/cli/environment.go index 5f947aec7..e279331b0 100644 --- a/pkg/cli/environment.go +++ b/pkg/cli/environment.go @@ -46,6 +46,10 @@ type EnvSettings struct { KubeConfig string // KubeContext is the name of the kubeconfig context. KubeContext string + // Bearer KubeToken used for authentication + KubeToken string + // Kubernetes API Server Endpoint for authentication + KubeAPIServer string // Debug indicates whether or not Helm is running in Debug mode. Debug bool // RegistryConfig is the path to the registry config file. @@ -63,6 +67,8 @@ func New() *EnvSettings { env := EnvSettings{ namespace: os.Getenv("HELM_NAMESPACE"), KubeContext: os.Getenv("HELM_KUBECONTEXT"), + KubeToken: os.Getenv("HELM_KUBETOKEN"), + KubeAPIServer: os.Getenv("HELM_KUBEAPISERVER"), PluginsDirectory: envOr("HELM_PLUGINS", helmpath.DataPath("plugins")), RegistryConfig: envOr("HELM_REGISTRY_CONFIG", helmpath.ConfigPath("registry.json")), RepositoryConfig: envOr("HELM_REPOSITORY_CONFIG", helmpath.ConfigPath("repositories.yaml")), @@ -77,6 +83,8 @@ func (s *EnvSettings) AddFlags(fs *pflag.FlagSet) { fs.StringVarP(&s.namespace, "namespace", "n", s.namespace, "namespace scope for this request") fs.StringVar(&s.KubeConfig, "kubeconfig", "", "path to the kubeconfig file") fs.StringVar(&s.KubeContext, "kube-context", s.KubeContext, "name of the kubeconfig context to use") + fs.StringVar(&s.KubeToken, "kube-token", s.KubeToken, "bearer token used for authentication") + fs.StringVar(&s.KubeAPIServer, "kube-apiserver", s.KubeAPIServer, "the address and the port for the Kubernetes API server") fs.BoolVar(&s.Debug, "debug", s.Debug, "enable verbose output") fs.StringVar(&s.RegistryConfig, "registry-config", s.RegistryConfig, "path to the registry config file") fs.StringVar(&s.RepositoryConfig, "repository-config", s.RepositoryConfig, "path to the file containing repository names and URLs") @@ -100,6 +108,8 @@ func (s *EnvSettings) EnvVars() map[string]string { "HELM_REPOSITORY_CONFIG": s.RepositoryConfig, "HELM_NAMESPACE": s.Namespace(), "HELM_KUBECONTEXT": s.KubeContext, + "HELM_KUBETOKEN": s.KubeToken, + "HELM_KUBEAPISERVER": s.KubeAPIServer, } if s.KubeConfig != "" { @@ -124,7 +134,15 @@ func (s *EnvSettings) Namespace() string { //RESTClientGetter gets the kubeconfig from EnvSettings func (s *EnvSettings) RESTClientGetter() genericclioptions.RESTClientGetter { s.configOnce.Do(func() { - s.config = kube.GetConfig(s.KubeConfig, s.KubeContext, s.namespace) + clientConfig := kube.GetConfig(s.KubeConfig, s.KubeContext, s.namespace) + if s.KubeToken != "" { + clientConfig.BearerToken = &s.KubeToken + } + if s.KubeAPIServer != "" { + clientConfig.APIServer = &s.KubeAPIServer + } + + s.config = clientConfig }) return s.config } diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index e46af6944..cb139f824 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -19,6 +19,7 @@ import ( "fmt" "io" "io/ioutil" + "log" "net/url" "os" "path" @@ -86,7 +87,17 @@ func (m *Manager) Build() error { } if sum, err := resolver.HashReq(req, lock.Dependencies); err != nil || sum != lock.Digest { - return errors.New("Chart.lock is out of sync with Chart.yaml") + // If lock digest differs and chart is apiVersion v1, it maybe because the lock was built + // with Helm 2 and therefore should be checked with Helm v2 hash + // Fix for: https://github.com/helm/helm/issues/7233 + if c.Metadata.APIVersion == chart.APIVersionV1 { + log.Println("warning: a valid Helm v3 hash was not found. Checking against Helm v2 hash...") + if sum, err := resolver.HashV2Req(req); err != nil || sum != lock.Digest { + return errors.New("the lock file (requirements.lock) is out of sync with the dependencies file (requirements.yaml). Please update the dependencies") + } + } else { + return errors.New("the lock file (Chart.lock) is out of sync with the dependencies file (Chart.yaml). Please update the dependencies") + } } // Check that all of the repos we're dependent on actually exist. diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index 490561037..1cc94d685 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -120,6 +120,7 @@ func (e Engine) initFunMap(t *template.Template, referenceTpls map[string]render includedNames[name] = 1 } err := t.ExecuteTemplate(&buf, name, data) + includedNames[name]-- return buf.String(), err } diff --git a/pkg/engine/engine_test.go b/pkg/engine/engine_test.go index f3609fcbd..d5f36aac8 100644 --- a/pkg/engine/engine_test.go +++ b/pkg/engine/engine_test.go @@ -643,3 +643,58 @@ func TestAlterFuncMap_tplinclude(t *testing.T) { } } + +func TestRenderRecursionLimit(t *testing.T) { + // endless recursion should produce an error + c := &chart.Chart{ + Metadata: &chart.Metadata{Name: "bad"}, + Templates: []*chart.File{ + {Name: "templates/base", Data: []byte(`{{include "recursion" . }}`)}, + {Name: "templates/recursion", Data: []byte(`{{define "recursion"}}{{include "recursion" . }}{{end}}`)}, + }, + } + v := chartutil.Values{ + "Values": "", + "Chart": c.Metadata, + "Release": chartutil.Values{ + "Name": "TestRelease", + }, + } + expectErr := "rendering template has a nested reference name: recursion: unable to execute template" + + _, err := Render(c, v) + if err == nil || !strings.HasSuffix(err.Error(), expectErr) { + t.Errorf("Expected err with suffix: %s", expectErr) + } + + // calling the same function many times is ok + times := 4000 + phrase := "All work and no play makes Jack a dull boy" + printFunc := `{{define "overlook"}}{{printf "` + phrase + `\n"}}{{end}}` + var repeatedIncl string + for i := 0; i < times; i++ { + repeatedIncl += `{{include "overlook" . }}` + } + + d := &chart.Chart{ + Metadata: &chart.Metadata{Name: "overlook"}, + Templates: []*chart.File{ + {Name: "templates/quote", Data: []byte(repeatedIncl)}, + {Name: "templates/_function", Data: []byte(printFunc)}, + }, + } + + out, err := Render(d, v) + if err != nil { + t.Fatal(err) + } + + var expect string + for i := 0; i < times; i++ { + expect += phrase + "\n" + } + if got := out["overlook/templates/quote"]; got != expect { + t.Errorf("Expected %q, got %q (%v)", expect, got, out) + } + +} diff --git a/pkg/engine/files.go b/pkg/engine/files.go index 3a6659d11..d7e62da5a 100644 --- a/pkg/engine/files.go +++ b/pkg/engine/files.go @@ -30,7 +30,7 @@ import ( type files map[string][]byte // NewFiles creates a new files from chart files. -// Given an []*any.Any (the format for files in a chart.Chart), extract a map of files. +// Given an []*chart.File (the format for files in a chart.Chart), extract a map of files. func newFiles(from []*chart.File) files { files := make(map[string][]byte) for _, f := range from { diff --git a/pkg/gates/gates_test.go b/pkg/gates/gates_test.go index a71d4905b..6bdd17ed6 100644 --- a/pkg/gates/gates_test.go +++ b/pkg/gates/gates_test.go @@ -45,3 +45,12 @@ func TestError(t *testing.T) { t.Errorf("incorrect error message. Received %s", g.Error().Error()) } } + +func TestString(t *testing.T) { + os.Unsetenv(name) + g := Gate(name) + + if g.String() != "HELM_EXPERIMENTAL_FEATURE" { + t.Errorf("incorrect string representation. Received %s", g.String()) + } +} diff --git a/pkg/helmpath/home_windows_test.go b/pkg/helmpath/home_windows_test.go index af74558a8..796ced62c 100644 --- a/pkg/helmpath/home_windows_test.go +++ b/pkg/helmpath/home_windows_test.go @@ -23,9 +23,9 @@ import ( ) func TestHelmHome(t *testing.T) { - os.Setenv(xdg.XDGCacheHomeEnvVar, "c:\\") - os.Setenv(xdg.XDGConfigHomeEnvVar, "d:\\") - os.Setenv(xdg.XDGDataHomeEnvVar, "e:\\") + os.Setenv(xdg.CacheHomeEnvVar, "c:\\") + os.Setenv(xdg.ConfigHomeEnvVar, "d:\\") + os.Setenv(xdg.DataHomeEnvVar, "e:\\") isEq := func(t *testing.T, a, b string) { if a != b { t.Errorf("Expected %q, got %q", b, a) diff --git a/pkg/helmpath/lazypath_windows_test.go b/pkg/helmpath/lazypath_windows_test.go index d02a0a7f6..866e7b9d9 100644 --- a/pkg/helmpath/lazypath_windows_test.go +++ b/pkg/helmpath/lazypath_windows_test.go @@ -32,7 +32,7 @@ const ( ) func TestDataPath(t *testing.T) { - os.Unsetenv(DataHomeEnvVar) + os.Unsetenv(xdg.DataHomeEnvVar) os.Setenv("APPDATA", filepath.Join(homedir.HomeDir(), "foo")) expected := filepath.Join(homedir.HomeDir(), "foo", appName, testFile) @@ -41,7 +41,7 @@ func TestDataPath(t *testing.T) { t.Errorf("expected '%s', got '%s'", expected, lazy.dataPath(testFile)) } - os.Setenv(DataHomeEnvVar, filepath.Join(homedir.HomeDir(), "xdg")) + os.Setenv(xdg.DataHomeEnvVar, filepath.Join(homedir.HomeDir(), "xdg")) expected = filepath.Join(homedir.HomeDir(), "xdg", appName, testFile) @@ -70,8 +70,8 @@ func TestConfigPath(t *testing.T) { } func TestCachePath(t *testing.T) { - os.Unsetenv(CacheHomeEnvVar) - os.Setenv("APPDATA", filepath.Join(homedir.HomeDir(), "foo")) + os.Unsetenv(xdg.CacheHomeEnvVar) + os.Setenv("TEMP", filepath.Join(homedir.HomeDir(), "foo")) expected := filepath.Join(homedir.HomeDir(), "foo", appName, testFile) @@ -79,7 +79,7 @@ func TestCachePath(t *testing.T) { t.Errorf("expected '%s', got '%s'", expected, lazy.cachePath(testFile)) } - os.Setenv(CacheHomeEnvVar, filepath.Join(homedir.HomeDir(), "xdg")) + os.Setenv(xdg.CacheHomeEnvVar, filepath.Join(homedir.HomeDir(), "xdg")) expected = filepath.Join(homedir.HomeDir(), "xdg", appName, testFile) diff --git a/pkg/kube/client.go b/pkg/kube/client.go index 3853e9036..31dabcc5d 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -54,6 +54,8 @@ var ErrNoObjectsVisited = errors.New("no objects visited") type Client struct { Factory Factory Log func(string, ...interface{}) + // Namespace allows to bypass the kubeconfig file for the choice of the namespace + Namespace string } var addToScheme sync.Once @@ -86,7 +88,7 @@ func (c *Client) IsReachable() error { client, _ := c.Factory.KubernetesClientSet() _, err := client.ServerVersion() if err != nil { - return errors.New("Kubernetes cluster unreachable") + return fmt.Errorf("Kubernetes cluster unreachable: %s", err.Error()) } return nil } @@ -115,6 +117,9 @@ func (c *Client) Wait(resources ResourceList, timeout time.Duration) error { } func (c *Client) namespace() string { + if c.Namespace != "" { + return c.Namespace + } if ns, _, err := c.Factory.ToRawKubeConfigLoader().Namespace(); err == nil { return ns } @@ -204,11 +209,6 @@ func (c *Client) Update(original, target ResourceList, force bool) (*Result, err } for _, info := range original.Difference(target) { - if info.Mapping.GroupVersionKind.Kind == "CustomResourceDefinition" { - c.Log("Skipping the deletion of CustomResourceDefinition %q", info.Name) - continue - } - c.Log("Deleting %q in %s...", info.Name, info.Namespace) res.Deleted = append(res.Deleted, info) if err := deleteResource(info); err != nil { @@ -231,11 +231,6 @@ func (c *Client) Delete(resources ResourceList) (*Result, []error) { var errs []error res := &Result{} err := perform(resources, func(info *resource.Info) error { - if info.Mapping.GroupVersionKind.Kind == "CustomResourceDefinition" { - c.Log("Skipping the deletion of CustomResourceDefinition %q", info.Name) - return nil - } - c.Log("Starting delete for %q %s", info.Name, info.Mapping.GroupVersionKind.Kind) if err := c.skipIfNotFound(deleteResource(info)); err != nil { // Collect the error and continue on diff --git a/pkg/kube/converter.go b/pkg/kube/converter.go index a5a6ae1f7..3bf0e358c 100644 --- a/pkg/kube/converter.go +++ b/pkg/kube/converter.go @@ -17,6 +17,10 @@ limitations under the License. package kube // import "helm.sh/helm/v3/pkg/kube" import ( + "sync" + + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" @@ -24,6 +28,9 @@ import ( "k8s.io/client-go/kubernetes/scheme" ) +var k8sNativeScheme *runtime.Scheme +var k8sNativeSchemeOnce sync.Once + // AsVersioned converts the given info into a runtime.Object with the correct // group and version set func AsVersioned(info *resource.Info) runtime.Object { @@ -33,12 +40,30 @@ func AsVersioned(info *resource.Info) runtime.Object { // convertWithMapper converts the given object with the optional provided // RESTMapping. If no mapping is provided, the default schema versioner is used func convertWithMapper(obj runtime.Object, mapping *meta.RESTMapping) runtime.Object { - var gv = runtime.GroupVersioner(schema.GroupVersions(scheme.Scheme.PrioritizedVersionsAllGroups())) + s := kubernetesNativeScheme() + var gv = runtime.GroupVersioner(schema.GroupVersions(s.PrioritizedVersionsAllGroups())) if mapping != nil { gv = mapping.GroupVersionKind.GroupVersion() } - if obj, err := runtime.ObjectConvertor(scheme.Scheme).ConvertToVersion(obj, gv); err == nil { + if obj, err := runtime.ObjectConvertor(s).ConvertToVersion(obj, gv); err == nil { return obj } return obj } + +// kubernetesNativeScheme returns a clean *runtime.Scheme with _only_ Kubernetes +// native resources added to it. This is required to break free of custom resources +// that may have been added to scheme.Scheme due to Helm being used as a package in +// combination with e.g. a versioned kube client. If we would not do this, the client +// may attempt to perform e.g. a 3-way-merge strategy patch for custom resources. +func kubernetesNativeScheme() *runtime.Scheme { + k8sNativeSchemeOnce.Do(func() { + k8sNativeScheme = runtime.NewScheme() + scheme.AddToScheme(k8sNativeScheme) + // API extensions are not in the above scheme set, + // and must thus be added separately. + apiextensionsv1beta1.AddToScheme(k8sNativeScheme) + apiextensionsv1.AddToScheme(k8sNativeScheme) + }) + return k8sNativeScheme +} diff --git a/pkg/kube/wait.go b/pkg/kube/wait.go index f0005a61e..0254a60bb 100644 --- a/pkg/kube/wait.go +++ b/pkg/kube/wait.go @@ -188,12 +188,25 @@ func (w *waiter) serviceReady(s *corev1.Service) bool { } // Make sure the service is not explicitly set to "None" before checking the IP - if (s.Spec.ClusterIP != corev1.ClusterIPNone && s.Spec.ClusterIP == "") || - // This checks if the service has a LoadBalancer and that balancer has an Ingress defined - (s.Spec.Type == corev1.ServiceTypeLoadBalancer && s.Status.LoadBalancer.Ingress == nil) { - w.log("Service does not have IP address: %s/%s", s.GetNamespace(), s.GetName()) + if s.Spec.ClusterIP != corev1.ClusterIPNone && s.Spec.ClusterIP == "" { + w.log("Service does not have cluster IP address: %s/%s", s.GetNamespace(), s.GetName()) return false } + + // This checks if the service has a LoadBalancer and that balancer has an Ingress defined + if s.Spec.Type == corev1.ServiceTypeLoadBalancer { + // do not wait when at least 1 external IP is set + if len(s.Spec.ExternalIPs) > 0 { + w.log("Service %s/%s has external IP addresses (%v), marking as ready", s.GetNamespace(), s.GetName(), s.Spec.ExternalIPs) + return true + } + + if s.Status.LoadBalancer.Ingress == nil { + w.log("Service does not have load balancer ingress IP address: %s/%s", s.GetNamespace(), s.GetName()) + return false + } + } + return true } diff --git a/pkg/postrender/exec.go b/pkg/postrender/exec.go new file mode 100644 index 000000000..0860e7c35 --- /dev/null +++ b/pkg/postrender/exec.go @@ -0,0 +1,108 @@ +/* +Copyright The Helm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package postrender + +import ( + "bytes" + "io" + "os/exec" + "path/filepath" + + "github.com/pkg/errors" +) + +type execRender struct { + binaryPath string +} + +// NewExec returns a PostRenderer implementation that calls the provided binary. +// It returns an error if the binary cannot be found. If the path does not +// contain any separators, it will search in $PATH, otherwise it will resolve +// any relative paths to a fully qualified path +func NewExec(binaryPath string) (PostRenderer, error) { + fullPath, err := getFullPath(binaryPath) + if err != nil { + return nil, err + } + return &execRender{fullPath}, nil +} + +// Run the configured binary for the post render +func (p *execRender) Run(renderedManifests *bytes.Buffer) (*bytes.Buffer, error) { + cmd := exec.Command(p.binaryPath) + stdin, err := cmd.StdinPipe() + if err != nil { + return nil, err + } + + var postRendered = &bytes.Buffer{} + var stderr = &bytes.Buffer{} + cmd.Stdout = postRendered + cmd.Stderr = stderr + + go func() { + defer stdin.Close() + io.Copy(stdin, renderedManifests) + }() + err = cmd.Run() + if err != nil { + return nil, errors.Wrapf(err, "error while running command %s. error output:\n%s", p.binaryPath, stderr.String()) + } + + return postRendered, nil +} + +// getFullPath returns the full filepath to the binary to execute. If the path +// does not contain any separators, it will search in $PATH, otherwise it will +// resolve any relative paths to a fully qualified path +func getFullPath(binaryPath string) (string, error) { + // NOTE(thomastaylor312): I am leaving this code commented out here. During + // the implementation of post-render, it was brought up that if we are + // relying on plguins, we should actually use the plugin system so it can + // properly handle multiple OSs. This will be a feature add in the future, + // so I left this code for reference. It can be deleted or reused once the + // feature is implemented + + // Manually check the plugin dir first + // if !strings.Contains(binaryPath, string(filepath.Separator)) { + // // First check the plugin dir + // pluginDir := helmpath.DataPath("plugins") // Default location + // // If location for plugins is explicitly set, check there + // if v, ok := os.LookupEnv("HELM_PLUGINS"); ok { + // pluginDir = v + // } + // // The plugins variable can actually contain multple paths, so loop through those + // for _, p := range filepath.SplitList(pluginDir) { + // _, err := os.Stat(filepath.Join(p, binaryPath)) + // if err != nil && !os.IsNotExist(err) { + // return "", err + // } else if err == nil { + // binaryPath = filepath.Join(p, binaryPath) + // break + // } + // } + // } + + // Now check for the binary using the given path or check if it exists in + // the path and is executable + checkedPath, err := exec.LookPath(binaryPath) + if err != nil { + return "", errors.Wrapf(err, "unable to find binary at %s", binaryPath) + } + + return filepath.Abs(checkedPath) +} diff --git a/pkg/postrender/exec_test.go b/pkg/postrender/exec_test.go new file mode 100644 index 000000000..ef0956949 --- /dev/null +++ b/pkg/postrender/exec_test.go @@ -0,0 +1,155 @@ +/* +Copyright The Helm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package postrender + +import ( + "bytes" + "io/ioutil" + "os" + "path/filepath" + "runtime" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "helm.sh/helm/v3/internal/test/ensure" +) + +const testingScript = `#!/bin/sh +sed s/FOOTEST/BARTEST/g <&0 +` + +func TestGetFullPath(t *testing.T) { + is := assert.New(t) + t.Run("full path resolves correctly", func(t *testing.T) { + testpath, cleanup := setupTestingScript(t) + defer cleanup() + + fullPath, err := getFullPath(testpath) + is.NoError(err) + is.Equal(testpath, fullPath) + }) + + t.Run("relative path resolves correctly", func(t *testing.T) { + testpath, cleanup := setupTestingScript(t) + defer cleanup() + + currentDir, err := os.Getwd() + require.NoError(t, err) + relative, err := filepath.Rel(currentDir, testpath) + require.NoError(t, err) + fullPath, err := getFullPath(relative) + is.NoError(err) + is.Equal(testpath, fullPath) + }) + + t.Run("binary in PATH resolves correctly", func(t *testing.T) { + testpath, cleanup := setupTestingScript(t) + defer cleanup() + + realPath := os.Getenv("PATH") + os.Setenv("PATH", filepath.Dir(testpath)) + defer func() { + os.Setenv("PATH", realPath) + }() + + fullPath, err := getFullPath(filepath.Base(testpath)) + is.NoError(err) + is.Equal(testpath, fullPath) + }) + + // NOTE(thomastaylor312): See note in getFullPath for more details why this + // is here + + // t.Run("binary in plugin path resolves correctly", func(t *testing.T) { + // testpath, cleanup := setupTestingScript(t) + // defer cleanup() + + // realPath := os.Getenv("HELM_PLUGINS") + // os.Setenv("HELM_PLUGINS", filepath.Dir(testpath)) + // defer func() { + // os.Setenv("HELM_PLUGINS", realPath) + // }() + + // fullPath, err := getFullPath(filepath.Base(testpath)) + // is.NoError(err) + // is.Equal(testpath, fullPath) + // }) + + // t.Run("binary in multiple plugin paths resolves correctly", func(t *testing.T) { + // testpath, cleanup := setupTestingScript(t) + // defer cleanup() + + // realPath := os.Getenv("HELM_PLUGINS") + // os.Setenv("HELM_PLUGINS", filepath.Dir(testpath)+string(os.PathListSeparator)+"/another/dir") + // defer func() { + // os.Setenv("HELM_PLUGINS", realPath) + // }() + + // fullPath, err := getFullPath(filepath.Base(testpath)) + // is.NoError(err) + // is.Equal(testpath, fullPath) + // }) +} + +func TestExecRun(t *testing.T) { + if runtime.GOOS == "windows" { + // the actual Run test uses a basic sed example, so skip this test on windows + t.Skip("skipping on windows") + } + is := assert.New(t) + testpath, cleanup := setupTestingScript(t) + defer cleanup() + + renderer, err := NewExec(testpath) + require.NoError(t, err) + + output, err := renderer.Run(bytes.NewBufferString("FOOTEST")) + is.NoError(err) + is.Contains(output.String(), "BARTEST") +} + +func setupTestingScript(t *testing.T) (filepath string, cleanup func()) { + t.Helper() + + tempdir := ensure.TempDir(t) + + f, err := ioutil.TempFile(tempdir, "post-render-test.sh") + if err != nil { + t.Fatalf("unable to create tempfile for testing: %s", err) + } + + _, err = f.WriteString(testingScript) + if err != nil { + t.Fatalf("unable to write tempfile for testing: %s", err) + } + + err = f.Chmod(0755) + if err != nil { + t.Fatalf("unable to make tempfile executable for testing: %s", err) + } + + err = f.Close() + if err != nil { + t.Fatalf("unable to close tempfile after writing: %s", err) + } + + return f.Name(), func() { + os.RemoveAll(tempdir) + } +} diff --git a/pkg/postrender/postrender.go b/pkg/postrender/postrender.go new file mode 100644 index 000000000..76f0f5a74 --- /dev/null +++ b/pkg/postrender/postrender.go @@ -0,0 +1,29 @@ +/* +Copyright The Helm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// package postrender contains an interface that can be implemented for custom +// post-renderers and an exec implementation that can be used for arbitrary +// binaries and scripts +package postrender + +import "bytes" + +type PostRenderer interface { + // Run expects a single buffer filled with Helm rendered manifests. It + // expects the modified results to be returned on a separate buffer or an + // error if there was an issue or failure while running the post render step + Run(renderedManifests *bytes.Buffer) (modifiedManifests *bytes.Buffer, err error) +} diff --git a/pkg/storage/driver/memory.go b/pkg/storage/driver/memory.go index ca8756c0c..a99b36ef0 100644 --- a/pkg/storage/driver/memory.go +++ b/pkg/storage/driver/memory.go @@ -26,18 +26,33 @@ import ( var _ Driver = (*Memory)(nil) -// MemoryDriverName is the string name of this driver. -const MemoryDriverName = "Memory" +const ( + // MemoryDriverName is the string name of this driver. + MemoryDriverName = "Memory" + + defaultNamespace = "default" +) + +// A map of release names to list of release records +type memReleases map[string]records // Memory is the in-memory storage driver implementation. type Memory struct { sync.RWMutex - cache map[string]records + namespace string + // A map of namespaces to releases + cache map[string]memReleases } // NewMemory initializes a new memory driver. func NewMemory() *Memory { - return &Memory{cache: map[string]records{}} + return &Memory{cache: map[string]memReleases{}, namespace: "default"} +} + +// SetNamespace sets a specific namespace in which releases will be accessed. +// An empty string indicates all namespaces (for the list operation) +func (mem *Memory) SetNamespace(ns string) { + mem.namespace = ns } // Name returns the name of the driver. @@ -56,7 +71,7 @@ func (mem *Memory) Get(key string) (*rspb.Release, error) { if _, err := strconv.Atoi(ver); err != nil { return nil, ErrInvalidKey } - if recs, ok := mem.cache[name]; ok { + if recs, ok := mem.cache[mem.namespace][name]; ok { if r := recs.Get(key); r != nil { return r.rls, nil } @@ -72,13 +87,23 @@ func (mem *Memory) List(filter func(*rspb.Release) bool) ([]*rspb.Release, error defer unlock(mem.rlock()) var ls []*rspb.Release - for _, recs := range mem.cache { - recs.Iter(func(_ int, rec *record) bool { - if filter(rec.rls) { - ls = append(ls, rec.rls) - } - return true - }) + for namespace := range mem.cache { + if mem.namespace != "" { + // Should only list releases of this namespace + namespace = mem.namespace + } + for _, recs := range mem.cache[namespace] { + recs.Iter(func(_ int, rec *record) bool { + if filter(rec.rls) { + ls = append(ls, rec.rls) + } + return true + }) + } + if mem.namespace != "" { + // Should only list releases of this namespace + break + } } return ls, nil } @@ -93,18 +118,28 @@ func (mem *Memory) Query(keyvals map[string]string) ([]*rspb.Release, error) { lbs.fromMap(keyvals) var ls []*rspb.Release - for _, recs := range mem.cache { - recs.Iter(func(_ int, rec *record) bool { - // A query for a release name that doesn't exist (has been deleted) - // can cause rec to be nil. - if rec == nil { - return false - } - if rec.lbs.match(lbs) { - ls = append(ls, rec.rls) - } - return true - }) + for namespace := range mem.cache { + if mem.namespace != "" { + // Should only query releases of this namespace + namespace = mem.namespace + } + for _, recs := range mem.cache[namespace] { + recs.Iter(func(_ int, rec *record) bool { + // A query for a release name that doesn't exist (has been deleted) + // can cause rec to be nil. + if rec == nil { + return false + } + if rec.lbs.match(lbs) { + ls = append(ls, rec.rls) + } + return true + }) + } + if mem.namespace != "" { + // Should only query releases of this namespace + break + } } return ls, nil } @@ -113,14 +148,25 @@ func (mem *Memory) Query(keyvals map[string]string) ([]*rspb.Release, error) { func (mem *Memory) Create(key string, rls *rspb.Release) error { defer unlock(mem.wlock()) - if recs, ok := mem.cache[rls.Name]; ok { + // For backwards compatibility, we protect against an unset namespace + namespace := rls.Namespace + if namespace == "" { + namespace = defaultNamespace + } + mem.SetNamespace(namespace) + + if _, ok := mem.cache[namespace]; !ok { + mem.cache[namespace] = memReleases{} + } + + if recs, ok := mem.cache[namespace][rls.Name]; ok { if err := recs.Add(newRecord(key, rls)); err != nil { return err } - mem.cache[rls.Name] = recs + mem.cache[namespace][rls.Name] = recs return nil } - mem.cache[rls.Name] = records{newRecord(key, rls)} + mem.cache[namespace][rls.Name] = records{newRecord(key, rls)} return nil } @@ -128,9 +174,18 @@ func (mem *Memory) Create(key string, rls *rspb.Release) error { func (mem *Memory) Update(key string, rls *rspb.Release) error { defer unlock(mem.wlock()) - if rs, ok := mem.cache[rls.Name]; ok && rs.Exists(key) { - rs.Replace(key, newRecord(key, rls)) - return nil + // For backwards compatibility, we protect against an unset namespace + namespace := rls.Namespace + if namespace == "" { + namespace = defaultNamespace + } + mem.SetNamespace(namespace) + + if _, ok := mem.cache[namespace]; ok { + if rs, ok := mem.cache[namespace][rls.Name]; ok && rs.Exists(key) { + rs.Replace(key, newRecord(key, rls)) + return nil + } } return ErrReleaseNotFound } @@ -150,11 +205,13 @@ func (mem *Memory) Delete(key string) (*rspb.Release, error) { if _, err := strconv.Atoi(ver); err != nil { return nil, ErrInvalidKey } - if recs, ok := mem.cache[name]; ok { - if r := recs.Remove(key); r != nil { - // recs.Remove changes the slice reference, so we have to re-assign it. - mem.cache[name] = recs - return r.rls, nil + if _, ok := mem.cache[mem.namespace]; ok { + if recs, ok := mem.cache[mem.namespace][name]; ok { + if r := recs.Remove(key); r != nil { + // recs.Remove changes the slice reference, so we have to re-assign it. + mem.cache[mem.namespace][name] = recs + return r.rls, nil + } } } return nil, ErrReleaseNotFound diff --git a/pkg/storage/driver/memory_test.go b/pkg/storage/driver/memory_test.go index c74df9432..7a2e8578e 100644 --- a/pkg/storage/driver/memory_test.go +++ b/pkg/storage/driver/memory_test.go @@ -37,7 +37,7 @@ func TestMemoryCreate(t *testing.T) { err bool }{ { - "create should success", + "create should succeed", releaseStub("rls-c", 1, "default", rspb.StatusDeployed), false, }, @@ -46,6 +46,16 @@ func TestMemoryCreate(t *testing.T) { releaseStub("rls-a", 1, "default", rspb.StatusDeployed), true, }, + { + "create in namespace should succeed", + releaseStub("rls-a", 1, "mynamespace", rspb.StatusDeployed), + false, + }, + { + "create in other namespace should fail (release already exists)", + releaseStub("rls-c", 1, "mynamespace", rspb.StatusDeployed), + true, + }, } ts := tsFixtureMemory(t) @@ -57,45 +67,103 @@ func TestMemoryCreate(t *testing.T) { if !tt.err { t.Fatalf("failed to create %q: %s", tt.desc, err) } + } else if tt.err { + t.Fatalf("Did not get expected error for %q\n", tt.desc) } } } func TestMemoryGet(t *testing.T) { var tests = []struct { - desc string - key string - err bool + desc string + key string + namespace string + err bool }{ - {"release key should exist", "rls-a.v1", false}, - {"release key should not exist", "rls-a.v5", true}, + {"release key should exist", "rls-a.v1", "default", false}, + {"release key should not exist", "rls-a.v5", "default", true}, + {"release key in namespace should exist", "rls-c.v1", "mynamespace", false}, + {"release key in namespace should not exist", "rls-a.v1", "mynamespace", true}, } ts := tsFixtureMemory(t) for _, tt := range tests { + ts.SetNamespace(tt.namespace) if _, err := ts.Get(tt.key); err != nil { if !tt.err { t.Fatalf("Failed %q to get '%s': %q\n", tt.desc, tt.key, err) } + } else if tt.err { + t.Fatalf("Did not get expected error for %q '%s'\n", tt.desc, tt.key) } } } +func TestMemoryList(t *testing.T) { + ts := tsFixtureMemory(t) + ts.SetNamespace("default") + + // list all deployed releases + dpl, err := ts.List(func(rel *rspb.Release) bool { + return rel.Info.Status == rspb.StatusDeployed + }) + // check + if err != nil { + t.Errorf("Failed to list deployed releases: %s", err) + } + if len(dpl) != 2 { + t.Errorf("Expected 2 deployed, got %d", len(dpl)) + } + + // list all superseded releases + ssd, err := ts.List(func(rel *rspb.Release) bool { + return rel.Info.Status == rspb.StatusSuperseded + }) + // check + if err != nil { + t.Errorf("Failed to list superseded releases: %s", err) + } + if len(ssd) != 6 { + t.Errorf("Expected 6 superseded, got %d", len(ssd)) + } + + // list all deleted releases + del, err := ts.List(func(rel *rspb.Release) bool { + return rel.Info.Status == rspb.StatusUninstalled + }) + // check + if err != nil { + t.Errorf("Failed to list deleted releases: %s", err) + } + if len(del) != 0 { + t.Errorf("Expected 0 deleted, got %d", len(del)) + } +} + func TestMemoryQuery(t *testing.T) { var tests = []struct { - desc string - xlen int - lbs map[string]string + desc string + xlen int + namespace string + lbs map[string]string }{ { "should be 2 query results", 2, + "default", + map[string]string{"status": "deployed"}, + }, + { + "should be 1 query result", + 1, + "mynamespace", map[string]string{"status": "deployed"}, }, } ts := tsFixtureMemory(t) for _, tt := range tests { + ts.SetNamespace(tt.namespace) l, err := ts.Query(tt.lbs) if err != nil { t.Fatalf("Failed to query: %s\n", err) @@ -122,8 +190,20 @@ func TestMemoryUpdate(t *testing.T) { }, { "update release does not exist", - "rls-z.v1", - releaseStub("rls-z", 1, "default", rspb.StatusUninstalled), + "rls-c.v1", + releaseStub("rls-c", 1, "default", rspb.StatusUninstalled), + true, + }, + { + "update release status in namespace", + "rls-c.v4", + releaseStub("rls-c", 4, "mynamespace", rspb.StatusSuperseded), + false, + }, + { + "update release in namespace does not exist", + "rls-a.v1", + releaseStub("rls-a", 1, "mynamespace", rspb.StatusUninstalled), true, }, } @@ -135,8 +215,11 @@ func TestMemoryUpdate(t *testing.T) { t.Fatalf("Failed %q: %s\n", tt.desc, err) } continue + } else if tt.err { + t.Fatalf("Did not get expected error for %q '%s'\n", tt.desc, tt.key) } + ts.SetNamespace(tt.rls.Namespace) r, err := ts.Get(tt.key) if err != nil { t.Fatalf("Failed to get: %s\n", err) @@ -150,26 +233,35 @@ func TestMemoryUpdate(t *testing.T) { func TestMemoryDelete(t *testing.T) { var tests = []struct { - desc string - key string - err bool + desc string + key string + namespace string + err bool }{ - {"release key should exist", "rls-a.v1", false}, - {"release key should not exist", "rls-a.v5", true}, + {"release key should exist", "rls-a.v4", "default", false}, + {"release key should not exist", "rls-a.v5", "default", true}, + {"release key from other namespace should not exist", "rls-c.v4", "default", true}, + {"release key from namespace should exist", "rls-c.v4", "mynamespace", false}, + {"release key from namespace should not exist", "rls-c.v5", "mynamespace", true}, + {"release key from namespace2 should not exist", "rls-a.v4", "mynamespace", true}, } ts := tsFixtureMemory(t) - start, err := ts.Query(map[string]string{"name": "rls-a"}) + ts.SetNamespace("") + start, err := ts.Query(map[string]string{"status": "deployed"}) if err != nil { t.Errorf("Query failed: %s", err) } startLen := len(start) for _, tt := range tests { + ts.SetNamespace(tt.namespace) if rel, err := ts.Delete(tt.key); err != nil { if !tt.err { t.Fatalf("Failed %q to get '%s': %q\n", tt.desc, tt.key, err) } continue + } else if tt.err { + t.Fatalf("Did not get expected error for %q '%s'\n", tt.desc, tt.key) } else if fmt.Sprintf("%s.v%d", rel.Name, rel.Version) != tt.key { t.Fatalf("Asked for delete on %s, but deleted %d", tt.key, rel.Version) } @@ -180,14 +272,15 @@ func TestMemoryDelete(t *testing.T) { } // Make sure that the deleted records are gone. - end, err := ts.Query(map[string]string{"name": "rls-a"}) + ts.SetNamespace("") + end, err := ts.Query(map[string]string{"status": "deployed"}) if err != nil { t.Errorf("Query failed: %s", err) } endLen := len(end) - if startLen <= endLen { - t.Errorf("expected start %d to be less than end %d", startLen, endLen) + if startLen-2 != endLen { + t.Errorf("expected end to be %d instead of %d", startLen-2, endLen) for _, ee := range end { t.Logf("Name: %s, Version: %d", ee.Name, ee.Version) } diff --git a/pkg/storage/driver/mock_test.go b/pkg/storage/driver/mock_test.go index 4c9b4ef9c..3cb3773c2 100644 --- a/pkg/storage/driver/mock_test.go +++ b/pkg/storage/driver/mock_test.go @@ -53,6 +53,11 @@ func tsFixtureMemory(t *testing.T) *Memory { releaseStub("rls-b", 1, "default", rspb.StatusSuperseded), releaseStub("rls-b", 3, "default", rspb.StatusSuperseded), releaseStub("rls-b", 2, "default", rspb.StatusSuperseded), + // rls-c in other namespace + releaseStub("rls-c", 4, "mynamespace", rspb.StatusDeployed), + releaseStub("rls-c", 1, "mynamespace", rspb.StatusSuperseded), + releaseStub("rls-c", 3, "mynamespace", rspb.StatusSuperseded), + releaseStub("rls-c", 2, "mynamespace", rspb.StatusSuperseded), } mem := NewMemory() diff --git a/pkg/storage/driver/records_test.go b/pkg/storage/driver/records_test.go index 79b60044f..3ede92bcd 100644 --- a/pkg/storage/driver/records_test.go +++ b/pkg/storage/driver/records_test.go @@ -17,6 +17,7 @@ limitations under the License. package driver // import "helm.sh/helm/v3/pkg/storage/driver" import ( + "reflect" "testing" rspb "helm.sh/helm/v3/pkg/release" @@ -110,3 +111,96 @@ func TestRecordsRemoveAt(t *testing.T) { t.Fatalf("Expected length of rs to be 1, got %d", len(rs)) } } + +func TestRecordsGet(t *testing.T) { + rs := records([]*record{ + newRecord("rls-a.v1", releaseStub("rls-a", 1, "default", rspb.StatusSuperseded)), + newRecord("rls-a.v2", releaseStub("rls-a", 2, "default", rspb.StatusDeployed)), + }) + + var tests = []struct { + desc string + key string + rec *record + }{ + { + "get valid key", + "rls-a.v1", + newRecord("rls-a.v1", releaseStub("rls-a", 1, "default", rspb.StatusSuperseded)), + }, + { + "get invalid key", + "rls-a.v3", + nil, + }, + } + + for _, tt := range tests { + got := rs.Get(tt.key) + if !reflect.DeepEqual(tt.rec, got) { + t.Fatalf("Expected %v, got %v", tt.rec, got) + } + } +} + +func TestRecordsIndex(t *testing.T) { + rs := records([]*record{ + newRecord("rls-a.v1", releaseStub("rls-a", 1, "default", rspb.StatusSuperseded)), + newRecord("rls-a.v2", releaseStub("rls-a", 2, "default", rspb.StatusDeployed)), + }) + + var tests = []struct { + desc string + key string + sort int + }{ + { + "get valid key", + "rls-a.v1", + 0, + }, + { + "get invalid key", + "rls-a.v3", + -1, + }, + } + + for _, tt := range tests { + got, _ := rs.Index(tt.key) + if got != tt.sort { + t.Fatalf("Expected %d, got %d", tt.sort, got) + } + } +} + +func TestRecordsExists(t *testing.T) { + rs := records([]*record{ + newRecord("rls-a.v1", releaseStub("rls-a", 1, "default", rspb.StatusSuperseded)), + newRecord("rls-a.v2", releaseStub("rls-a", 2, "default", rspb.StatusDeployed)), + }) + + var tests = []struct { + desc string + key string + ok bool + }{ + { + "get valid key", + "rls-a.v1", + true, + }, + { + "get invalid key", + "rls-a.v3", + false, + }, + } + + for _, tt := range tests { + got := rs.Exists(tt.key) + if got != tt.ok { + t.Fatalf("Expected %t, got %t", tt.ok, got) + } + } +} diff --git a/pkg/strvals/parser_test.go b/pkg/strvals/parser_test.go index 7f38efa52..44d317220 100644 --- a/pkg/strvals/parser_test.go +++ b/pkg/strvals/parser_test.go @@ -449,6 +449,39 @@ func TestParseIntoString(t *testing.T) { } } +func TestParseFile(t *testing.T) { + input := "name1=path1" + expect := map[string]interface{}{ + "name1": "value1", + } + rs2v := func(rs []rune) (interface{}, error) { + v := string(rs) + if v != "path1" { + t.Errorf("%s: runesToVal: Expected value path1, got %s", input, v) + return "", nil + } + return "value1", nil + } + + got, err := ParseFile(input, rs2v) + if err != nil { + t.Fatal(err) + } + + y1, err := yaml.Marshal(expect) + if err != nil { + t.Fatal(err) + } + y2, err := yaml.Marshal(got) + if err != nil { + t.Fatalf("Error serializing parsed value: %s", err) + } + + if string(y1) != string(y2) { + t.Errorf("%s: Expected:\n%s\nGot:\n%s", input, y1, y2) + } +} + func TestParseIntoFile(t *testing.T) { got := map[string]interface{}{} input := "name1=path1" diff --git a/scripts/get b/scripts/get index 711635ee3..3da11d4a4 100755 --- a/scripts/get +++ b/scripts/get @@ -78,16 +78,14 @@ verifySupported() { # checkDesiredVersion checks if the desired version is available. checkDesiredVersion() { if [ "x$DESIRED_VERSION" == "x" ]; then - # FIXME(bacongobbler): hard code the desired version for the time being. - # A better fix would be to filter for Helm 2 release pages. - TAG="v2.16.1" # Get tag from release URL - # local latest_release_url="https://github.com/helm/helm/releases/latest" - # if type "curl" > /dev/null; then - # TAG=$(curl -Ls -o /dev/null -w %{url_effective} $latest_release_url | grep -oE "[^/]+$" ) - # elif type "wget" > /dev/null; then - # TAG=$(wget $latest_release_url --server-response -O /dev/null 2>&1 | awk '/^ Location: /{DEST=$2} END{ print DEST}' | grep -oE "[^/]+$") - # fi + local release_url="https://github.com/helm/helm/releases" + if type "curl" > /dev/null; then + + TAG=$(curl -Ls $release_url | grep 'href="/helm/helm/releases/tag/v2.' | grep -v no-underline | head -n 1 | cut -d '"' -f 2 | awk '{n=split($NF,a,"/");print a[n]}' | awk 'a !~ $0{print}; {a=$0}') + elif type "wget" > /dev/null; then + TAG=$(wget $release_url -O - 2>&1 | grep 'href="/helm/helm/releases/tag/v2.' | grep -v no-underline | head -n 1 | cut -d '"' -f 2 | awk '{n=split($NF,a,"/");print a[n]}' | awk 'a !~ $0{print}; {a=$0}') + fi else TAG=$DESIRED_VERSION fi diff --git a/scripts/get-helm-3 b/scripts/get-helm-3 index c1655a68e..a974d97b6 100755 --- a/scripts/get-helm-3 +++ b/scripts/get-helm-3 @@ -78,11 +78,11 @@ verifySupported() { checkDesiredVersion() { if [ "x$DESIRED_VERSION" == "x" ]; then # Get tag from release URL - local latest_release_url="https://github.com/helm/helm/releases/latest" + local latest_release_url="https://github.com/helm/helm/releases" if type "curl" > /dev/null; then - TAG=$(curl -Ls -o /dev/null -w %{url_effective} $latest_release_url | grep -oE "[^/]+$" ) + TAG=$(curl -Ls $latest_release_url | grep 'href="/helm/helm/releases/tag/v3.' | grep -v no-underline | head -n 1 | cut -d '"' -f 2 | awk '{n=split($NF,a,"/");print a[n]}' | awk 'a !~ $0{print}; {a=$0}') elif type "wget" > /dev/null; then - TAG=$(wget $latest_release_url --server-response -O /dev/null 2>&1 | awk '/^ Location: /{DEST=$2} END{ print DEST}' | grep -oE "[^/]+$") + TAG=$(wget $latest_release_url -O - 2>&1 | grep 'href="/helm/helm/releases/tag/v3.' | grep -v no-underline | head -n 1 | cut -d '"' -f 2 | awk '{n=split($NF,a,"/");print a[n]}' | awk 'a !~ $0{print}; {a=$0}') fi else TAG=$DESIRED_VERSION diff --git a/testdata/releases.yaml b/testdata/releases.yaml new file mode 100644 index 000000000..fef79f424 --- /dev/null +++ b/testdata/releases.yaml @@ -0,0 +1,43 @@ +# This file can be used as input to create test releases: +# HELM_MEMORY_DRIVER_DATA=./testdata/releases.yaml HELM_DRIVER=memory helm list --all-namespaces +- name: athos + version: 1 + namespace: default + info: + status: deployed + chart: + metadata: + name: athos-chart + version: 1.0.0 + appversion: 1.1.0 +- name: porthos + version: 2 + namespace: default + info: + status: deployed + chart: + metadata: + name: prothos-chart + version: 0.2.0 + appversion: 0.2.2 +- name: aramis + version: 3 + namespace: default + info: + status: deployed + chart: + metadata: + name: aramis-chart + version: 0.0.3 + appversion: 3.0.3 +- name: dartagnan + version: 4 + namespace: gascony + info: + status: deployed + chart: + metadata: + name: dartagnan-chart + version: 0.4.4 + appversion: 4.4.4 +