diff --git a/.appveyor.yml b/.appveyor.yml deleted file mode 100644 index 40d02927d..000000000 --- a/.appveyor.yml +++ /dev/null @@ -1,17 +0,0 @@ -version: "{build}" -clone_folder: c:\go\src\k8s.io\helm -environment: - GOPATH: c:\go - PATH: c:\ProgramData\bin;$(PATH) -install: - - ps: iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/fishworks/gofish/master/scripts/install.ps1')) - - gofish init - - gofish install glide - - glide install --strip-vendor -cache: - - vendor -> glide.lock -build: "off" -deploy: "off" -test_script: - - go build .\cmd\... - - go test .\... diff --git a/.circleci/config.yml b/.circleci/config.yml index 96f53ee40..7bba262a8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -4,13 +4,13 @@ jobs: working_directory: /go/src/k8s.io/helm parallelism: 3 docker: - - image: golang:1.11 + - image: golang:1.12.1 environment: PROJECT_NAME: "kubernetes-helm" steps: - checkout - setup_remote_docker: - version: 17.09.0-ce + version: 18.06.0-ce - restore_cache: keys: - glide-{{ checksum "glide.yaml" }}-{{ checksum "glide.lock" }} diff --git a/.gitignore b/.gitignore index 2414f7f2b..d1ec13265 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,9 @@ rootfs/rudder vendor/ *.exe .idea/ -*.iml \ No newline at end of file +*.iml +*.swp +*~ +.classpath +.project +.settings/** diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7736cbd6b..fc35e0643 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ # Contributing Guidelines -The Kubernetes Helm project accepts contributions via GitHub pull requests. This document outlines the process to help get your contribution accepted. +The Helm project accepts contributions via GitHub pull requests. This document outlines the process to help get your contribution accepted. ## Reporting a Security Issue @@ -15,7 +15,7 @@ us a chance to try to fix the issue before it is exploited in the wild. The sign-off is a simple line at the end of the explanation for a commit. All commits needs to be signed. Your signature certifies that you wrote the patch or otherwise have the right to contribute the material. The rules are pretty simple, -if you can certify the below (from [developercertificate.org](http://developercertificate.org/)): +if you can certify the below (from [developercertificate.org](https://developercertificate.org/)): ``` Developer Certificate of Origin @@ -242,7 +242,7 @@ Documentation PRs will follow the same lifecycle as other PRs. They will also be ## The Triager Each week, one of the core maintainers will serve as the designated "triager" starting after the -public standup meetings on Thursday. This person will be in charge triaging new PRs and issues +public stand-up meetings on Thursday. This person will be in charge triaging new PRs and issues throughout the work week. ## Labels diff --git a/Makefile b/Makefile index 0677cafe4..3584521a4 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,10 @@ DOCKER_REGISTRY ?= gcr.io IMAGE_PREFIX ?= kubernetes-helm -DEV_IMAGE ?= golang:1.11 +DEV_IMAGE ?= golang:1.12.1 SHORT_NAME ?= tiller SHORT_NAME_RUDDER ?= rudder 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 DIST_DIRS = find * -type d -exec # go option @@ -44,10 +45,25 @@ dist: $(DIST_DIRS) zip -r helm-${VERSION}-{}.zip {} \; \ ) +.PHONY: fetch-dist +fetch-dist: + mkdir -p _dist + cd _dist && \ + for obj in ${TARGET_OBJS} ; do \ + curl -sSL -o helm-${VERSION}-$${obj} https://storage.googleapis.com/kubernetes-helm/helm-${VERSION}-$${obj} ; \ + done + +.PHONY: sign +sign: + for f in _dist/*.{gz,zip,sha256} ; do \ + gpg --armor --detach-sign $${f} ; \ + done + .PHONY: checksum checksum: for f in _dist/*.{gz,zip} ; do \ shasum -a 256 "$${f}" | awk '{print $$1}' > "$${f}.sha256" ; \ + echo -n "Checksum: " && cat $${f}.sha256 ; \ done .PHONY: check-docker diff --git a/_proto/README.md b/_proto/README.md index 0ebd6b6a4..7704572eb 100644 --- a/_proto/README.md +++ b/_proto/README.md @@ -3,7 +3,7 @@ Protobuf3 type declarations for the Helm API Packages - - `hapi.chart` Complete serialization of Heml charts + - `hapi.chart` Complete serialization of Helm charts - `hapi.release` Information about installed charts (Releases) such as metadata about when they were installed, their status, and how they were configured. - `hapi.services.rudder` Definition for the ReleaseModuleService used by Tiller to manipulate releases on a given node - `hapi.services.tiller` Definition of the ReleaseService provided by Tiller and used by Helm clients to manipulate releases cluster wide. diff --git a/_proto/hapi/release/status.proto b/_proto/hapi/release/status.proto index aa90760b3..e6ccd3d6e 100644 --- a/_proto/hapi/release/status.proto +++ b/_proto/hapi/release/status.proto @@ -29,7 +29,7 @@ message Status { UNKNOWN = 0; // Status_DEPLOYED indicates that the release has been pushed to Kubernetes. DEPLOYED = 1; - // Status_DELETED indicates that a release has been deleted from Kubermetes. + // Status_DELETED indicates that a release has been deleted from Kubernetes. DELETED = 2; // Status_SUPERSEDED indicates that this release object is outdated and a newer one exists. SUPERSEDED = 3; diff --git a/cmd/helm/completion.go b/cmd/helm/completion.go index d0249b2ea..039dcbe5f 100644 --- a/cmd/helm/completion.go +++ b/cmd/helm/completion.go @@ -212,7 +212,8 @@ __helm_convert_bash_to_zsh() { -e "s/${LWORD}compopt${RWORD}/__helm_compopt/g" \ -e "s/${LWORD}declare${RWORD}/__helm_declare/g" \ -e "s/\\\$(type${RWORD}/\$(__helm_type/g" \ - -e 's/aliashash\["\(\w\+\)"\]/aliashash[\1]/g' \ + -e 's/aliashash\["\(.\{1,\}\)"\]/aliashash[\1]/g' \ + -e 's/FUNCNAME/funcstack/g' \ <<'BASH_COMPLETION_EOF' ` out.Write([]byte(zshInitialization)) diff --git a/cmd/helm/dependency_build.go b/cmd/helm/dependency_build.go index 3af3c1243..64a80f3bd 100644 --- a/cmd/helm/dependency_build.go +++ b/cmd/helm/dependency_build.go @@ -29,11 +29,11 @@ const dependencyBuildDesc = ` Build out the charts/ directory from the requirements.lock file. Build is used to reconstruct a chart's dependencies to the state specified in -the lock file. This will not re-negotiate dependencies, as 'helm dependency update' -does. +the lock file. -If no lock file is found, 'helm dependency build' will mirror the behavior -of 'helm dependency update'. +If no lock file is found, 'helm dependency build' will mirror the behavior of +the 'helm dependency update' command. This means it will update the on-disk +dependencies to mirror the requirements.yaml file and generate a lock file. ` type dependencyBuildCmd struct { diff --git a/cmd/helm/helm_test.go b/cmd/helm/helm_test.go index 6e915fa7b..83f1173f2 100644 --- a/cmd/helm/helm_test.go +++ b/cmd/helm/helm_test.go @@ -30,6 +30,7 @@ import ( "github.com/spf13/cobra" "k8s.io/client-go/util/homedir" + "k8s.io/helm/cmd/helm/installer" "k8s.io/helm/pkg/helm" "k8s.io/helm/pkg/helm/environment" "k8s.io/helm/pkg/helm/helmpath" @@ -137,7 +138,7 @@ func ensureTestHome(home helmpath.Home, t *testing.T) error { } } - localRepoIndexFile := home.LocalRepository(localRepositoryIndexFile) + localRepoIndexFile := home.LocalRepository(installer.LocalRepositoryIndexFile) if fi, err := os.Stat(localRepoIndexFile); err != nil { i := repo.NewIndexFile() if err := i.WriteFile(localRepoIndexFile, 0644); err != nil { diff --git a/cmd/helm/init.go b/cmd/helm/init.go index db35ef037..682189f84 100644 --- a/cmd/helm/init.go +++ b/cmd/helm/init.go @@ -31,11 +31,9 @@ import ( "k8s.io/apimachinery/pkg/util/yaml" "k8s.io/helm/cmd/helm/installer" - "k8s.io/helm/pkg/getter" "k8s.io/helm/pkg/helm" "k8s.io/helm/pkg/helm/helmpath" "k8s.io/helm/pkg/helm/portforwarder" - "k8s.io/helm/pkg/repo" "k8s.io/helm/pkg/version" ) @@ -60,12 +58,6 @@ To dump a manifest containing the Tiller deployment YAML, combine the '--dry-run' and '--debug' flags. ` -const ( - stableRepository = "stable" - localRepository = "local" - localRepositoryIndexFile = "index.yaml" -) - var ( stableRepositoryURL = "https://kubernetes-charts.storage.googleapis.com" // This is the IPv4 loopback, not localhost, because we have to force IPv4 @@ -266,14 +258,8 @@ func (i *initCmd) run() error { return nil } - if err := ensureDirectories(i.home, i.out); err != nil { - return err - } - if err := ensureDefaultRepos(i.home, i.out, i.skipRefresh); err != nil { - return err - } - if err := ensureRepoFileFormat(i.home.RepositoryFile(), i.out); err != nil { - return err + if err := installer.Initialize(i.home, i.out, i.skipRefresh, settings, stableRepositoryURL, localRepositoryURL); err != nil { + return fmt.Errorf("error initializing: %s", err) } fmt.Fprintf(i.out, "$HELM_HOME has been configured at %s.\n", settings.Home) @@ -351,117 +337,6 @@ func (i *initCmd) ping(image string) error { return nil } -// ensureDirectories checks to see if $HELM_HOME exists. -// -// If $HELM_HOME does not exist, this function will create it. -func ensureDirectories(home helmpath.Home, out io.Writer) error { - configDirectories := []string{ - home.String(), - home.Repository(), - home.Cache(), - home.LocalRepository(), - home.Plugins(), - home.Starters(), - home.Archive(), - } - for _, p := range configDirectories { - if fi, err := os.Stat(p); err != nil { - fmt.Fprintf(out, "Creating %s \n", p) - if err := os.MkdirAll(p, 0755); err != nil { - return fmt.Errorf("Could not create %s: %s", p, err) - } - } else if !fi.IsDir() { - return fmt.Errorf("%s must be a directory", p) - } - } - - return nil -} - -func ensureDefaultRepos(home helmpath.Home, out io.Writer, skipRefresh bool) error { - repoFile := home.RepositoryFile() - if fi, err := os.Stat(repoFile); err != nil { - fmt.Fprintf(out, "Creating %s \n", repoFile) - f := repo.NewRepoFile() - sr, err := initStableRepo(home.CacheIndex(stableRepository), out, skipRefresh, home) - if err != nil { - return err - } - lr, err := initLocalRepo(home.LocalRepository(localRepositoryIndexFile), home.CacheIndex("local"), out, home) - if err != nil { - return err - } - f.Add(sr) - f.Add(lr) - if err := f.WriteFile(repoFile, 0644); err != nil { - return err - } - } else if fi.IsDir() { - return fmt.Errorf("%s must be a file, not a directory", repoFile) - } - return nil -} - -func initStableRepo(cacheFile string, out io.Writer, skipRefresh bool, home helmpath.Home) (*repo.Entry, error) { - fmt.Fprintf(out, "Adding %s repo with URL: %s \n", stableRepository, stableRepositoryURL) - c := repo.Entry{ - Name: stableRepository, - URL: stableRepositoryURL, - Cache: cacheFile, - } - r, err := repo.NewChartRepository(&c, getter.All(settings)) - if err != nil { - return nil, err - } - - if skipRefresh { - return &c, nil - } - - // In this case, the cacheFile is always absolute. So passing empty string - // is safe. - if err := r.DownloadIndexFile(""); err != nil { - return nil, fmt.Errorf("Looks like %q is not a valid chart repository or cannot be reached: %s", stableRepositoryURL, err.Error()) - } - - return &c, nil -} - -func initLocalRepo(indexFile, cacheFile string, out io.Writer, home helmpath.Home) (*repo.Entry, error) { - if fi, err := os.Stat(indexFile); err != nil { - fmt.Fprintf(out, "Adding %s repo with URL: %s \n", localRepository, localRepositoryURL) - i := repo.NewIndexFile() - if err := i.WriteFile(indexFile, 0644); err != nil { - return nil, err - } - - //TODO: take this out and replace with helm update functionality - if err := createLink(indexFile, cacheFile, home); err != nil { - return nil, err - } - } else if fi.IsDir() { - return nil, fmt.Errorf("%s must be a file, not a directory", indexFile) - } - - return &repo.Entry{ - Name: localRepository, - URL: localRepositoryURL, - Cache: cacheFile, - }, nil -} - -func ensureRepoFileFormat(file string, out io.Writer) error { - r, err := repo.LoadRepositoriesFile(file) - if err == repo.ErrRepoOutOfDate { - fmt.Fprintln(out, "Updating repository file format...") - if err := r.WriteFile(file, 0644); err != nil { - return err - } - } - - return nil -} - // watchTillerUntilReady waits for the tiller pod to become available. This is useful in situations where we // want to wait before we call New(). // diff --git a/cmd/helm/init_test.go b/cmd/helm/init_test.go index fd6ef97c4..b58303f42 100644 --- a/cmd/helm/init_test.go +++ b/cmd/helm/init_test.go @@ -28,7 +28,7 @@ import ( "github.com/ghodss/yaml" - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" "k8s.io/api/extensions/v1beta1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -179,51 +179,6 @@ func TestInitCmd_dryRun(t *testing.T) { } } -func TestEnsureHome(t *testing.T) { - home, err := ioutil.TempDir("", "helm_home") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(home) - - b := bytes.NewBuffer(nil) - hh := helmpath.Home(home) - settings.Home = hh - if err := ensureDirectories(hh, b); err != nil { - t.Error(err) - } - if err := ensureDefaultRepos(hh, b, false); err != nil { - t.Error(err) - } - if err := ensureDefaultRepos(hh, b, true); err != nil { - t.Error(err) - } - if err := ensureRepoFileFormat(hh.RepositoryFile(), b); err != nil { - t.Error(err) - } - - expectedDirs := []string{hh.String(), hh.Repository(), hh.Cache(), hh.LocalRepository()} - for _, dir := range expectedDirs { - if fi, err := os.Stat(dir); err != nil { - t.Errorf("%s", err) - } else if !fi.IsDir() { - t.Errorf("%s is not a directory", fi) - } - } - - if fi, err := os.Stat(hh.RepositoryFile()); err != nil { - t.Error(err) - } else if fi.IsDir() { - t.Errorf("%s should not be a directory", fi) - } - - if fi, err := os.Stat(hh.LocalRepository(localRepositoryIndexFile)); err != nil { - t.Errorf("%s", err) - } else if fi.IsDir() { - t.Errorf("%s should not be a directory", fi) - } -} - func TestInitCmd_tlsOptions(t *testing.T) { const testDir = "../../testdata" diff --git a/cmd/helm/installer/init.go b/cmd/helm/installer/init.go new file mode 100644 index 000000000..7731a4a98 --- /dev/null +++ b/cmd/helm/installer/init.go @@ -0,0 +1,163 @@ +/* +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 installer // import "k8s.io/helm/cmd/helm/installer" + +import ( + "fmt" + "io" + "os" + + "k8s.io/helm/pkg/getter" + helm_env "k8s.io/helm/pkg/helm/environment" + "k8s.io/helm/pkg/helm/helmpath" + "k8s.io/helm/pkg/repo" +) + +const ( + stableRepository = "stable" + + // LocalRepository is the standard name of the local repository + LocalRepository = "local" + + // LocalRepositoryIndexFile is the standard name of the local repository index file + LocalRepositoryIndexFile = "index.yaml" +) + +// Initialize initializes local config +// +// Returns an error if the command failed. +func Initialize(home helmpath.Home, out io.Writer, skipRefresh bool, settings helm_env.EnvSettings, stableRepositoryURL, localRepositoryURL string) error { + if err := ensureDirectories(home, out); err != nil { + return err + } + if err := ensureDefaultRepos(home, out, skipRefresh, settings, stableRepositoryURL, localRepositoryURL); err != nil { + return err + } + + return ensureRepoFileFormat(home.RepositoryFile(), out) +} + +// ensureDirectories checks to see if $HELM_HOME exists. +// +// If $HELM_HOME does not exist, this function will create it. +func ensureDirectories(home helmpath.Home, out io.Writer) error { + configDirectories := []string{ + home.String(), + home.Repository(), + home.Cache(), + home.LocalRepository(), + home.Plugins(), + home.Starters(), + home.Archive(), + } + for _, p := range configDirectories { + if fi, err := os.Stat(p); err != nil { + fmt.Fprintf(out, "Creating %s \n", p) + if err := os.MkdirAll(p, 0755); err != nil { + return fmt.Errorf("Could not create %s: %s", p, err) + } + } else if !fi.IsDir() { + return fmt.Errorf("%s must be a directory", p) + } + } + + return nil +} + +func ensureDefaultRepos(home helmpath.Home, out io.Writer, skipRefresh bool, settings helm_env.EnvSettings, stableRepositoryURL, localRepositoryURL string) error { + repoFile := home.RepositoryFile() + if fi, err := os.Stat(repoFile); err != nil { + fmt.Fprintf(out, "Creating %s \n", repoFile) + f := repo.NewRepoFile() + sr, err := initStableRepo(home.CacheIndex(stableRepository), home, out, skipRefresh, settings, stableRepositoryURL) + if err != nil { + return err + } + lr, err := initLocalRepo(home.LocalRepository(LocalRepositoryIndexFile), home.CacheIndex("local"), home, out, settings, localRepositoryURL) + if err != nil { + return err + } + f.Add(sr) + f.Add(lr) + if err := f.WriteFile(repoFile, 0644); err != nil { + return err + } + } else if fi.IsDir() { + return fmt.Errorf("%s must be a file, not a directory", repoFile) + } + return nil +} + +func initStableRepo(cacheFile string, home helmpath.Home, out io.Writer, skipRefresh bool, settings helm_env.EnvSettings, stableRepositoryURL string) (*repo.Entry, error) { + fmt.Fprintf(out, "Adding %s repo with URL: %s \n", stableRepository, stableRepositoryURL) + c := repo.Entry{ + Name: stableRepository, + URL: stableRepositoryURL, + Cache: cacheFile, + } + r, err := repo.NewChartRepository(&c, getter.All(settings)) + if err != nil { + return nil, err + } + + if skipRefresh { + return &c, nil + } + + // In this case, the cacheFile is always absolute. So passing empty string + // is safe. + if err := r.DownloadIndexFile(""); err != nil { + return nil, fmt.Errorf("Looks like %q is not a valid chart repository or cannot be reached: %s", stableRepositoryURL, err.Error()) + } + + return &c, nil +} + +func initLocalRepo(indexFile, cacheFile string, home helmpath.Home, out io.Writer, settings helm_env.EnvSettings, localRepositoryURL string) (*repo.Entry, error) { + if fi, err := os.Stat(indexFile); err != nil { + fmt.Fprintf(out, "Adding %s repo with URL: %s \n", LocalRepository, localRepositoryURL) + i := repo.NewIndexFile() + if err := i.WriteFile(indexFile, 0644); err != nil { + return nil, err + } + + //TODO: take this out and replace with helm update functionality + if err := createLink(indexFile, cacheFile, home); err != nil { + return nil, err + } + } else if fi.IsDir() { + return nil, fmt.Errorf("%s must be a file, not a directory", indexFile) + } + + return &repo.Entry{ + Name: LocalRepository, + URL: localRepositoryURL, + Cache: cacheFile, + }, nil +} + +func ensureRepoFileFormat(file string, out io.Writer) error { + r, err := repo.LoadRepositoriesFile(file) + if err == repo.ErrRepoOutOfDate { + fmt.Fprintln(out, "Updating repository file format...") + if err := r.WriteFile(file, 0644); err != nil { + return err + } + } + + return nil +} diff --git a/cmd/helm/installer/init_test.go b/cmd/helm/installer/init_test.go new file mode 100644 index 000000000..1d53687e6 --- /dev/null +++ b/cmd/helm/installer/init_test.go @@ -0,0 +1,120 @@ +/* +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 installer // import "k8s.io/helm/cmd/helm/installer" + +import ( + "bytes" + "io/ioutil" + "os" + "testing" + + helm_env "k8s.io/helm/pkg/helm/environment" + "k8s.io/helm/pkg/helm/helmpath" +) + +func TestInitialize(t *testing.T) { + home, err := ioutil.TempDir("", "helm_home") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(home) + + b := bytes.NewBuffer(nil) + hh := helmpath.Home(home) + + settings := helm_env.EnvSettings{ + Home: hh, + } + stableRepositoryURL := "https://kubernetes-charts.storage.googleapis.com" + localRepositoryURL := "http://127.0.0.1:8879/charts" + + if err := Initialize(hh, b, false, settings, stableRepositoryURL, localRepositoryURL); err != nil { + t.Error(err) + } + + expectedDirs := []string{hh.String(), hh.Repository(), hh.Cache(), hh.LocalRepository()} + for _, dir := range expectedDirs { + if fi, err := os.Stat(dir); err != nil { + t.Errorf("%s", err) + } else if !fi.IsDir() { + t.Errorf("%s is not a directory", fi) + } + } + + if fi, err := os.Stat(hh.RepositoryFile()); err != nil { + t.Error(err) + } else if fi.IsDir() { + t.Errorf("%s should not be a directory", fi) + } + + if fi, err := os.Stat(hh.LocalRepository(LocalRepositoryIndexFile)); err != nil { + t.Errorf("%s", err) + } else if fi.IsDir() { + t.Errorf("%s should not be a directory", fi) + } +} + +func TestEnsureHome(t *testing.T) { + home, err := ioutil.TempDir("", "helm_home") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(home) + + b := bytes.NewBuffer(nil) + hh := helmpath.Home(home) + + settings := helm_env.EnvSettings{ + Home: hh, + } + stableRepositoryURL := "https://kubernetes-charts.storage.googleapis.com" + localRepositoryURL := "http://127.0.0.1:8879/charts" + + if err := ensureDirectories(hh, b); err != nil { + t.Error(err) + } + if err := ensureDefaultRepos(hh, b, false, settings, stableRepositoryURL, localRepositoryURL); err != nil { + t.Error(err) + } + if err := ensureDefaultRepos(hh, b, true, settings, stableRepositoryURL, localRepositoryURL); err != nil { + t.Error(err) + } + if err := ensureRepoFileFormat(hh.RepositoryFile(), b); err != nil { + t.Error(err) + } + + expectedDirs := []string{hh.String(), hh.Repository(), hh.Cache(), hh.LocalRepository()} + for _, dir := range expectedDirs { + if fi, err := os.Stat(dir); err != nil { + t.Errorf("%s", err) + } else if !fi.IsDir() { + t.Errorf("%s is not a directory", fi) + } + } + + if fi, err := os.Stat(hh.RepositoryFile()); err != nil { + t.Error(err) + } else if fi.IsDir() { + t.Errorf("%s should not be a directory", fi) + } + + if fi, err := os.Stat(hh.LocalRepository(LocalRepositoryIndexFile)); err != nil { + t.Errorf("%s", err) + } else if fi.IsDir() { + t.Errorf("%s should not be a directory", fi) + } +} diff --git a/cmd/helm/init_unix.go b/cmd/helm/installer/init_unix.go similarity index 92% rename from cmd/helm/init_unix.go rename to cmd/helm/installer/init_unix.go index bf61f1925..d7f15a1c2 100644 --- a/cmd/helm/init_unix.go +++ b/cmd/helm/installer/init_unix.go @@ -16,7 +16,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package main +package installer // import "k8s.io/helm/cmd/helm/installer" import ( "os" diff --git a/cmd/helm/init_windows.go b/cmd/helm/installer/init_windows.go similarity index 92% rename from cmd/helm/init_windows.go rename to cmd/helm/installer/init_windows.go index 447044bba..48c56e288 100644 --- a/cmd/helm/init_windows.go +++ b/cmd/helm/installer/init_windows.go @@ -16,7 +16,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package main +package installer // import "k8s.io/helm/cmd/helm/installer" import ( "os" diff --git a/cmd/helm/installer/uninstall.go b/cmd/helm/installer/uninstall.go index 87fbd4050..b1d78004e 100644 --- a/cmd/helm/installer/uninstall.go +++ b/cmd/helm/installer/uninstall.go @@ -31,13 +31,13 @@ const ( // Uninstall uses Kubernetes client to uninstall Tiller. func Uninstall(client kubernetes.Interface, opts *Options) error { - if err := deleteService(client.Core(), opts.Namespace); err != nil { + if err := deleteService(client.CoreV1(), opts.Namespace); err != nil { return err } if err := deleteDeployment(client, opts.Namespace); err != nil { return err } - return deleteSecret(client.Core(), opts.Namespace) + return deleteSecret(client.CoreV1(), opts.Namespace) } // deleteService deletes the Tiller Service resource diff --git a/cmd/helm/repo_update.go b/cmd/helm/repo_update.go index 1a239b407..2628b7f2f 100644 --- a/cmd/helm/repo_update.go +++ b/cmd/helm/repo_update.go @@ -24,6 +24,7 @@ import ( "github.com/spf13/cobra" + "k8s.io/helm/cmd/helm/installer" "k8s.io/helm/pkg/getter" "k8s.io/helm/pkg/helm/helmpath" "k8s.io/helm/pkg/repo" @@ -99,7 +100,7 @@ func updateCharts(repos []*repo.ChartRepository, out io.Writer, home helmpath.Ho wg.Add(1) go func(re *repo.ChartRepository) { defer wg.Done() - if re.Config.Name == localRepository { + if re.Config.Name == installer.LocalRepository { mu.Lock() fmt.Fprintf(out, "...Skip %s chart repository\n", re.Config.Name) mu.Unlock() @@ -124,6 +125,6 @@ func updateCharts(repos []*repo.ChartRepository, out io.Writer, home helmpath.Ho return errors.New("Update Failed. Check log for details") } - fmt.Fprintln(out, "Update Complete. ⎈ Happy Helming!⎈ ") + fmt.Fprintln(out, "Update Complete. ⎈ Happy Helming! ⎈") return nil } diff --git a/cmd/helm/verify.go b/cmd/helm/verify.go index bbc8347c1..6b8e6895d 100644 --- a/cmd/helm/verify.go +++ b/cmd/helm/verify.go @@ -27,7 +27,7 @@ import ( const verifyDesc = ` Verify that the given chart has a valid provenance file. -Provenance files provide crytographic verification that a chart has not been +Provenance files provide cryptographic verification that a chart has not been tampered with, and was packaged by a trusted provider. This command can be used to verify a local chart. Several other commands provide diff --git a/cmd/tiller/tiller.go b/cmd/tiller/tiller.go index 478ca92f4..a1141b591 100644 --- a/cmd/tiller/tiller.go +++ b/cmd/tiller/tiller.go @@ -36,6 +36,7 @@ import ( "google.golang.org/grpc/health" healthpb "google.golang.org/grpc/health/grpc_health_v1" "google.golang.org/grpc/keepalive" + "k8s.io/klog" // Import to initialize client auth plugins. _ "k8s.io/client-go/plugin/pkg/client/auth" @@ -100,6 +101,7 @@ var ( ) func main() { + klog.InitFlags(nil) // TODO: use spf13/cobra for tiller instead of flags flag.Parse() diff --git a/docs/chart_best_practices/conventions.md b/docs/chart_best_practices/conventions.md index 524928e25..c8bbd7d94 100644 --- a/docs/chart_best_practices/conventions.md +++ b/docs/chart_best_practices/conventions.md @@ -22,7 +22,7 @@ The directory that contains a chart MUST have the same name as the chart. Thus, ## Version Numbers -Wherever possible, Helm uses [SemVer 2](http://semver.org) to represent version numbers. (Note that Docker image tags do not necessarily follow SemVer, and are thus considered an unfortunate exception to the rule.) +Wherever possible, Helm uses [SemVer 2](https://semver.org) to represent version numbers. (Note that Docker image tags do not necessarily follow SemVer, and are thus considered an unfortunate exception to the rule.) When SemVer versions are stored in Kubernetes labels, we conventionally alter the `+` character to an `_` character, as labels do not allow the `+` sign as a value. diff --git a/docs/chart_template_guide/control_structures.md b/docs/chart_template_guide/control_structures.md index e2f9ca89d..d411c2f79 100644 --- a/docs/chart_template_guide/control_structures.md +++ b/docs/chart_template_guide/control_structures.md @@ -329,7 +329,7 @@ data: - "Onions" ``` -Now, in this example we've done something tricky. The `toppings: |-` line is declaring a multi-line string. So our list of toppings is actually not a YAML list. It's a big string. Why would we do this? Because the data in ConfigMaps `data` is composed of key/value pairs, where both the key and the value are simple strings. To understand why this is the case, take a look at the [Kubernetes ConfigMap docs](http://kubernetes.io/docs/user-guide/configmap/). For us, though, this detail doesn't matter much. +Now, in this example we've done something tricky. The `toppings: |-` line is declaring a multi-line string. So our list of toppings is actually not a YAML list. It's a big string. Why would we do this? Because the data in ConfigMaps `data` is composed of key/value pairs, where both the key and the value are simple strings. To understand why this is the case, take a look at the [Kubernetes ConfigMap docs](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/). For us, though, this detail doesn't matter much. > The `|-` marker in YAML takes a multi-line string. This can be a useful technique for embedding big blocks of data inside of your manifests, as exemplified here. diff --git a/docs/chart_template_guide/functions_and_pipelines.md b/docs/chart_template_guide/functions_and_pipelines.md index fe5a3c2b2..1c099887d 100644 --- a/docs/chart_template_guide/functions_and_pipelines.md +++ b/docs/chart_template_guide/functions_and_pipelines.md @@ -150,7 +150,7 @@ Template functions and pipelines are a powerful way to transform information and ## Operators are functions -Operators are implemented as functions that return a boolean value. To use `eq`, `ne`, `lt`, `gt`, `and`, `or`, `not` etcetera place the operator at the front of the statement followed by its parameters just as you would a function. To chain multiple operations together, separate individual functions by surrounding them with paranthesis. +Operators are implemented as functions that return a boolean value. To use `eq`, `ne`, `lt`, `gt`, `and`, `or`, `not` etcetera place the operator at the front of the statement followed by its parameters just as you would a function. To chain multiple operations together, separate individual functions by surrounding them with parentheses. ```yaml {{/* include the body of this if statement when the variable .Values.fooString exists and is set to "foo" */}} diff --git a/docs/chart_template_guide/getting_started.md b/docs/chart_template_guide/getting_started.md index 87ae5fa3c..eb1d966d3 100644 --- a/docs/chart_template_guide/getting_started.md +++ b/docs/chart_template_guide/getting_started.md @@ -51,8 +51,8 @@ already there. - `NOTES.txt`: The "help text" for your chart. This will be displayed to your users when they run `helm install`. -- `deployment.yaml`: A basic manifest for creating a Kubernetes [deployment](http://kubernetes.io/docs/user-guide/deployments/) -- `service.yaml`: A basic manifest for creating a [service endpoint](http://kubernetes.io/docs/user-guide/services/) for your deployment +- `deployment.yaml`: A basic manifest for creating a Kubernetes [deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) +- `service.yaml`: A basic manifest for creating a [service endpoint](https://kubernetes.io/docs/concepts/services-networking/service/) for your deployment - `_helpers.tpl`: A place to put template helpers that you can re-use throughout the chart And what we're going to do is... _remove them all!_ That way we can work through our tutorial from scratch. We'll actually create our own `NOTES.txt` and `_helpers.tpl` as we go. diff --git a/docs/chart_template_guide/helm_ignore_file.md b/docs/chart_template_guide/helm_ignore_file.md index 6793bdfec..5980f439c 100644 --- a/docs/chart_template_guide/helm_ignore_file.md +++ b/docs/chart_template_guide/helm_ignore_file.md @@ -4,7 +4,7 @@ The `.helmignore` file is used to specify files you don't want to include in you If this file exists, the `helm package` command will ignore all the files that match the pattern specified in the `.helmignore` file while packaging your application. -This can help in avoiding unncessary or sensitive files or directories from being added in your helm chart. +This can help in avoiding unnecessary or sensitive files or directories from being added in your helm chart. The `.helmignore` file supports Unix shell glob matching, relative path matching, and negation (prefixed with !). Only one pattern per line is considered. diff --git a/docs/chart_template_guide/wrapping_up.md b/docs/chart_template_guide/wrapping_up.md index ea5dc1183..c7ecad475 100755 --- a/docs/chart_template_guide/wrapping_up.md +++ b/docs/chart_template_guide/wrapping_up.md @@ -5,7 +5,7 @@ This guide is intended to give you, the chart developer, a strong understanding But there are many things this guide has not covered when it comes to the practical day-to-day development of charts. Here are some useful pointers to other documentation that will help you as you create new charts: - The [Helm Charts project](https://github.com/helm/charts) is an indispensable source of charts. That project is also sets the standard for best practices in chart development. -- The Kubernetes [User's Guide](http://kubernetes.io/docs/user-guide/) provides detailed examples of the various resource kinds that you can use, from ConfigMaps and Secrets to DaemonSets and Deployments. +- The Kubernetes [Documentation](https://kubernetes.io/docs/home/) provides detailed examples of the various resource kinds that you can use, from ConfigMaps and Secrets to DaemonSets and Deployments. - The Helm [Charts Guide](../charts.md) explains the workflow of using charts. - The Helm [Chart Hooks Guide](../charts_hooks.md) explains how to create lifecycle hooks. - The Helm [Charts Tips and Tricks](../charts_tips_and_tricks.md) article provides some useful tips for writing charts. diff --git a/docs/chart_template_guide/yaml_techniques.md b/docs/chart_template_guide/yaml_techniques.md index 00b33b674..0a84e4a25 100644 --- a/docs/chart_template_guide/yaml_techniques.md +++ b/docs/chart_template_guide/yaml_techniques.md @@ -7,7 +7,7 @@ to read. ## Scalars and Collections -According to the [YAML spec](http://yaml.org/spec/1.2/spec.html), there are two +According to the [YAML spec](https://yaml.org/spec/1.2/spec.html), there are two types of collections, and many scalar types. The two types of collections are maps and sequences: diff --git a/docs/charts.md b/docs/charts.md index 7bc4f0020..6137898c2 100644 --- a/docs/charts.md +++ b/docs/charts.md @@ -71,7 +71,7 @@ Other fields will be silently ignored. ### Charts and Versioning Every chart must have a version number. A version must follow the -[SemVer 2](http://semver.org/) standard. Unlike Helm Classic, Kubernetes +[SemVer 2](https://semver.org/) standard. Unlike Helm Classic, Kubernetes Helm uses version numbers as release markers. Packages in repositories are identified by name plus version. @@ -492,7 +492,7 @@ create/update all of the above Kubernetes objects in the following order: This is because when Helm installs/upgrades charts, the Kubernetes objects from the charts and all its dependencies are -- aggregrated into a single set; then +- aggregated into a single set; then - sorted by type followed by name; and then - created/updated in that order. @@ -792,7 +792,7 @@ standard references that will help you out. - [Go templates](https://godoc.org/text/template) - [Extra template functions](https://godoc.org/github.com/Masterminds/sprig) -- [The YAML format](http://yaml.org/spec/) +- [The YAML format](https://yaml.org/spec/) ## Using Helm to Manage Charts diff --git a/docs/charts_hooks.md b/docs/charts_hooks.md index fbb302481..6d436402d 100644 --- a/docs/charts_hooks.md +++ b/docs/charts_hooks.md @@ -248,8 +248,8 @@ annotated. When a helm release, that uses a hook, is being updated, it is possible that the hook resource might already exist in the cluster. In such circumstances, by default, helm will fail trying to install the hook resource with an `"... already exists"` error. -A common reason why the hook resource might already exist is that it was not deleted following use on a previous install/upgrade. There are, in fact, good reasons why one might want to keep the hook: for example, to aid manual debugging in case something went wrong. In this case, the recommended way of ensuring subsequent attemps to create the hook do not fail is to define a `"hook-delete-policy"` that can handle this: `"helm.sh/hook-delete-policy": "before-hook-creation"`. This hook annotation causes any existing hook to be removed, before the new hook is installed. +A common reason why the hook resource might already exist is that it was not deleted following use on a previous install/upgrade. There are, in fact, good reasons why one might want to keep the hook: for example, to aid manual debugging in case something went wrong. In this case, the recommended way of ensuring subsequent attempts to create the hook do not fail is to define a `"hook-delete-policy"` that can handle this: `"helm.sh/hook-delete-policy": "before-hook-creation"`. This hook annotation causes any existing hook to be removed, before the new hook is installed. -If it is preferred to actually delete the hook after each use (rather than have to handle it on a subsequent use, as shown above), then this can be achived using a delete policy of `"helm.sh/hook-delete-policy": "hook-succeeded,hook-failed"`. +If it is preferred to actually delete the hook after each use (rather than have to handle it on a subsequent use, as shown above), then this can be achieved using a delete policy of `"helm.sh/hook-delete-policy": "hook-succeeded,hook-failed"`. diff --git a/docs/charts_tips_and_tricks.md b/docs/charts_tips_and_tricks.md index c20ca67fe..813668dbd 100644 --- a/docs/charts_tips_and_tricks.md +++ b/docs/charts_tips_and_tricks.md @@ -235,6 +235,9 @@ orphaned. Helm will no longer manage it in any way. This can lead to problems if using `helm install --replace` on a release that has already been deleted, but has kept resources. +To explicitly opt in to resource deletion, for example when overriding a chart's +default annotations, set the resource policy annotation value to `delete`. + ### Using with Random Secrets For the case where a chart installs a randomized secret that should not be @@ -310,7 +313,7 @@ According to the YAML specification, YAML is a superset of JSON. That means that any valid JSON structure ought to be valid in YAML. This has an advantage: Sometimes template developers may find it easier -to express a datastructure with a JSON-like syntax rather than deal with +to express a data structure with a JSON-like syntax rather than deal with YAML's whitespace sensitivity. As a best practice, templates should follow a YAML-like syntax _unless_ diff --git a/docs/developers.md b/docs/developers.md index 4edc4bea1..70203b2d0 100644 --- a/docs/developers.md +++ b/docs/developers.md @@ -32,7 +32,7 @@ docker-test`. To run Helm and Tiller locally, you can run `bin/helm` or `bin/tiller`. -- Helm and Tiller are known to run on macOS and most Linuxes, including +- Helm and Tiller are known to run on macOS and most Linux distributions, including Alpine. - Tiller must have access to a Kubernetes cluster. It learns about the cluster by examining the Kube config files that `kubectl` uses. @@ -170,7 +170,7 @@ workflow for doing this is as follows: 5. When you are ready for us to review, sign your commit, push your branch to GitHub, and then open a new pull request with us. -For Git commit messages, we follow the [Semantic Commit Messages](http://karma-runner.github.io/0.13/dev/git-commit-msg.html): +For Git commit messages, we follow the [Semantic Commit Messages](https://karma-runner.github.io/0.13/dev/git-commit-msg.html): ``` fix(helm): add --foo flag to 'helm install' @@ -201,7 +201,7 @@ Common scopes: Read more: - The [Deis Guidelines](https://github.com/deis/workflow/blob/master/src/contributing/submitting-a-pull-request.md) were the inspiration for this section. -- Karma Runner [defines](http://karma-runner.github.io/0.13/dev/git-commit-msg.html) the semantic commit message idea. +- Karma Runner [defines](https://karma-runner.github.io/0.13/dev/git-commit-msg.html) the semantic commit message idea. ### Go Conventions diff --git a/docs/glossary.md b/docs/glossary.md index 875807268..02a5c125f 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -37,7 +37,7 @@ are bundled with it. ## Chart Version Charts are versioned according to the [SemVer 2 -spec](http://semver.org). A version number is required on every chart. +spec](https://semver.org). A version number is required on every chart. ## Chart.yaml diff --git a/docs/helm/helm_dependency_build.md b/docs/helm/helm_dependency_build.md index fba70f2ec..1df32d9ab 100644 --- a/docs/helm/helm_dependency_build.md +++ b/docs/helm/helm_dependency_build.md @@ -8,12 +8,11 @@ rebuild the charts/ directory based on the requirements.lock file Build out the charts/ directory from the requirements.lock file. Build is used to reconstruct a chart's dependencies to the state specified in -the lock file. This will not re-negotiate dependencies, as 'helm dependency update' -does. - -If no lock file is found, 'helm dependency build' will mirror the behavior -of 'helm dependency update'. +the lock file. +If no lock file is found, 'helm dependency build' will mirror the behavior of +the 'helm dependency update' command. This means it will update the on-disk +dependencies to mirror the requirements.yaml file and generate a lock file. ``` helm dependency build [flags] CHART diff --git a/docs/helm/helm_verify.md b/docs/helm/helm_verify.md index 30ed43679..acd1c2923 100644 --- a/docs/helm/helm_verify.md +++ b/docs/helm/helm_verify.md @@ -7,7 +7,7 @@ verify that a chart at the given path has been signed and is valid Verify that the given chart has a valid provenance file. -Provenance files provide crytographic verification that a chart has not been +Provenance files provide cryptographic verification that a chart has not been tampered with, and was packaged by a trusted provider. This command can be used to verify a local chart. Several other commands provide diff --git a/docs/history.md b/docs/history.md index 71e63c6b2..1a3d9dbe4 100644 --- a/docs/history.md +++ b/docs/history.md @@ -12,7 +12,7 @@ Differences from Helm Classic: - Helm's chart format has changed for the better: - Dependencies are immutable and stored inside of a chart's `charts/` directory. - - Charts are strongly versioned using [SemVer 2](http://semver.org/spec/v2.0.0.html) + - Charts are strongly versioned using [SemVer 2](https://semver.org/spec/v2.0.0.html) - Charts can be loaded from directories or from chart archive files - Helm supports Go templates without requiring you to run `generate` or `template` commands. diff --git a/docs/images/make-bucket-public.png b/docs/images/make-bucket-public.png index f8a5e17f0..e457e34b2 100644 Binary files a/docs/images/make-bucket-public.png and b/docs/images/make-bucket-public.png differ diff --git a/docs/man/man1/helm_dependency_build.1 b/docs/man/man1/helm_dependency_build.1 index adc225a81..ef92e8959 100644 --- a/docs/man/man1/helm_dependency_build.1 +++ b/docs/man/man1/helm_dependency_build.1 @@ -19,13 +19,12 @@ Build out the charts/ directory from the requirements.lock file. .PP Build is used to reconstruct a chart's dependencies to the state specified in -the lock file. This will not re\-negotiate dependencies, as 'helm dependency update' -does. +the lock file. .PP -If no lock file is found, 'helm dependency build' will mirror the behavior -of 'helm dependency update'. - +If no lock file is found, 'helm dependency build' will mirror the behavior of +the 'helm dependency update' command. This means it will update the on-disk +dependencies to mirror the requirements.yaml file and generate a lock file. .SH OPTIONS .PP diff --git a/docs/man/man1/helm_verify.1 b/docs/man/man1/helm_verify.1 index 5297924ae..341449ad8 100644 --- a/docs/man/man1/helm_verify.1 +++ b/docs/man/man1/helm_verify.1 @@ -18,7 +18,7 @@ helm\-verify \- verify that a chart at the given path has been signed and is val Verify that the given chart has a valid provenance file. .PP -Provenance files provide crytographic verification that a chart has not been +Provenance files provide cryptographic verification that a chart has not been tampered with, and was packaged by a trusted provider. .PP diff --git a/docs/provenance.md b/docs/provenance.md index 163e72842..3f259a391 100644 --- a/docs/provenance.md +++ b/docs/provenance.md @@ -180,7 +180,7 @@ The following pieces of provenance data are added: * The signature (SHA256, just like Docker) of the chart package (the .tgz file) is included, and may be used to verify the integrity of the chart package. * The entire body is signed using the algorithm used by PGP (see - [http://keybase.io] for an emerging way of making crypto signing and + [https://keybase.io] for an emerging way of making crypto signing and verification easy). The combination of this gives users the following assurances: @@ -202,7 +202,7 @@ keywords: - proxy source: - https://github.com/foo/bar -home: http://nginx.com +home: https://nginx.com ... files: @@ -221,7 +221,7 @@ first is the Chart.yaml. The second is the checksums, a map of filenames to SHA-256 digests (value shown is fake/truncated) The signature block is a standard PGP signature, which provides [tamper -resistance](http://www.rossde.com/PGP/pgp_signatures.html). +resistance](https://www.rossde.com/PGP/pgp_signatures.html). ## Chart Repositories diff --git a/docs/quickstart.md b/docs/quickstart.md index ef3cb460e..6e760ced8 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -54,9 +54,11 @@ Once you have Helm ready, you can initialize the local CLI and also install Tiller into your Kubernetes cluster in one step: ```console -$ helm init +$ helm init --history-max 200 ``` +**TIP:** Setting `--history-max` on helm init is recommended as configmaps and other objects in helm history can grow large in number if not purged by max limit. Without a max history set the history is kept indefinitely, leaving a large number of records for helm and tiller to maintain. + This will install Tiller into the Kubernetes cluster you saw with `kubectl config current-context`. diff --git a/docs/rbac.md b/docs/rbac.md index 4b39ecdc6..d53edda49 100644 --- a/docs/rbac.md +++ b/docs/rbac.md @@ -43,7 +43,7 @@ _Note: The cluster-admin role is created by default in a Kubernetes cluster, so $ kubectl create -f rbac-config.yaml serviceaccount "tiller" created clusterrolebinding "tiller" created -$ helm init --service-account tiller +$ helm init --service-account tiller --history-max 200 ``` ### Example: Deploy Tiller in a namespace, restricted to deploying resources only in that namespace diff --git a/docs/related.md b/docs/related.md index ba1b0dfbf..a8e494172 100644 --- a/docs/related.md +++ b/docs/related.md @@ -8,9 +8,9 @@ or [pull request](https://github.com/helm/helm/pulls). ## Article, Blogs, How-Tos, and Extra Documentation - [Awesome Helm](https://github.com/cdwv/awesome-helm) - List of awesome Helm resources -- [CI/CD with Kubernetes, Helm & Wercker ](http://www.slideshare.net/Diacode/cicd-with-kubernetes-helm-wercker-madscalability) +- [CI/CD with Kubernetes, Helm & Wercker ](https://www.slideshare.net/Diacode/cicd-with-kubernetes-helm-wercker-madscalability) - [Creating a Helm Plugin in 3 Steps](http://technosophos.com/2017/03/21/creating-a-helm-plugin.html) -- [Deploying Kubernetes Applications with Helm](http://cloudacademy.com/blog/deploying-kubernetes-applications-with-helm/) +- [Deploying Kubernetes Applications with Helm](https://cloudacademy.com/blog/deploying-kubernetes-applications-with-helm/) - [GitLab, Consumer Driven Contracts, Helm and Kubernetes](https://medium.com/@enxebre/gitlab-consumer-driven-contracts-helm-and-kubernetes-b7235a60a1cb#.xwp1y4tgi) - [Honestbee's Helm Chart Conventions](https://gist.github.com/so0k/f927a4b60003cedd101a0911757c605a) - [Releasing backward-incompatible changes: Kubernetes, Jenkins, Prometheus Operator, Helm and Traefik](https://medium.com/@enxebre/releasing-backward-incompatible-changes-kubernetes-jenkins-plugin-prometheus-operator-helm-self-6263ca61a1b1#.e0c7elxhq) @@ -90,7 +90,7 @@ Tools layered on top of Helm or Tiller. Platforms, distributions, and services that include Helm support. - [Fabric8](https://fabric8.io) - Integrated development platform for Kubernetes -- [Jenkins X](http://jenkins-x.io/) - open source automated CI/CD for Kubernetes which uses Helm for [promoting](http://jenkins-x.io/about/features/#promotion) applications through [environments via GitOps](http://jenkins-x.io/about/features/#environments) +- [Jenkins X](https://jenkins-x.io/) - open source automated CI/CD for Kubernetes which uses Helm for [promoting](https://jenkins-x.io/about/features/#promotion) applications through [environments via GitOps](https://jenkins-x.io/about/features/#environments) - [Kubernetic](https://kubernetic.com/) - Kubernetes Desktop Client - [Qstack](https://qstack.com) diff --git a/docs/release_checklist.md b/docs/release_checklist.md index 4011b6675..bddb50ffb 100644 --- a/docs/release_checklist.md +++ b/docs/release_checklist.md @@ -41,7 +41,7 @@ Just kidding! :trollface: All releases will be of the form vX.Y.Z where X is the major version number, Y is the minor version number and Z is the patch release number. This project -strictly follows [semantic versioning](http://semver.org/) so following this +strictly follows [semantic versioning](https://semver.org/) so following this step is critical. It is important to note that this document assumes that the git remote in your @@ -250,7 +250,25 @@ git tag --sign --annotate "${RELEASE_NAME}" --message "Helm release ${RELEASE_NA git push upstream $RELEASE_NAME ``` -## 7. Write the Release Notes +## 7. PGP Sign the downloads + +While hashes provide a signature that the content of the downloads is what it +was generated, signed packages provide traceability of where the package came +from. + +To do this, run the following `make` commands: + +```shell +make clean +make fetch-dist +make sign +``` + +This will generate ascii armored signature files for each of the files pushed by CI. + +All of the signature files need to be uploaded to the release on GitHub. + +## 8. Write the Release Notes We will auto-generate a changelog based on the commits that occurred during a release cycle, but it is usually more beneficial to the end-user if the release @@ -286,14 +304,14 @@ The community keeps growing, and we'd love to see you there! Download Helm X.Y. The common platform binaries are here: -- [MacOS amd64](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-darwin-amd64.tar.gz) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-darwin-amd64.tar.gz.sha256)) -- [Linux amd64](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-amd64.tar.gz) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-amd64.tar.gz.sha256)) -- [Linux arm](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-arm.tar.gz) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-arm.tar.gz.sha256)) -- [Linux arm64](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-arm64.tar.gz) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-arm64.tar.gz.sha256)) -- [Linux i386](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-386.tar.gz) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-386.tar.gz.sha256)) -- [Linux ppc64le](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-ppc64le.tar.gz) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-ppc64le.tar.gz.sha256)) -- [Linux s390x](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-s390x.tar.gz) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-s390x.tar.gz.sha256)) -- [Windows amd64](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-windows-amd64.zip) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-windows-amd64.zip.sha256)) +- [MacOS amd64](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-darwin-amd64.tar.gz) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-darwin-amd64.tar.gz.sha256) / CHECKSUM_VAL) +- [Linux amd64](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-amd64.tar.gz) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-amd64.tar.gz.sha256) / CHECKSUM_VAL) +- [Linux arm](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-arm.tar.gz) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-arm.tar.gz.sha256) / CHECKSUM_VAL) +- [Linux arm64](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-arm64.tar.gz) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-arm64.tar.gz.sha256) / CHECKSUM_VAL) +- [Linux i386](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-386.tar.gz) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-386.tar.gz.sha256) / CHECKSUM_VAL) +- [Linux ppc64le](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-ppc64le.tar.gz) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-ppc64le.tar.gz.sha256) / CHECKSUM_VAL) +- [Linux s390x](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-s390x.tar.gz) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-s390x.tar.gz.sha256) / CHECKSUM_VAL) +- [Windows amd64](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-windows-amd64.zip) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-windows-amd64.zip.sha256) / CHECKSUM_VAL) Once you have the client installed, upgrade Tiller with `helm init --upgrade`. @@ -308,7 +326,7 @@ The [Quickstart Guide](https://docs.helm.sh/using_helm/#quickstart-guide) will g ### Features - ref(*): kubernetes v1.11 support efadbd88035654b2951f3958167afed014c46bc6 (Adam Reese) -- feat(helm): add $HELM_KEY_PASSPHRASE environment variable for signing helm charts (#4778) 1e26b5300b5166fabb90002535aacd2f9cc7d787 +- feat(helm): add $HELM_KEY_PASSPHRASE environment variable for signing helm charts (#4778) 1e26b5300b5166fabb90002535aacd2f9cc7d787 ### Bug fixes - fix circle not building tags f4f932fabd197f7e6d608c8672b33a483b4b76fa (Matthew Fisher) @@ -332,10 +350,11 @@ git log --no-merges --pretty=format:'- %s %H (%aN)' $PREVIOUS_RELEASE..$RELEASE_ After generating the changelog, you will need to categorize the changes as shown in the example above. -Once finished, go into GitHub and edit the release notes for the tagged release -with the notes written here. +Once finished, go into GitHub and edit the release notes for the tagged release with the notes written here. + +Remember to attach the ascii armored signatures generated in the previous step to the release notes. -## 8. Evangelize +## 9. Evangelize Congratulations! You're done. Go grab yourself a $DRINK_OF_CHOICE. You've earned it. diff --git a/docs/tiller_ssl.md b/docs/tiller_ssl.md index 41e704653..3d64635ae 100644 --- a/docs/tiller_ssl.md +++ b/docs/tiller_ssl.md @@ -288,7 +288,7 @@ not available for public resolution. By default, the Helm client connects to Tiller via tunnel (i.e. kube proxy) at 127.0.0.1. During the TLS handshake, a target, usually provided as a hostname (e.g. example.com), is checked against the subject and subject alternative -names of the certificate (i.e. hostname verficiation). However, because of the tunnel, the target is an IP address. +names of the certificate (i.e. hostname verification). However, because of the tunnel, the target is an IP address. Therefore, to validate the certificate, the IP address 127.0.0.1 must be listed as an IP subject alternative name (IP SAN) in the Tiller certificate. diff --git a/docs/using_helm.md b/docs/using_helm.md index db723d993..faf3cc20f 100755 --- a/docs/using_helm.md +++ b/docs/using_helm.md @@ -17,9 +17,9 @@ cluster. Think of it like the Kubernetes equivalent of a Homebrew formula, an Apt dpkg, or a Yum RPM file. A *Repository* is the place where charts can be collected and shared. -It's like Perl's [CPAN archive](http://www.cpan.org) or the -[Fedora Package Database](https://admin.fedoraproject.org/pkgdb/), but for -Kubernetes packages. +It's like Perl's [CPAN archive](https://www.cpan.org) or the +[Fedora Package Database](https://apps.fedoraproject.org/packages/s/pkgdb), but +for Kubernetes packages. A *Release* is an instance of a chart running in a Kubernetes cluster. One chart can often be installed many times into the same cluster. And @@ -190,7 +190,7 @@ imageTag: 10.1.14-r3 ## Specify a imagePullPolicy ## Default to 'Always' if imageTag is 'latest', else set to 'IfNotPresent' -## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images +## ref: https://kubernetes.io/docs/user-guide/images/#pre-pulling-images ## # imagePullPolicy: diff --git a/glide.lock b/glide.lock index 105dada1f..eedbd9381 100644 --- a/glide.lock +++ b/glide.lock @@ -1,13 +1,11 @@ -hash: 2af9a5c4f891a0f44109a929a494b5aeaaffa3a87cd1f3881f25f79845703d5b -updated: 2018-12-14T21:39:31.112097Z +hash: 9a8f0b6c906f605bb879fbcdf0c122096f7698fe6a975ec4e6648f2ee85fce3e +updated: 2019-03-26T10:33:38.977361532-07:00 imports: - name: cloud.google.com/go version: 3b1ae45394a234c385be014e9a488f2bb6eef821 subpackages: - compute/metadata - internal -- name: github.com/aokoli/goutils - version: 9c37978a95bd5c709a15883b6242714ea6709e64 - name: github.com/asaskevich/govalidator version: 7664702784775e51966f0885f5cd27435916517b - name: github.com/Azure/go-ansiterm @@ -86,14 +84,18 @@ imports: version: 449fdfce4d962303d702fec724ef0ad181c92528 subpackages: - spdy +- name: github.com/emicklei/go-restful + version: ff4f55a206334ef123e4f79bbf348980da81ca46 + subpackages: + - log - name: github.com/evanphx/json-patch - version: 36442dbdb585210f8d5a1b45e67aa323c197d5c4 + version: 5858425f75500d40c52783dce87d085a483ce135 - name: github.com/exponent-io/jsonpath version: d6023ce2651d8eafb5c75bb0c7167536102ec9f5 - name: github.com/fatih/camelcase version: f6a740d52f961c60348ebb109adde9f4635d7540 - name: github.com/ghodss/yaml - version: 73d445a93680fa1a78ae23a5839bad48f32ba1ee + version: c7ce16629ff4cd059ed96ed06419dd3856fd3577 - name: github.com/go-openapi/jsonpointer version: ef5f0afec364d3b9396b7b77b43dbe26bf1f8004 - name: github.com/go-openapi/jsonreference @@ -122,7 +124,7 @@ imports: subpackages: - lru - name: github.com/golang/protobuf - version: 1643683e1b54a9e88ad26d98f81400c8c9d9f4f9 + version: aa810b61a9c79d51363740d207bb46cf8e620ed5 subpackages: - proto - ptypes @@ -132,7 +134,7 @@ imports: - name: github.com/google/btree version: 7d79101e329e5a3adf994758c578dab82b90c017 - name: github.com/google/gofuzz - version: 44d81051d367757e1c7c6a5a86423ece9afcf63c + version: 24818f796faf91cd76ec7bddd72458fbced7a6c1 - name: github.com/google/uuid version: 064e2069ce9c359c118179501254f67d7d37ba24 - name: github.com/googleapis/gnostic @@ -142,7 +144,7 @@ imports: - compiler - extensions - name: github.com/gophercloud/gophercloud - version: 781450b3c4fcb4f5182bcc5133adb4b2e4a09d1d + version: c818fa66e4c88b30db28038fe3f18f2f4a0db9a8 subpackages: - openstack - openstack/identity/v2/tenants @@ -162,17 +164,19 @@ imports: - name: github.com/grpc-ecosystem/go-grpc-prometheus version: 0c1b191dbfe51efdabe3c14b9f6f3b96429e0722 - name: github.com/hashicorp/golang-lru - version: a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4 + version: 20f1fb78b0740ba8c3cb143a61e86ba5c8669768 subpackages: - simplelru - name: github.com/huandu/xstrings - version: 3959339b333561bf62a38b424fd41517c2c90f40 + version: f02667b379e2fb5916c3cda2cf31e0eb885d79f8 - name: github.com/imdario/mergo version: 9316a62528ac99aaecb4e47eadd6dc8aa6533d58 - name: github.com/inconshreveable/mousetrap version: 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 - name: github.com/json-iterator/go version: ab8a2e0c74be9d3be70b3184d9acc634935ded82 +- name: github.com/liggitt/tabwriter + version: 89fcab3d43de07060e4fd4c1547430ed57e87f24 - name: github.com/mailru/easyjson version: 2f5df55504ebc322e4d52d34df6a1f5b503bf26d subpackages: @@ -181,10 +185,12 @@ imports: - jwriter - name: github.com/MakeNowJust/heredoc version: bb23615498cded5e105af4ce27de75b089cbe851 +- name: github.com/Masterminds/goutils + version: 41ac8693c5c10a92ea1ff5ac3a7f95646f6123b0 - name: github.com/Masterminds/semver version: 517734cc7d6470c0d07130e40fd40bdeb9bcd3fd - name: github.com/Masterminds/sprig - version: 15f9564e7e9cf0da02a48e0d25f12a7b83559aa6 + version: 9f8fceff796fb9f4e992cd2bece016be0121ab74 - name: github.com/Masterminds/vcs version: 3084677c2c188840777bff30054f2b553729d329 - name: github.com/mattn/go-runewidth @@ -215,7 +221,7 @@ imports: subpackages: - go - name: github.com/prometheus/common - version: 13ba4ddd0caa9c28ca7b7bffe1dfa9ed8d5ef207 + version: cfeb6f9992ffa54aaa4f2170ade4067ee478b250 subpackages: - expfmt - internal/bitbucket.org/ww/goautoneg @@ -259,15 +265,15 @@ imports: - scrypt - ssh/terminal - name: golang.org/x/net - version: 0ed95abb35c445290478a5348a7b38bb154135fd + version: 65e2d4e15006aab9813ff8769e768bbf4bb667a0 subpackages: - context - context/ctxhttp + - http/httpguts - http2 - http2/hpack - idna - internal/timeseries - - lex/httplex - trace - name: golang.org/x/oauth2 version: a6bd8cefa1811bd24b86f8902872e4e8225f74c4 @@ -281,7 +287,7 @@ imports: subpackages: - semaphore - name: golang.org/x/sys - version: 95c6576299259db960f6c5b9b69ea52422860fce + version: b90733256f2e882e81d52f9126de08df5615afd9 subpackages: - unix - windows @@ -325,26 +331,40 @@ imports: subpackages: - googleapis/rpc/status - name: google.golang.org/grpc - version: 5ffe3083946d5603a0578721101dc8165b1d5b5f + version: a02b0774206b209466313a0b525d2c738fe407eb subpackages: - balancer + - balancer/base + - balancer/roundrobin + - binarylog/grpc_binarylog_v1 - codes - connectivity - credentials - - grpclb/grpc_lb_v1/messages + - credentials/internal + - encoding + - encoding/proto - grpclog - health - health/grpc_health_v1 - internal + - internal/backoff + - internal/binarylog + - internal/channelz + - internal/envconfig + - internal/grpcrand + - internal/grpcsync + - internal/syscall + - internal/transport - keepalive - metadata - naming - peer - resolver + - resolver/dns + - resolver/passthrough - stats - status - tap - - transport - name: gopkg.in/inf.v0 version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4 - name: gopkg.in/square/go-jose.v2 @@ -354,12 +374,11 @@ imports: - json - jwt - name: gopkg.in/yaml.v2 - version: 670d4cfef0544295bc27a114dbac37980d83185a + version: 5420a8b6744d3b0345ab293f6fcba19c978f1183 - name: k8s.io/api - version: 05914d821849570fba9eacfb29466f2d8d3cd229 + version: 40a48860b5abbba9aa891b02b32da429b08d96a0 subpackages: - admission/v1beta1 - - admissionregistration/v1alpha1 - admissionregistration/v1beta1 - apps/v1 - apps/v1beta1 @@ -376,16 +395,21 @@ imports: - batch/v1beta1 - batch/v2alpha1 - certificates/v1beta1 + - coordination/v1 - coordination/v1beta1 - core/v1 - events/v1beta1 - extensions/v1beta1 - imagepolicy/v1alpha1 - networking/v1 + - networking/v1beta1 + - node/v1alpha1 + - node/v1beta1 - policy/v1beta1 - rbac/v1 - rbac/v1alpha1 - rbac/v1beta1 + - scheduling/v1 - scheduling/v1alpha1 - scheduling/v1beta1 - settings/v1alpha1 @@ -393,11 +417,11 @@ imports: - storage/v1alpha1 - storage/v1beta1 - name: k8s.io/apiextensions-apiserver - version: 0fe22c71c47604641d9aa352c785b7912c200562 + version: 53c4693659ed354d76121458fb819202dd1635fa subpackages: - pkg/features - name: k8s.io/apimachinery - version: 2b1284ed4c93a43499e781493253e2ac5959c4fd + version: d7deff9243b165ee192f5551710ea4285dcfd615 subpackages: - pkg/api/equality - pkg/api/errors @@ -453,7 +477,7 @@ imports: - third_party/forked/golang/netutil - third_party/forked/golang/reflect - name: k8s.io/apiserver - version: 3ccfe8365421eb08e334b195786a2973460741d8 + version: 8b27c41bdbb11ff103caa673315e097bf0289171 subpackages: - pkg/authentication/authenticator - pkg/authentication/serviceaccount @@ -461,23 +485,31 @@ imports: - pkg/features - pkg/util/feature - name: k8s.io/cli-runtime - version: 835b10687cb6556f6b113099ef925146a56d5981 + version: 2899ed30580fdbc8286718edb4382b529463099d subpackages: - pkg/genericclioptions - - pkg/genericclioptions/printers - - pkg/genericclioptions/resource + - pkg/kustomize + - pkg/kustomize/k8sdeps + - pkg/kustomize/k8sdeps/configmapandsecret + - pkg/kustomize/k8sdeps/kunstruct + - pkg/kustomize/k8sdeps/kv + - pkg/kustomize/k8sdeps/transformer + - pkg/kustomize/k8sdeps/transformer/hash + - pkg/kustomize/k8sdeps/transformer/patch + - pkg/kustomize/k8sdeps/validator + - pkg/printers + - pkg/resource - name: k8s.io/client-go - version: 8d9ed539ba3134352c586810e749e58df4e94e4f + version: 6ee68ca5fd8355d024d02f9db0b3b667e8357a0f subpackages: - discovery + - discovery/cached/disk - discovery/fake - dynamic - dynamic/fake - kubernetes - kubernetes/fake - kubernetes/scheme - - kubernetes/typed/admissionregistration/v1alpha1 - - kubernetes/typed/admissionregistration/v1alpha1/fake - kubernetes/typed/admissionregistration/v1beta1 - kubernetes/typed/admissionregistration/v1beta1/fake - kubernetes/typed/apps/v1 @@ -510,6 +542,8 @@ imports: - kubernetes/typed/batch/v2alpha1/fake - kubernetes/typed/certificates/v1beta1 - kubernetes/typed/certificates/v1beta1/fake + - kubernetes/typed/coordination/v1 + - kubernetes/typed/coordination/v1/fake - kubernetes/typed/coordination/v1beta1 - kubernetes/typed/coordination/v1beta1/fake - kubernetes/typed/core/v1 @@ -520,6 +554,12 @@ imports: - kubernetes/typed/extensions/v1beta1/fake - kubernetes/typed/networking/v1 - kubernetes/typed/networking/v1/fake + - kubernetes/typed/networking/v1beta1 + - kubernetes/typed/networking/v1beta1/fake + - kubernetes/typed/node/v1alpha1 + - kubernetes/typed/node/v1alpha1/fake + - kubernetes/typed/node/v1beta1 + - kubernetes/typed/node/v1beta1/fake - kubernetes/typed/policy/v1beta1 - kubernetes/typed/policy/v1beta1/fake - kubernetes/typed/rbac/v1 @@ -528,6 +568,8 @@ imports: - kubernetes/typed/rbac/v1alpha1/fake - kubernetes/typed/rbac/v1beta1 - kubernetes/typed/rbac/v1beta1/fake + - kubernetes/typed/scheduling/v1 + - kubernetes/typed/scheduling/v1/fake - kubernetes/typed/scheduling/v1alpha1 - kubernetes/typed/scheduling/v1alpha1/fake - kubernetes/typed/scheduling/v1beta1 @@ -574,30 +616,35 @@ imports: - tools/pager - tools/portforward - tools/record + - tools/record/util - tools/reference - tools/remotecommand - tools/watch - transport - transport/spdy - - util/buffer - util/cert - util/connrotation - util/exec - util/flowcontrol - util/homedir - - util/integer - util/jsonpath + - util/keyutil - util/retry +- name: k8s.io/cloud-provider + version: 9c9d72d1bf90eb62005f5112f3eea019b272c44b + subpackages: + - features - name: k8s.io/klog - version: 8139d8cb77af419532b33dfa7dd09fbc5f1d344f + version: 8e90cee79f823779174776412c13478955131846 - name: k8s.io/kube-openapi - version: c59034cc13d587f5ef4e85ca0ade0c1866ae8e1d + version: b3a7cee44a305be0a69e1b9ac03018307287e1b0 subpackages: + - pkg/common - pkg/util/proto - pkg/util/proto/testing - pkg/util/proto/validation - name: k8s.io/kubernetes - version: f2c8f1cadf1808ec28476682e49a3cce2b09efbf + version: b805719a99126e54bcbc0a3d9ee8a45cd7e85632 subpackages: - pkg/api/legacyscheme - pkg/api/service @@ -630,6 +677,7 @@ imports: - pkg/apis/certificates/v1beta1 - pkg/apis/coordination - pkg/apis/coordination/install + - pkg/apis/coordination/v1 - pkg/apis/coordination/v1beta1 - pkg/apis/core - pkg/apis/core/helper @@ -645,6 +693,7 @@ imports: - pkg/apis/extensions/install - pkg/apis/extensions/v1beta1 - pkg/apis/networking + - pkg/apis/node - pkg/apis/policy - pkg/apis/policy/install - pkg/apis/policy/v1beta1 @@ -655,6 +704,7 @@ imports: - pkg/apis/rbac/v1beta1 - pkg/apis/scheduling - pkg/apis/scheduling/install + - pkg/apis/scheduling/v1 - pkg/apis/scheduling/v1alpha1 - pkg/apis/scheduling/v1beta1 - pkg/apis/settings @@ -699,30 +749,54 @@ imports: - pkg/kubectl/util/templates - pkg/kubectl/util/term - pkg/kubectl/validation - - pkg/kubelet/apis - pkg/kubelet/types - pkg/master/ports - pkg/printers - pkg/printers/internalversion - - pkg/scheduler/api - pkg/security/apparmor - pkg/serviceaccount - - pkg/util/file - pkg/util/hash - pkg/util/interrupt - pkg/util/labels - - pkg/util/net/sets - pkg/util/node - pkg/util/parsers - pkg/util/taints - pkg/version - name: k8s.io/utils - version: 66066c83e385e385ccc3c964b44fd7dcd413d0ed + version: c2654d5206da6b7b6ace12841e8f359bb89b443c subpackages: - - clock + - buffer - exec - - exec/testing + - integer + - net + - path - pointer + - trace +- name: sigs.k8s.io/kustomize + version: a6f65144121d1955266b0cd836ce954c04122dc8 + subpackages: + - pkg/commands/build + - pkg/constants + - pkg/expansion + - pkg/factory + - pkg/fs + - pkg/git + - pkg/gvk + - pkg/ifc + - pkg/ifc/transformer + - pkg/image + - pkg/internal/error + - pkg/loader + - pkg/patch + - pkg/patch/transformer + - pkg/resid + - pkg/resmap + - pkg/resource + - pkg/target + - pkg/transformers + - pkg/transformers/config + - pkg/transformers/config/defaultconfig + - pkg/types - name: sigs.k8s.io/yaml version: fd68e9863619f6ec2fdd8625fe1f02e7c877e480 - name: vbom.ml/util @@ -731,7 +805,7 @@ imports: - sortorder testImports: - name: github.com/pmezard/go-difflib - version: d8ed2627bdf02c080bf22230dbb337003b7aba2d + version: 5d4384ee4fb2527b0a1256a821ebfc92f91efefc subpackages: - difflib - name: github.com/stretchr/testify diff --git a/glide.yaml b/glide.yaml index bf81b22ee..8600ed0ac 100644 --- a/glide.yaml +++ b/glide.yaml @@ -6,6 +6,12 @@ import: - package: golang.org/x/sync subpackages: - semaphore + # This is temporary and can probably be removed the next time gRPC is updated + - package: golang.org/x/sys + version: b90733256f2e882e81d52f9126de08df5615afd9 + subpackages: + - unix + - windows - package: github.com/spf13/cobra version: fe5e611709b0c57fa4a89136deaa8e1d4004d053 - package: github.com/spf13/pflag @@ -15,20 +21,20 @@ import: - package: github.com/imdario/mergo version: v0.3.5 - package: github.com/Masterminds/sprig - version: ^2.16.0 + version: ^2.19.0 - package: github.com/ghodss/yaml - package: github.com/Masterminds/semver version: ~1.3.1 - package: github.com/technosophos/moniker version: ~0.2 - package: github.com/golang/protobuf - version: 1643683e1b54a9e88ad26d98f81400c8c9d9f4f9 + version: 1.2.0 subpackages: - proto - ptypes/any - ptypes/timestamp - package: google.golang.org/grpc - version: 1.7.2 + version: 1.18.0 - package: github.com/gosuri/uitable - package: github.com/asaskevich/govalidator version: ^4.0.0 @@ -45,19 +51,19 @@ import: version: 0.8.0 - package: github.com/grpc-ecosystem/go-grpc-prometheus - package: k8s.io/kubernetes - version: release-1.13 + version: release-1.14 - package: k8s.io/client-go - version: kubernetes-1.13.1 + version: kubernetes-1.14.0 - package: k8s.io/api - version: kubernetes-1.13.1 + version: kubernetes-1.14.0 - package: k8s.io/apimachinery - version: kubernetes-1.13.1 + version: kubernetes-1.14.0 - package: k8s.io/apiserver - version: kubernetes-1.13.1 + version: kubernetes-1.14.0 - package: k8s.io/cli-runtime - version: kubernetes-1.13.1 + version: kubernetes-1.14.0 - package: k8s.io/apiextensions-apiserver - version: kubernetes-1.13.1 + version: kubernetes-1.14.0 - package: github.com/cyphar/filepath-securejoin version: ^0.2.1 diff --git a/pkg/chartutil/capabilities.go b/pkg/chartutil/capabilities.go index d7e660b8a..b4533e417 100644 --- a/pkg/chartutil/capabilities.go +++ b/pkg/chartutil/capabilities.go @@ -40,7 +40,7 @@ var ( // Capabilities describes the capabilities of the Kubernetes cluster that Tiller is attached to. type Capabilities struct { - // List of all supported API versions + // APIVersions list of all supported API versions APIVersions VersionSet // KubeVersion is the Kubernetes version KubeVersion *version.Info diff --git a/pkg/chartutil/requirements.go b/pkg/chartutil/requirements.go index 0f1128305..f21a22005 100644 --- a/pkg/chartutil/requirements.go +++ b/pkg/chartutil/requirements.go @@ -85,7 +85,7 @@ type Requirements struct { // // It represents the state that the dependencies should be in. type RequirementsLock struct { - // Genderated is the date the lock file was last generated. + // Generated is the date the lock file was last generated. Generated time.Time `json:"generated"` // Digest is a hash of the requirements file used to generate it. Digest string `json:"digest"` diff --git a/pkg/chartutil/save.go b/pkg/chartutil/save.go index 400b85e91..0482b1eb9 100644 --- a/pkg/chartutil/save.go +++ b/pkg/chartutil/save.go @@ -63,6 +63,12 @@ func SaveDir(c *chart.Chart, dest string) error { // Save templates for _, f := range c.Templates { n := filepath.Join(outdir, f.Name) + + d := filepath.Dir(n) + if err := os.MkdirAll(d, 0755); err != nil { + return err + } + if err := ioutil.WriteFile(n, f.Data, 0644); err != nil { return err } diff --git a/pkg/chartutil/save_test.go b/pkg/chartutil/save_test.go index 0ec305e78..9952fbbb0 100644 --- a/pkg/chartutil/save_test.go +++ b/pkg/chartutil/save_test.go @@ -48,6 +48,9 @@ func TestSave(t *testing.T) { Files: []*any.Any{ {TypeUrl: "scheherazade/shahryar.txt", Value: []byte("1,001 Nights")}, }, + Templates: []*chart.Template{ + {Name: "templates/scheherazade/shahryar.txt.tmpl", Data: []byte("{{ \"1,001 Nights\" }}")}, + }, } where, err := Save(c, tmp) @@ -75,6 +78,9 @@ func TestSave(t *testing.T) { if len(c2.Files) != 1 || c2.Files[0].TypeUrl != "scheherazade/shahryar.txt" { t.Fatal("Files data did not match") } + if len(c2.Templates) != 1 || c2.Templates[0].Name != "templates/scheherazade/shahryar.txt.tmpl" { + t.Fatal("Templates data did not match") + } } func TestSavePreservesTimestamps(t *testing.T) { @@ -100,6 +106,9 @@ func TestSavePreservesTimestamps(t *testing.T) { Files: []*any.Any{ {TypeUrl: "scheherazade/shahryar.txt", Value: []byte("1,001 Nights")}, }, + Templates: []*chart.Template{ + {Name: "templates/scheherazade/shahryar.txt.tmpl", Data: []byte("{{ \"1,001 Nights\" }}")}, + }, } where, err := Save(c, tmp) @@ -171,6 +180,9 @@ func TestSaveDir(t *testing.T) { Files: []*any.Any{ {TypeUrl: "scheherazade/shahryar.txt", Value: []byte("1,001 Nights")}, }, + Templates: []*chart.Template{ + {Name: "templates/scheherazade/shahryar.txt.tmpl", Data: []byte("{{ \"1,001 Nights\" }}")}, + }, } if err := SaveDir(c, tmp); err != nil { @@ -191,4 +203,7 @@ func TestSaveDir(t *testing.T) { if len(c2.Files) != 1 || c2.Files[0].TypeUrl != "scheherazade/shahryar.txt" { t.Fatal("Files data did not match") } + if len(c2.Templates) != 1 || c2.Templates[0].Name != "templates/scheherazade/shahryar.txt.tmpl" { + t.Fatal("Templates data did not match") + } } diff --git a/pkg/downloader/chart_downloader.go b/pkg/downloader/chart_downloader.go index 5e6287299..563188ec3 100644 --- a/pkg/downloader/chart_downloader.go +++ b/pkg/downloader/chart_downloader.go @@ -65,11 +65,11 @@ type ChartDownloader struct { Keyring string // HelmHome is the $HELM_HOME. HelmHome helmpath.Home - // Getter collection for the operation + // Getters collection for the operation Getters getter.Providers - // Chart repository username + // Username chart repository username Username string - // Chart repository password + // Password chart repository password Password string } @@ -213,7 +213,7 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, ge cv, err := i.Get(chartName, version) if err != nil { - return u, r.Client, fmt.Errorf("chart %q matching %s not found in %s index. (try 'helm repo update'). %s", chartName, version, r.Config.Name, err) + return u, r.Client, fmt.Errorf("chart %q matching version %q not found in %s index. (try 'helm repo update'). %s", chartName, version, r.Config.Name, err) } if len(cv.URLs) == 0 { @@ -243,14 +243,14 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, ge return u, r.Client, nil } -// If HttpGetter is used, this method sets the configured repository credentials on the HttpGetter. +// setCredentials if HttpGetter is used, this method sets the configured repository credentials on the HttpGetter. func (c *ChartDownloader) setCredentials(r *repo.ChartRepository) { if t, ok := r.Client.(*getter.HttpGetter); ok { t.SetCredentials(c.getRepoCredentials(r)) } } -// If this ChartDownloader is not configured to use credentials, and the chart repository sent as an argument is, +// getRepoCredentials if this ChartDownloader is not configured to use credentials, and the chart repository sent as an argument is, // then the repository's configured credentials are returned. // Else, this ChartDownloader's credentials are returned. func (c *ChartDownloader) getRepoCredentials(r *repo.ChartRepository) (username, password string) { diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index aea48bd7e..372940880 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -604,7 +604,7 @@ func writeLock(chartpath string, lock *chartutil.RequirementsLock) error { return ioutil.WriteFile(dest, data, 0644) } -// archive a dep chart from local directory and save it into charts/ +// tarFromLocalDir archive a dep chart from local directory and save it into charts/ func tarFromLocalDir(chartpath string, name string, repo string, version string) (string, error) { destPath := filepath.Join(chartpath, "charts") diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index f3dd869c9..9a155de2e 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -130,7 +130,7 @@ type renderable struct { tpl string // vals are the values to be supplied to the template. vals chartutil.Values - // namespace prefix to the templates of the current chart + // basePath namespace prefix to the templates of the current chart basePath string } diff --git a/pkg/helm/client.go b/pkg/helm/client.go index 0d4d16039..fa867c2d3 100644 --- a/pkg/helm/client.go +++ b/pkg/helm/client.go @@ -334,7 +334,7 @@ func (h *Client) connect(ctx context.Context) (conn *grpc.ClientConn, err error) return conn, nil } -// Executes tiller.ListReleases RPC. +// list executes tiller.ListReleases RPC. func (h *Client) list(ctx context.Context, req *rls.ListReleasesRequest) (*rls.ListReleasesResponse, error) { c, err := h.connect(ctx) if err != nil { @@ -365,7 +365,7 @@ func (h *Client) list(ctx context.Context, req *rls.ListReleasesRequest) (*rls.L return resp, nil } -// Executes tiller.InstallRelease RPC. +// install executes tiller.InstallRelease RPC. func (h *Client) install(ctx context.Context, req *rls.InstallReleaseRequest) (*rls.InstallReleaseResponse, error) { c, err := h.connect(ctx) if err != nil { @@ -377,7 +377,7 @@ func (h *Client) install(ctx context.Context, req *rls.InstallReleaseRequest) (* return rlc.InstallRelease(ctx, req) } -// Executes tiller.UninstallRelease RPC. +// delete executes tiller.UninstallRelease RPC. func (h *Client) delete(ctx context.Context, req *rls.UninstallReleaseRequest) (*rls.UninstallReleaseResponse, error) { c, err := h.connect(ctx) if err != nil { @@ -389,7 +389,7 @@ func (h *Client) delete(ctx context.Context, req *rls.UninstallReleaseRequest) ( return rlc.UninstallRelease(ctx, req) } -// Executes tiller.UpdateRelease RPC. +// update executes tiller.UpdateRelease RPC. func (h *Client) update(ctx context.Context, req *rls.UpdateReleaseRequest) (*rls.UpdateReleaseResponse, error) { c, err := h.connect(ctx) if err != nil { @@ -401,7 +401,7 @@ func (h *Client) update(ctx context.Context, req *rls.UpdateReleaseRequest) (*rl return rlc.UpdateRelease(ctx, req) } -// Executes tiller.RollbackRelease RPC. +// rollback executes tiller.RollbackRelease RPC. func (h *Client) rollback(ctx context.Context, req *rls.RollbackReleaseRequest) (*rls.RollbackReleaseResponse, error) { c, err := h.connect(ctx) if err != nil { @@ -413,7 +413,7 @@ func (h *Client) rollback(ctx context.Context, req *rls.RollbackReleaseRequest) return rlc.RollbackRelease(ctx, req) } -// Executes tiller.GetReleaseStatus RPC. +// status executes tiller.GetReleaseStatus RPC. func (h *Client) status(ctx context.Context, req *rls.GetReleaseStatusRequest) (*rls.GetReleaseStatusResponse, error) { c, err := h.connect(ctx) if err != nil { @@ -425,7 +425,7 @@ func (h *Client) status(ctx context.Context, req *rls.GetReleaseStatusRequest) ( return rlc.GetReleaseStatus(ctx, req) } -// Executes tiller.GetReleaseContent RPC. +// content executes tiller.GetReleaseContent RPC. func (h *Client) content(ctx context.Context, req *rls.GetReleaseContentRequest) (*rls.GetReleaseContentResponse, error) { c, err := h.connect(ctx) if err != nil { @@ -437,7 +437,7 @@ func (h *Client) content(ctx context.Context, req *rls.GetReleaseContentRequest) return rlc.GetReleaseContent(ctx, req) } -// Executes tiller.GetVersion RPC. +// version executes tiller.GetVersion RPC. func (h *Client) version(ctx context.Context, req *rls.GetVersionRequest) (*rls.GetVersionResponse, error) { c, err := h.connect(ctx) if err != nil { @@ -449,7 +449,7 @@ func (h *Client) version(ctx context.Context, req *rls.GetVersionRequest) (*rls. return rlc.GetVersion(ctx, req) } -// Executes tiller.GetHistory RPC. +// history executes tiller.GetHistory RPC. func (h *Client) history(ctx context.Context, req *rls.GetHistoryRequest) (*rls.GetHistoryResponse, error) { c, err := h.connect(ctx) if err != nil { @@ -461,7 +461,7 @@ func (h *Client) history(ctx context.Context, req *rls.GetHistoryRequest) (*rls. return rlc.GetHistory(ctx, req) } -// Executes tiller.TestRelease RPC. +// test executes tiller.TestRelease RPC. func (h *Client) test(ctx context.Context, req *rls.TestReleaseRequest) (<-chan *rls.TestReleaseResponse, <-chan error) { errc := make(chan error, 1) c, err := h.connect(ctx) @@ -499,7 +499,7 @@ func (h *Client) test(ctx context.Context, req *rls.TestReleaseRequest) (<-chan return ch, errc } -// Executes tiller.Ping RPC. +// ping executes tiller.Ping RPC. func (h *Client) ping(ctx context.Context) error { c, err := h.connect(ctx) if err != nil { diff --git a/pkg/kube/client.go b/pkg/kube/client.go index 0fa57bdfc..77613b2ef 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -24,6 +24,7 @@ import ( "fmt" "io" "log" + "sort" "strings" "time" @@ -46,7 +47,7 @@ import ( "k8s.io/apimachinery/pkg/util/strategicpatch" "k8s.io/apimachinery/pkg/watch" "k8s.io/cli-runtime/pkg/genericclioptions" - "k8s.io/cli-runtime/pkg/genericclioptions/resource" + "k8s.io/cli-runtime/pkg/resource" "k8s.io/client-go/kubernetes/scheme" watchtools "k8s.io/client-go/tools/watch" "k8s.io/kubernetes/pkg/api/legacyscheme" @@ -73,7 +74,7 @@ type Client struct { // New creates a new Client. func New(getter genericclioptions.RESTClientGetter) *Client { if getter == nil { - getter = genericclioptions.NewConfigFlags() + getter = genericclioptions.NewConfigFlags(true) } return &Client{ Factory: cmdutil.NewFactory(getter), @@ -155,13 +156,41 @@ func (c *Client) Build(namespace string, reader io.Reader) (Result, error) { return result, scrubValidationError(err) } +// Return the resource info as internal +func resourceInfoToObject(info *resource.Info, c *Client) runtime.Object { + internalObj, err := asInternal(info) + if err != nil { + // If the problem is just that the resource is not registered, don't print any + // error. This is normal for custom resources. + if !runtime.IsNotRegisteredError(err) { + c.Log("Warning: conversion to internal type failed: %v", err) + } + // Add the unstructured object in this situation. It will still get listed, just + // with less information. + return info.Object + } + + return internalObj +} + +func sortByKey(objs map[string](map[string]runtime.Object)) []string { + var keys []string + // Create a simple slice, so we can sort it + for key := range objs { + keys = append(keys, key) + } + // Sort alphabetically by version/kind keys + sort.Strings(keys) + return keys +} + // Get gets Kubernetes resources as pretty-printed string. // // Namespace will set the namespace. func (c *Client) Get(namespace string, reader io.Reader) (string, error) { - // Since we don't know what order the objects come in, let's group them by the types, so + // Since we don't know what order the objects come in, let's group them by the types and then sort them, so // that when we print them, they come out looking good (headers apply to subgroups, etc.). - objs := make(map[string][]runtime.Object) + objs := make(map[string](map[string]runtime.Object)) infos, err := c.BuildUnstructured(namespace, reader) if err != nil { return "", err @@ -182,19 +211,15 @@ func (c *Client) Get(namespace string, reader io.Reader) (string, error) { // versions per cluster, but this certainly won't hurt anything, so let's be safe. gvk := info.ResourceMapping().GroupVersionKind vk := gvk.Version + "/" + gvk.Kind - internalObj, err := asInternal(info) - if err != nil { - // If the problem is just that the resource is not registered, don't print any - // error. This is normal for custom resources. - if !runtime.IsNotRegisteredError(err) { - c.Log("Warning: conversion to internal type failed: %v", err) - } - // Add the unstructured object in this situation. It will still get listed, just - // with less information. - objs[vk] = append(objs[vk], info.Object) - } else { - objs[vk] = append(objs[vk], internalObj) + + // Initialize map. The main map groups resources based on version/kind + // The second level is a simple 'Name' to 'Object', that will help sort + // the individual resource later + if objs[vk] == nil { + objs[vk] = make(map[string]runtime.Object) } + // Map between the resource name to the underlying info object + objs[vk][info.Name] = resourceInfoToObject(info, c) //Get the relation pods objPods, err = c.getSelectRelationPod(info, objPods) @@ -212,8 +237,12 @@ func (c *Client) Get(namespace string, reader io.Reader) (string, error) { for key, podItems := range objPods { for i := range podItems { pod := &core.Pod{} + legacyscheme.Scheme.Convert(&podItems[i], pod, nil) - objs[key+"(related)"] = append(objs[key+"(related)"], pod) + if objs[key+"(related)"] == nil { + objs[key+"(related)"] = make(map[string]runtime.Object) + } + objs[key+"(related)"][pod.ObjectMeta.Name] = runtime.Object(pod) } } @@ -223,14 +252,28 @@ func (c *Client) Get(namespace string, reader io.Reader) (string, error) { // track of tab widths. buf := new(bytes.Buffer) printFlags := get.NewHumanPrintFlags() - for t, ot := range objs { + + // Sort alphabetically by version/kind keys + vkKeys := sortByKey(objs) + // Iterate on sorted version/kind types + for _, t := range vkKeys { if _, err = fmt.Fprintf(buf, "==> %s\n", t); err != nil { return "", err } typePrinter, _ := printFlags.ToPrinter("") - for _, o := range ot { - if err := typePrinter.PrintObj(o, buf); err != nil { - c.Log("failed to print object type %s, object: %q :\n %v", t, o, err) + + var sortedResources []string + for resource := range objs[t] { + sortedResources = append(sortedResources, resource) + } + sort.Strings(sortedResources) + + // Now that each individual resource within the specific version/kind + // is sorted, we print each resource using the k8s printer + vk := objs[t] + for _, resourceName := range sortedResources { + if err := typePrinter.PrintObj(vk[resourceName], buf); err != nil { + c.Log("failed to print object type %s, object: %q :\n %v", t, resourceName, err) return "", err } } @@ -290,9 +333,18 @@ func (c *Client) Update(namespace string, originalReader, targetReader io.Reader } originalInfo := original.Get(info) + + // The resource already exists in the cluster, but it wasn't defined in the previous release. + // In this case, we consider it to be a resource that was previously un-managed by the release and error out, + // asking for the user to intervene. + // + // See https://github.com/helm/helm/issues/1193 for more info. if originalInfo == nil { - kind := info.Mapping.GroupVersionKind.Kind - return fmt.Errorf("no %s with the name %q found", kind, info.Name) + return fmt.Errorf( + "kind %s with the name %q already exists in the cluster and wasn't defined in the previous release. Before upgrading, please either delete the resource from the cluster or remove it from the chart", + info.Mapping.GroupVersionKind.Kind, + info.Name, + ) } if err := updateResource(c, info, originalInfo.Object, force, recreate); err != nil { @@ -320,8 +372,9 @@ func (c *Client) Update(namespace string, originalReader, targetReader io.Reader if err != nil { c.Log("Unable to get annotations on %q, err: %s", info.Name, err) } - if annotations != nil && annotations[ResourcePolicyAnno] == KeepPolicy { - c.Log("Skipping delete of %q due to annotation [%s=%s]", info.Name, ResourcePolicyAnno, KeepPolicy) + if ResourcePolicyIsKeep(annotations) { + policy := annotations[ResourcePolicyAnno] + c.Log("Skipping delete of %q due to annotation [%s=%s]", info.Name, ResourcePolicyAnno, policy) continue } diff --git a/pkg/kube/client_test.go b/pkg/kube/client_test.go index aa21b937c..a41490f9b 100644 --- a/pkg/kube/client_test.go +++ b/pkg/kube/client_test.go @@ -21,14 +21,15 @@ import ( "io" "io/ioutil" "net/http" + "sort" "strings" "testing" - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/cli-runtime/pkg/genericclioptions/resource" + "k8s.io/cli-runtime/pkg/resource" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest/fake" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" @@ -77,6 +78,18 @@ func newPodList(names ...string) v1.PodList { return list } +func newService(name string) v1.Service { + ns := v1.NamespaceDefault + return v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: ns, + SelfLink: "/api/v1/namespaces/default/services/" + name, + }, + Spec: v1.ServiceSpec{}, + } +} + func notFoundBody() *metav1.Status { return &metav1.Status{ Code: http.StatusNotFound, @@ -200,7 +213,7 @@ func TestUpdate(t *testing.T) { // Test resource policy is respected actions = nil - listA.Items[2].ObjectMeta.Annotations = map[string]string{ResourcePolicyAnno: KeepPolicy} + listA.Items[2].ObjectMeta.Annotations = map[string]string{ResourcePolicyAnno: "keep"} if err := c.Update(v1.NamespaceDefault, objBody(&listA), objBody(&listB), false, false, 0, false); err != nil { t.Fatal(err) } @@ -211,6 +224,43 @@ func TestUpdate(t *testing.T) { } } +func TestUpdateNonManagedResourceError(t *testing.T) { + actual := newPodList("starfish") + current := newPodList() + target := newPodList("starfish") + + tf := cmdtesting.NewTestFactory() + defer tf.Cleanup() + + tf.UnstructuredClient = &fake.RESTClient{ + NegotiatedSerializer: unstructuredSerializer, + Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { + p, m := req.URL.Path, req.Method + t.Logf("got request %s %s", p, m) + switch { + case p == "/namespaces/default/pods/starfish" && m == "GET": + return newResponse(200, &actual.Items[0]) + default: + t.Fatalf("unexpected request: %s %s", req.Method, req.URL.Path) + return nil, nil + } + }), + } + + c := &Client{ + Factory: tf, + Log: nopLogger, + } + + if err := c.Update(v1.NamespaceDefault, objBody(¤t), objBody(&target), false, false, 0, false); err != nil { + if err.Error() != "kind Pod with the name \"starfish\" already exists in the cluster and wasn't defined in the previous release. Before upgrading, please either delete the resource from the cluster or remove it from the chart" { + t.Fatal(err) + } + } else { + t.Fatalf("error expected") + } +} + func TestBuild(t *testing.T) { tests := []struct { name string @@ -295,6 +345,95 @@ func TestGet(t *testing.T) { } } +func TestResourceTypeSortOrder(t *testing.T) { + pod := newPod("my-pod") + service := newService("my-service") + c := newTestClient() + defer c.Cleanup() + c.TestFactory.UnstructuredClient = &fake.RESTClient{ + GroupVersion: schema.GroupVersion{Version: "v1"}, + NegotiatedSerializer: unstructuredSerializer, + Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { + p, m := req.URL.Path, req.Method + t.Logf("got request %s %s", p, m) + switch { + case p == "/namespaces/default/pods/my-pod" && m == "GET": + return newResponse(200, &pod) + case p == "/namespaces/default/services/my-service" && m == "GET": + return newResponse(200, &service) + default: + t.Fatalf("unexpected request: %s %s", req.Method, req.URL.Path) + return nil, nil + } + }), + } + + // Test sorting order + data := strings.NewReader(testResourceTypeSortOrder) + o, err := c.Get("default", data) + if err != nil { + t.Errorf("Expected missing results, got %q", err) + } + podIndex := strings.Index(o, "my-pod") + serviceIndex := strings.Index(o, "my-service") + if podIndex == -1 { + t.Errorf("Expected v1/Pod my-pod, got %s", o) + } + if serviceIndex == -1 { + t.Errorf("Expected v1/Service my-service, got %s", o) + } + if !sort.IntsAreSorted([]int{podIndex, serviceIndex}) { + t.Errorf("Expected order: [v1/Pod v1/Service], got %s", o) + } +} + +func TestResourceSortOrder(t *testing.T) { + list := newPodList("albacore", "coral", "beluga") + c := newTestClient() + defer c.Cleanup() + c.TestFactory.UnstructuredClient = &fake.RESTClient{ + GroupVersion: schema.GroupVersion{Version: "v1"}, + NegotiatedSerializer: unstructuredSerializer, + Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { + p, m := req.URL.Path, req.Method + t.Logf("got request %s %s", p, m) + switch { + case p == "/namespaces/default/pods/albacore" && m == "GET": + return newResponse(200, &list.Items[0]) + case p == "/namespaces/default/pods/coral" && m == "GET": + return newResponse(200, &list.Items[1]) + case p == "/namespaces/default/pods/beluga" && m == "GET": + return newResponse(200, &list.Items[2]) + default: + t.Fatalf("unexpected request: %s %s", req.Method, req.URL.Path) + return nil, nil + } + }), + } + + // Test sorting order + data := strings.NewReader(testResourceSortOrder) + o, err := c.Get("default", data) + if err != nil { + t.Errorf("Expected missing results, got %q", err) + } + albacoreIndex := strings.Index(o, "albacore") + belugaIndex := strings.Index(o, "beluga") + coralIndex := strings.Index(o, "coral") + if albacoreIndex == -1 { + t.Errorf("Expected v1/Pod albacore, got %s", o) + } + if belugaIndex == -1 { + t.Errorf("Expected v1/Pod beluga, got %s", o) + } + if coralIndex == -1 { + t.Errorf("Expected v1/Pod coral, got %s", o) + } + if !sort.IntsAreSorted([]int{albacoreIndex, belugaIndex, coralIndex}) { + t.Errorf("Expected order: [albacore beluga coral], got %s", o) + } +} + func TestPerform(t *testing.T) { tests := []struct { name string @@ -376,6 +515,35 @@ func TestReal(t *testing.T) { } } +const testResourceTypeSortOrder = ` +kind: Service +apiVersion: v1 +metadata: + name: my-service +--- +kind: Pod +apiVersion: v1 +metadata: + name: my-pod +` + +const testResourceSortOrder = ` +kind: Pod +apiVersion: v1 +metadata: + name: albacore +--- +kind: Pod +apiVersion: v1 +metadata: + name: coral +--- +kind: Pod +apiVersion: v1 +metadata: + name: beluga +` + const testServiceManifest = ` kind: Service apiVersion: v1 diff --git a/pkg/kube/resource_policy.go b/pkg/kube/resource_policy.go index 4421f126d..648374c6c 100644 --- a/pkg/kube/resource_policy.go +++ b/pkg/kube/resource_policy.go @@ -19,14 +19,29 @@ package kube // ResourcePolicyAnno is the annotation name for a resource policy const ResourcePolicyAnno = "helm.sh/resource-policy" -// KeepPolicy is the resource policy type for keep +// deletePolicy is the resource policy type for delete // -// This resource policy type allows resources to skip being deleted -// during an uninstallRelease action. -const KeepPolicy = "keep" +// This resource policy type allows explicitly opting in to the default +// resource deletion behavior, for example when overriding a chart's +// default annotations. Any other value allows resources to skip being +// deleted during an uninstallRelease action. +const deletePolicy = "delete" // NoUpgradeExistingPolicy is the resource policy type for no-upgrade-existing // // This resource policy type allows resources to skip upgrading // an existing resource if it already exists. const NoUpgradeExistingPolicy = "no-upgrade-existing" + +// ResourcePolicyIsKeep accepts a map of Kubernetes resource annotations and +// returns true if the resource should be kept, otherwise false if it is safe +// for Helm to delete. +func ResourcePolicyIsKeep(annotations map[string]string) bool { + if annotations != nil { + resourcePolicyType, ok := annotations[ResourcePolicyAnno] + if ok && resourcePolicyType != deletePolicy { + return true + } + } + return false +} diff --git a/pkg/kube/resource_policy_test.go b/pkg/kube/resource_policy_test.go new file mode 100644 index 000000000..de6061b48 --- /dev/null +++ b/pkg/kube/resource_policy_test.go @@ -0,0 +1,72 @@ +/* +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 kube + +import "testing" + +func TestResourcePolicyIsKeep(t *testing.T) { + type annotations map[string]string + type testcase struct { + annotations + keep bool + } + cases := []testcase{ + {nil, false}, + { + annotations{ + "foo": "bar", + }, + false, + }, + { + annotations{ + ResourcePolicyAnno: "keep", + }, + true, + }, + { + annotations{ + ResourcePolicyAnno: "KEEP ", + }, + true, + }, + { + annotations{ + ResourcePolicyAnno: "", + }, + true, + }, + { + annotations{ + ResourcePolicyAnno: "delete", + }, + false, + }, + { + annotations{ + ResourcePolicyAnno: "DELETE", + }, + true, + }, + } + + for _, tc := range cases { + if tc.keep != ResourcePolicyIsKeep(tc.annotations) { + t.Errorf("Expected function to return %t for annotations %v", tc.keep, tc.annotations) + } + } +} diff --git a/pkg/kube/result.go b/pkg/kube/result.go index cc222a66f..cf4a4195e 100644 --- a/pkg/kube/result.go +++ b/pkg/kube/result.go @@ -16,7 +16,7 @@ limitations under the License. package kube // import "k8s.io/helm/pkg/kube" -import "k8s.io/cli-runtime/pkg/genericclioptions/resource" +import "k8s.io/cli-runtime/pkg/resource" // Result provides convenience methods for comparing collections of Infos. type Result []*resource.Info diff --git a/pkg/kube/result_test.go b/pkg/kube/result_test.go index c4cf989b8..d4c18ee6a 100644 --- a/pkg/kube/result_test.go +++ b/pkg/kube/result_test.go @@ -21,7 +21,7 @@ import ( "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/cli-runtime/pkg/genericclioptions/resource" + "k8s.io/cli-runtime/pkg/resource" ) func TestResult(t *testing.T) { diff --git a/pkg/proto/hapi/services/tiller.pb.go b/pkg/proto/hapi/services/tiller.pb.go index 8708d0a18..ce76cad12 100644 --- a/pkg/proto/hapi/services/tiller.pb.go +++ b/pkg/proto/hapi/services/tiller.pb.go @@ -467,18 +467,18 @@ func (m *UpdateReleaseRequest) GetForce() bool { return false } -func (m *UpdateReleaseRequest) GetSubNotes() bool { +func (m *UpdateReleaseRequest) GetDescription() string { if m != nil { - return m.SubNotes + return m.Description } - return false + return "" } -func (m *UpdateReleaseRequest) GetDescription() string { +func (m *UpdateReleaseRequest) GetSubNotes() bool { if m != nil { - return m.Description + return m.SubNotes } - return "" + return false } // UpdateReleaseResponse is the response to an update request. @@ -711,18 +711,18 @@ func (m *InstallReleaseRequest) GetDisableCrdHook() bool { return false } -func (m *InstallReleaseRequest) GetSubNotes() bool { +func (m *InstallReleaseRequest) GetDescription() string { if m != nil { - return m.SubNotes + return m.Description } - return false + return "" } -func (m *InstallReleaseRequest) GetDescription() string { +func (m *InstallReleaseRequest) GetSubNotes() bool { if m != nil { - return m.Description + return m.SubNotes } - return "" + return false } // InstallReleaseResponse is the response from a release installation. @@ -752,7 +752,7 @@ type UninstallReleaseRequest struct { Purge bool `protobuf:"varint,3,opt,name=purge" json:"purge,omitempty"` // timeout specifies the max amount of time any kubernetes client command can run. Timeout int64 `protobuf:"varint,4,opt,name=timeout" json:"timeout,omitempty"` - // Description, if set, will set the description for the uninnstalled release + // Description, if set, will set the description for the uninstalled release Description string `protobuf:"bytes,5,opt,name=description" json:"description,omitempty"` } @@ -1018,7 +1018,7 @@ type ReleaseServiceClient interface { GetVersion(ctx context.Context, in *GetVersionRequest, opts ...grpc.CallOption) (*GetVersionResponse, error) // RollbackRelease rolls back a release to a previous version. RollbackRelease(ctx context.Context, in *RollbackReleaseRequest, opts ...grpc.CallOption) (*RollbackReleaseResponse, error) - // ReleaseHistory retrieves a releasse's history. + // ReleaseHistory retrieves a release's history. GetHistory(ctx context.Context, in *GetHistoryRequest, opts ...grpc.CallOption) (*GetHistoryResponse, error) // RunReleaseTest executes the tests defined of a named release RunReleaseTest(ctx context.Context, in *TestReleaseRequest, opts ...grpc.CallOption) (ReleaseService_RunReleaseTestClient, error) @@ -1190,7 +1190,7 @@ type ReleaseServiceServer interface { GetVersion(context.Context, *GetVersionRequest) (*GetVersionResponse, error) // RollbackRelease rolls back a release to a previous version. RollbackRelease(context.Context, *RollbackReleaseRequest) (*RollbackReleaseResponse, error) - // ReleaseHistory retrieves a releasse's history. + // ReleaseHistory retrieves a release's history. GetHistory(context.Context, *GetHistoryRequest) (*GetHistoryResponse, error) // RunReleaseTest executes the tests defined of a named release RunReleaseTest(*TestReleaseRequest, ReleaseService_RunReleaseTestServer) error @@ -1441,86 +1441,87 @@ var _ReleaseService_serviceDesc = grpc.ServiceDesc{ func init() { proto.RegisterFile("hapi/services/tiller.proto", fileDescriptor0) } var fileDescriptor0 = []byte{ - // 1289 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x57, 0xed, 0x72, 0xdb, 0x44, - 0x17, 0x8e, 0x2d, 0x7f, 0x1e, 0xa7, 0x7e, 0xdd, 0x6d, 0x9a, 0xa8, 0x7a, 0x0b, 0x63, 0xc4, 0x40, - 0xdd, 0x42, 0x1d, 0x30, 0xfc, 0x61, 0x86, 0x61, 0x26, 0x75, 0x3d, 0x49, 0x21, 0xa4, 0x33, 0x72, - 0x5b, 0x66, 0x98, 0x61, 0x3c, 0x8a, 0xbd, 0x6e, 0x45, 0x65, 0xc9, 0x68, 0x57, 0xa1, 0xb9, 0x00, - 0x98, 0xe1, 0x3e, 0xb8, 0x10, 0xee, 0x83, 0xeb, 0xe0, 0x3f, 0xb3, 0x5f, 0x8a, 0x56, 0x96, 0x1c, - 0x91, 0x3f, 0xb1, 0x76, 0xcf, 0xd9, 0xf3, 0xf1, 0x3c, 0x7b, 0xce, 0x9e, 0x80, 0xf5, 0xc6, 0x5d, - 0x7b, 0x87, 0x04, 0x47, 0x17, 0xde, 0x1c, 0x93, 0x43, 0xea, 0xf9, 0x3e, 0x8e, 0x86, 0xeb, 0x28, - 0xa4, 0x21, 0xda, 0x63, 0xb2, 0xa1, 0x92, 0x0d, 0x85, 0xcc, 0xda, 0xe7, 0x27, 0xe6, 0x6f, 0xdc, - 0x88, 0x8a, 0xbf, 0x42, 0xdb, 0x3a, 0x48, 0xef, 0x87, 0xc1, 0xd2, 0x7b, 0x2d, 0x05, 0xc2, 0x45, - 0x84, 0x7d, 0xec, 0x12, 0xac, 0x7e, 0xb5, 0x43, 0x4a, 0xe6, 0x05, 0xcb, 0x50, 0x0a, 0xfe, 0xaf, - 0x09, 0x28, 0x26, 0x74, 0x16, 0xc5, 0x81, 0x14, 0xde, 0xd3, 0x84, 0x84, 0xba, 0x34, 0x26, 0x9a, - 0xb3, 0x0b, 0x1c, 0x11, 0x2f, 0x0c, 0xd4, 0xaf, 0x90, 0xd9, 0x7f, 0x55, 0xe1, 0xce, 0xa9, 0x47, - 0xa8, 0x23, 0x0e, 0x12, 0x07, 0xff, 0x12, 0x63, 0x42, 0xd1, 0x1e, 0xd4, 0x7d, 0x6f, 0xe5, 0x51, - 0xb3, 0xd2, 0xaf, 0x0c, 0x0c, 0x47, 0x2c, 0xd0, 0x3e, 0x34, 0xc2, 0xe5, 0x92, 0x60, 0x6a, 0x56, - 0xfb, 0x95, 0x41, 0xdb, 0x91, 0x2b, 0xf4, 0x0d, 0x34, 0x49, 0x18, 0xd1, 0xd9, 0xf9, 0xa5, 0x69, - 0xf4, 0x2b, 0x83, 0xee, 0xe8, 0xa3, 0x61, 0x1e, 0x4e, 0x43, 0xe6, 0x69, 0x1a, 0x46, 0x74, 0xc8, - 0xfe, 0x3c, 0xb9, 0x74, 0x1a, 0x84, 0xff, 0x32, 0xbb, 0x4b, 0xcf, 0xa7, 0x38, 0x32, 0x6b, 0xc2, - 0xae, 0x58, 0xa1, 0x63, 0x00, 0x6e, 0x37, 0x8c, 0x16, 0x38, 0x32, 0xeb, 0xdc, 0xf4, 0xa0, 0x84, - 0xe9, 0xe7, 0x4c, 0xdf, 0x69, 0x13, 0xf5, 0x89, 0xbe, 0x86, 0x5d, 0x01, 0xc9, 0x6c, 0x1e, 0x2e, - 0x30, 0x31, 0x1b, 0x7d, 0x63, 0xd0, 0x1d, 0xdd, 0x13, 0xa6, 0x14, 0xfc, 0x53, 0x01, 0xda, 0x38, - 0x5c, 0x60, 0xa7, 0x23, 0xd4, 0xd9, 0x37, 0x41, 0xf7, 0xa1, 0x1d, 0xb8, 0x2b, 0x4c, 0xd6, 0xee, - 0x1c, 0x9b, 0x4d, 0x1e, 0xe1, 0xd5, 0x86, 0x1d, 0x40, 0x4b, 0x39, 0xb7, 0x9f, 0x40, 0x43, 0xa4, - 0x86, 0x3a, 0xd0, 0x7c, 0x79, 0xf6, 0xdd, 0xd9, 0xf3, 0x1f, 0xce, 0x7a, 0x3b, 0xa8, 0x05, 0xb5, - 0xb3, 0xa3, 0xef, 0x27, 0xbd, 0x0a, 0xba, 0x0d, 0xb7, 0x4e, 0x8f, 0xa6, 0x2f, 0x66, 0xce, 0xe4, - 0x74, 0x72, 0x34, 0x9d, 0x3c, 0xed, 0x55, 0x51, 0x17, 0x60, 0x7c, 0x72, 0xe4, 0xbc, 0x98, 0x71, - 0x15, 0xc3, 0x7e, 0x1f, 0xda, 0x49, 0x0e, 0xa8, 0x09, 0xc6, 0xd1, 0x74, 0x2c, 0x4c, 0x3c, 0x9d, - 0x4c, 0xc7, 0xbd, 0x8a, 0xfd, 0x47, 0x05, 0xf6, 0x74, 0xca, 0xc8, 0x3a, 0x0c, 0x08, 0x66, 0x9c, - 0xcd, 0xc3, 0x38, 0x48, 0x38, 0xe3, 0x0b, 0x84, 0xa0, 0x16, 0xe0, 0x77, 0x8a, 0x31, 0xfe, 0xcd, - 0x34, 0x69, 0x48, 0x5d, 0x9f, 0xb3, 0x65, 0x38, 0x62, 0x81, 0x3e, 0x87, 0x96, 0x84, 0x82, 0x98, - 0xb5, 0xbe, 0x31, 0xe8, 0x8c, 0xee, 0xea, 0x00, 0x49, 0x8f, 0x4e, 0xa2, 0x66, 0x1f, 0xc3, 0xc1, - 0x31, 0x56, 0x91, 0x08, 0xfc, 0xd4, 0x0d, 0x62, 0x7e, 0xdd, 0x15, 0xe6, 0xc1, 0x30, 0xbf, 0xee, - 0x0a, 0x23, 0x13, 0x9a, 0xf2, 0xfa, 0xf1, 0x70, 0xea, 0x8e, 0x5a, 0xda, 0x14, 0xcc, 0x4d, 0x43, - 0x32, 0xaf, 0x3c, 0x4b, 0x1f, 0x43, 0x8d, 0x55, 0x06, 0x37, 0xd3, 0x19, 0x21, 0x3d, 0xce, 0x67, - 0xc1, 0x32, 0x74, 0xb8, 0x5c, 0xa7, 0xce, 0xc8, 0x52, 0x77, 0x92, 0xf6, 0x3a, 0x0e, 0x03, 0x8a, - 0x03, 0x7a, 0xb3, 0xf8, 0x4f, 0xe1, 0x5e, 0x8e, 0x25, 0x99, 0xc0, 0x21, 0x34, 0x65, 0x68, 0xdc, - 0x5a, 0x21, 0xae, 0x4a, 0xcb, 0xfe, 0xcd, 0x80, 0xbd, 0x97, 0xeb, 0x85, 0x4b, 0xb1, 0x12, 0x6d, - 0x09, 0xea, 0x01, 0xd4, 0x79, 0x87, 0x91, 0x58, 0xdc, 0x16, 0xb6, 0x45, 0x1b, 0x1a, 0xb3, 0xbf, - 0x8e, 0x90, 0xa3, 0x47, 0xd0, 0xb8, 0x70, 0xfd, 0x18, 0x13, 0x0e, 0x44, 0x82, 0x9a, 0xd4, 0xe4, - 0xed, 0xc9, 0x91, 0x1a, 0xe8, 0x00, 0x9a, 0x8b, 0xe8, 0x92, 0xf5, 0x17, 0x5e, 0x92, 0x2d, 0xa7, - 0xb1, 0x88, 0x2e, 0x9d, 0x38, 0x40, 0x1f, 0xc2, 0xad, 0x85, 0x47, 0xdc, 0x73, 0x1f, 0xcf, 0xde, - 0x84, 0xe1, 0x5b, 0xc2, 0xab, 0xb2, 0xe5, 0xec, 0xca, 0xcd, 0x13, 0xb6, 0x87, 0x2c, 0x76, 0x93, - 0xe6, 0x11, 0x76, 0x29, 0x36, 0x1b, 0x5c, 0x9e, 0xac, 0x19, 0x86, 0xd4, 0x5b, 0xe1, 0x30, 0xa6, - 0xbc, 0x94, 0x0c, 0x47, 0x2d, 0xd1, 0x07, 0xb0, 0x1b, 0x61, 0x82, 0xe9, 0x4c, 0x46, 0xd9, 0xe2, - 0x27, 0x3b, 0x7c, 0xef, 0x95, 0x08, 0x0b, 0x41, 0xed, 0x57, 0xd7, 0xa3, 0x66, 0x9b, 0x8b, 0xf8, - 0xb7, 0x38, 0x16, 0x13, 0xac, 0x8e, 0x81, 0x3a, 0x16, 0x13, 0x2c, 0x8f, 0xed, 0x41, 0x7d, 0x19, - 0x46, 0x73, 0x6c, 0x76, 0xb8, 0x4c, 0x2c, 0x50, 0x1f, 0x3a, 0x0b, 0x4c, 0xe6, 0x91, 0xb7, 0xa6, - 0x8c, 0xd1, 0x5d, 0x8e, 0x69, 0x7a, 0xcb, 0x3e, 0x81, 0xbb, 0x19, 0x1a, 0x6e, 0xca, 0xe8, 0xef, - 0x55, 0xd8, 0x77, 0x42, 0xdf, 0x3f, 0x77, 0xe7, 0x6f, 0x4b, 0x70, 0x9a, 0x82, 0xbf, 0xba, 0x1d, - 0x7e, 0x23, 0x07, 0xfe, 0xd4, 0x35, 0xad, 0x69, 0xd7, 0x54, 0x23, 0xa6, 0x5e, 0x4c, 0x4c, 0x43, - 0x27, 0x46, 0xa1, 0xde, 0x4c, 0xa1, 0x9e, 0x40, 0xda, 0xda, 0x02, 0x69, 0x7b, 0x13, 0xd2, 0x6f, - 0xe1, 0x60, 0x03, 0x87, 0x9b, 0x82, 0xfa, 0x4f, 0x15, 0xee, 0x3e, 0x0b, 0x08, 0x75, 0x7d, 0x3f, - 0x83, 0x69, 0x52, 0x13, 0x95, 0xd2, 0x35, 0x51, 0xfd, 0x2f, 0x35, 0x61, 0x68, 0xa4, 0x28, 0x06, - 0x6b, 0x29, 0x06, 0x4b, 0xd5, 0x89, 0xd6, 0x9d, 0x1a, 0x99, 0xee, 0x84, 0xde, 0x03, 0x10, 0x17, - 0x9b, 0x1b, 0x17, 0xe0, 0xb7, 0xf9, 0xce, 0x99, 0x6c, 0x46, 0x8a, 0xaf, 0x56, 0x3e, 0x5f, 0xe9, - 0x2a, 0x19, 0x40, 0x4f, 0xc5, 0x33, 0x8f, 0x16, 0x3c, 0x26, 0x59, 0x29, 0x5d, 0xb9, 0x3f, 0x8e, - 0x16, 0x2c, 0xaa, 0x2c, 0x87, 0x9d, 0x4d, 0x0e, 0x9f, 0xc1, 0x7e, 0x16, 0xf6, 0x9b, 0x52, 0xf8, - 0x67, 0x05, 0x0e, 0x5e, 0x06, 0x5e, 0x2e, 0x89, 0x79, 0x85, 0xb1, 0x01, 0x6b, 0x35, 0x07, 0xd6, - 0x3d, 0xa8, 0xaf, 0xe3, 0xe8, 0x35, 0x96, 0x34, 0x89, 0x45, 0x1a, 0xaf, 0x9a, 0x8e, 0x57, 0x26, - 0xe3, 0xfa, 0x66, 0xc6, 0x33, 0x30, 0x37, 0xa3, 0xbc, 0x61, 0xce, 0x2c, 0xaf, 0xe4, 0xed, 0x6a, - 0x8b, 0x77, 0xca, 0xbe, 0x03, 0xb7, 0x8f, 0x31, 0x7d, 0x25, 0xca, 0x54, 0x02, 0x60, 0x4f, 0x00, - 0xa5, 0x37, 0xaf, 0xfc, 0xc9, 0x2d, 0xdd, 0x9f, 0x1a, 0xec, 0x94, 0xbe, 0xd2, 0xb2, 0xbf, 0xe2, - 0xb6, 0x4f, 0x3c, 0x42, 0xc3, 0xe8, 0x72, 0x1b, 0xb8, 0x3d, 0x30, 0x56, 0xee, 0x3b, 0xf9, 0xb4, - 0xb1, 0x4f, 0xfb, 0x98, 0x47, 0x90, 0x1c, 0x95, 0x11, 0xa4, 0x07, 0x85, 0x4a, 0xb9, 0x41, 0xe1, - 0x1d, 0xa0, 0x17, 0x38, 0x99, 0x59, 0xae, 0x79, 0x63, 0x15, 0x4d, 0x55, 0x9d, 0x26, 0x13, 0x9a, - 0x73, 0x1f, 0xbb, 0x41, 0xbc, 0x96, 0xc4, 0xaa, 0x25, 0x6b, 0x6b, 0x6b, 0x37, 0x72, 0x7d, 0x1f, - 0xfb, 0xf2, 0xb9, 0x4a, 0xd6, 0xf6, 0x4f, 0x70, 0x47, 0xf3, 0x2c, 0x73, 0x60, 0xb9, 0x92, 0xd7, - 0xd2, 0x33, 0xfb, 0x44, 0x5f, 0x42, 0x43, 0x0c, 0x7d, 0xdc, 0x6f, 0x77, 0x74, 0x5f, 0xcf, 0x89, - 0x1b, 0x89, 0x03, 0x39, 0x25, 0x3a, 0x52, 0x77, 0xf4, 0x77, 0x0b, 0xba, 0x6a, 0x6c, 0x11, 0x23, - 0x29, 0xf2, 0x60, 0x37, 0x3d, 0x9f, 0xa1, 0x87, 0xc5, 0x13, 0x6b, 0x66, 0xec, 0xb6, 0x1e, 0x95, - 0x51, 0x15, 0x19, 0xd8, 0x3b, 0x9f, 0x55, 0x10, 0x81, 0x5e, 0x76, 0x6c, 0x42, 0x8f, 0xf3, 0x6d, - 0x14, 0xcc, 0x69, 0xd6, 0xb0, 0xac, 0xba, 0x72, 0x8b, 0x2e, 0xf8, 0x7d, 0xd2, 0x67, 0x1d, 0x74, - 0xad, 0x19, 0x7d, 0xbc, 0xb2, 0x0e, 0x4b, 0xeb, 0x27, 0x7e, 0x7f, 0x86, 0x5b, 0xda, 0x6b, 0x8c, - 0x0a, 0xd0, 0xca, 0x9b, 0x9c, 0xac, 0x4f, 0x4a, 0xe9, 0x26, 0xbe, 0x56, 0xd0, 0xd5, 0x5b, 0x1c, - 0x2a, 0x30, 0x90, 0xfb, 0xfe, 0x58, 0x9f, 0x96, 0x53, 0x4e, 0xdc, 0x11, 0xe8, 0x65, 0xfb, 0x4b, - 0x11, 0x8f, 0x05, 0xdd, 0xb2, 0x88, 0xc7, 0xa2, 0xb6, 0x65, 0xef, 0x20, 0x17, 0xe0, 0xaa, 0xbd, - 0xa0, 0x07, 0x85, 0x84, 0xe8, 0x5d, 0xc9, 0x1a, 0x5c, 0xaf, 0x98, 0xb8, 0x58, 0xc3, 0xff, 0x32, - 0xaf, 0x3d, 0x2a, 0x80, 0x26, 0x7f, 0x38, 0xb2, 0x1e, 0x97, 0xd4, 0xce, 0x24, 0x25, 0x3b, 0xd6, - 0x96, 0xa4, 0xf4, 0x76, 0xb8, 0x25, 0xa9, 0x4c, 0xf3, 0xb3, 0x77, 0x90, 0x07, 0x5d, 0x27, 0x0e, - 0xa4, 0x6b, 0xd6, 0x16, 0x50, 0xc1, 0xe9, 0xcd, 0x8e, 0x67, 0x3d, 0x2c, 0xa1, 0x79, 0x55, 0xdf, - 0x4f, 0xe0, 0xc7, 0x96, 0x52, 0x3d, 0x6f, 0xf0, 0xff, 0xd8, 0xbf, 0xf8, 0x37, 0x00, 0x00, 0xff, - 0xff, 0xb6, 0x48, 0x98, 0x76, 0x9f, 0x10, 0x00, 0x00, + // 1308 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x57, 0xed, 0x6e, 0x1b, 0x45, + 0x17, 0x8e, 0xbd, 0xfe, 0x3c, 0x4e, 0xfc, 0xba, 0xd3, 0x34, 0xd9, 0xee, 0x5b, 0x50, 0x58, 0x04, + 0x75, 0x0b, 0x75, 0xc0, 0xf0, 0x07, 0x09, 0x21, 0xa5, 0xae, 0x95, 0x14, 0x82, 0x2b, 0xad, 0xdb, + 0x22, 0x21, 0x21, 0x6b, 0x63, 0x8f, 0xdb, 0xa5, 0xeb, 0x5d, 0xb3, 0x33, 0x1b, 0x9a, 0x1b, 0x40, + 0xe2, 0x27, 0x97, 0x80, 0xc4, 0x85, 0x70, 0x1f, 0xdc, 0x0c, 0x9a, 0xaf, 0xcd, 0xce, 0x7a, 0xd7, + 0x5d, 0xf2, 0x27, 0xde, 0x99, 0x73, 0xe6, 0x7c, 0x3c, 0xcf, 0x9c, 0x33, 0x27, 0x60, 0xbd, 0x76, + 0xd7, 0xde, 0x31, 0xc1, 0xd1, 0xa5, 0x37, 0xc7, 0xe4, 0x98, 0x7a, 0xbe, 0x8f, 0xa3, 0xc1, 0x3a, + 0x0a, 0x69, 0x88, 0xf6, 0x99, 0x6c, 0xa0, 0x64, 0x03, 0x21, 0xb3, 0x0e, 0xf8, 0x89, 0xf9, 0x6b, + 0x37, 0xa2, 0xe2, 0xaf, 0xd0, 0xb6, 0x0e, 0xd3, 0xfb, 0x61, 0xb0, 0xf4, 0x5e, 0x49, 0x81, 0x70, + 0x11, 0x61, 0x1f, 0xbb, 0x04, 0xab, 0x5f, 0xed, 0x90, 0x92, 0x79, 0xc1, 0x32, 0x94, 0x82, 0xff, + 0x6b, 0x02, 0x8a, 0x09, 0x9d, 0x45, 0x71, 0x20, 0x85, 0x77, 0x35, 0x21, 0xa1, 0x2e, 0x8d, 0x89, + 0xe6, 0xec, 0x12, 0x47, 0xc4, 0x0b, 0x03, 0xf5, 0x2b, 0x64, 0xf6, 0xdf, 0x55, 0xb8, 0x7d, 0xee, + 0x11, 0xea, 0x88, 0x83, 0xc4, 0xc1, 0xbf, 0xc4, 0x98, 0x50, 0xb4, 0x0f, 0x75, 0xdf, 0x5b, 0x79, + 0xd4, 0xac, 0x1c, 0x55, 0xfa, 0x86, 0x23, 0x16, 0xe8, 0x00, 0x1a, 0xe1, 0x72, 0x49, 0x30, 0x35, + 0xab, 0x47, 0x95, 0x7e, 0xdb, 0x91, 0x2b, 0xf4, 0x0d, 0x34, 0x49, 0x18, 0xd1, 0xd9, 0xc5, 0x95, + 0x69, 0x1c, 0x55, 0xfa, 0xdd, 0xe1, 0x47, 0x83, 0x3c, 0x9c, 0x06, 0xcc, 0xd3, 0x34, 0x8c, 0xe8, + 0x80, 0xfd, 0x79, 0x7c, 0xe5, 0x34, 0x08, 0xff, 0x65, 0x76, 0x97, 0x9e, 0x4f, 0x71, 0x64, 0xd6, + 0x84, 0x5d, 0xb1, 0x42, 0xa7, 0x00, 0xdc, 0x6e, 0x18, 0x2d, 0x70, 0x64, 0xd6, 0xb9, 0xe9, 0x7e, + 0x09, 0xd3, 0xcf, 0x98, 0xbe, 0xd3, 0x26, 0xea, 0x13, 0x7d, 0x0d, 0xbb, 0x02, 0x92, 0xd9, 0x3c, + 0x5c, 0x60, 0x62, 0x36, 0x8e, 0x8c, 0x7e, 0x77, 0x78, 0x57, 0x98, 0x52, 0xf0, 0x4f, 0x05, 0x68, + 0xa3, 0x70, 0x81, 0x9d, 0x8e, 0x50, 0x67, 0xdf, 0x04, 0xdd, 0x83, 0x76, 0xe0, 0xae, 0x30, 0x59, + 0xbb, 0x73, 0x6c, 0x36, 0x79, 0x84, 0xd7, 0x1b, 0x76, 0x00, 0x2d, 0xe5, 0xdc, 0x7e, 0x0c, 0x0d, + 0x91, 0x1a, 0xea, 0x40, 0xf3, 0xc5, 0xe4, 0xbb, 0xc9, 0xb3, 0x1f, 0x26, 0xbd, 0x1d, 0xd4, 0x82, + 0xda, 0xe4, 0xe4, 0xfb, 0x71, 0xaf, 0x82, 0x6e, 0xc1, 0xde, 0xf9, 0xc9, 0xf4, 0xf9, 0xcc, 0x19, + 0x9f, 0x8f, 0x4f, 0xa6, 0xe3, 0x27, 0xbd, 0x2a, 0xea, 0x02, 0x8c, 0xce, 0x4e, 0x9c, 0xe7, 0x33, + 0xae, 0x62, 0xd8, 0xef, 0x43, 0x3b, 0xc9, 0x01, 0x35, 0xc1, 0x38, 0x99, 0x8e, 0x84, 0x89, 0x27, + 0xe3, 0xe9, 0xa8, 0x57, 0xb1, 0x7f, 0xaf, 0xc0, 0xbe, 0x4e, 0x19, 0x59, 0x87, 0x01, 0xc1, 0x8c, + 0xb3, 0x79, 0x18, 0x07, 0x09, 0x67, 0x7c, 0x81, 0x10, 0xd4, 0x02, 0xfc, 0x56, 0x31, 0xc6, 0xbf, + 0x99, 0x26, 0x0d, 0xa9, 0xeb, 0x73, 0xb6, 0x0c, 0x47, 0x2c, 0xd0, 0xe7, 0xd0, 0x92, 0x50, 0x10, + 0xb3, 0x76, 0x64, 0xf4, 0x3b, 0xc3, 0x3b, 0x3a, 0x40, 0xd2, 0xa3, 0x93, 0xa8, 0xd9, 0xa7, 0x70, + 0x78, 0x8a, 0x55, 0x24, 0x02, 0x3f, 0x75, 0x83, 0x98, 0x5f, 0x77, 0x85, 0x79, 0x30, 0xcc, 0xaf, + 0xbb, 0xc2, 0xc8, 0x84, 0xa6, 0xbc, 0x7e, 0x3c, 0x9c, 0xba, 0xa3, 0x96, 0x36, 0x05, 0x73, 0xd3, + 0x90, 0xcc, 0x2b, 0xcf, 0xd2, 0xc7, 0x50, 0x63, 0x95, 0xc1, 0xcd, 0x74, 0x86, 0x48, 0x8f, 0xf3, + 0x69, 0xb0, 0x0c, 0x1d, 0x2e, 0xd7, 0xa9, 0x33, 0xb2, 0xd4, 0x9d, 0xa5, 0xbd, 0x8e, 0xc2, 0x80, + 0xe2, 0x80, 0xde, 0x2c, 0xfe, 0x73, 0xb8, 0x9b, 0x63, 0x49, 0x26, 0x70, 0x0c, 0x4d, 0x19, 0x1a, + 0xb7, 0x56, 0x88, 0xab, 0xd2, 0xb2, 0xff, 0x34, 0x60, 0xff, 0xc5, 0x7a, 0xe1, 0x52, 0xac, 0x44, + 0x5b, 0x82, 0xba, 0x0f, 0x75, 0xde, 0x61, 0x24, 0x16, 0xb7, 0x84, 0x6d, 0xd1, 0x86, 0x46, 0xec, + 0xaf, 0x23, 0xe4, 0xe8, 0x21, 0x34, 0x2e, 0x5d, 0x3f, 0xc6, 0x84, 0x03, 0x91, 0xa0, 0x26, 0x35, + 0x79, 0x7b, 0x72, 0xa4, 0x06, 0x3a, 0x84, 0xe6, 0x22, 0xba, 0x62, 0xfd, 0x85, 0x97, 0x64, 0xcb, + 0x69, 0x2c, 0xa2, 0x2b, 0x27, 0x0e, 0xd0, 0x87, 0xb0, 0xb7, 0xf0, 0x88, 0x7b, 0xe1, 0xe3, 0xd9, + 0xeb, 0x30, 0x7c, 0x43, 0x78, 0x55, 0xb6, 0x9c, 0x5d, 0xb9, 0x79, 0xc6, 0xf6, 0x90, 0xc5, 0x6e, + 0xd2, 0x3c, 0xc2, 0x2e, 0xc5, 0x66, 0x83, 0xcb, 0x93, 0x35, 0xc3, 0x90, 0x7a, 0x2b, 0x1c, 0xc6, + 0x94, 0x97, 0x92, 0xe1, 0xa8, 0x25, 0xfa, 0x00, 0x76, 0x23, 0x4c, 0x30, 0x9d, 0xc9, 0x28, 0x5b, + 0xfc, 0x64, 0x87, 0xef, 0xbd, 0x14, 0x61, 0x21, 0xa8, 0xfd, 0xea, 0x7a, 0xd4, 0x6c, 0x73, 0x11, + 0xff, 0x16, 0xc7, 0x62, 0x82, 0xd5, 0x31, 0x50, 0xc7, 0x62, 0x82, 0xe5, 0xb1, 0x7d, 0xa8, 0x2f, + 0xc3, 0x68, 0x8e, 0xcd, 0x0e, 0x97, 0x89, 0x05, 0x3a, 0x82, 0xce, 0x02, 0x93, 0x79, 0xe4, 0xad, + 0x29, 0x63, 0x74, 0x97, 0x63, 0x9a, 0xde, 0x62, 0x79, 0x90, 0xf8, 0x62, 0x12, 0x52, 0x4c, 0xcc, + 0x3d, 0x91, 0x87, 0x5a, 0xdb, 0x67, 0x70, 0x27, 0x43, 0xd1, 0x4d, 0xd9, 0xfe, 0xad, 0x0a, 0x07, + 0x4e, 0xe8, 0xfb, 0x17, 0xee, 0xfc, 0x4d, 0x09, 0xbe, 0x53, 0xd4, 0x54, 0xb7, 0x53, 0x63, 0xe4, + 0x50, 0x93, 0xba, 0xc2, 0x35, 0xed, 0x0a, 0x6b, 0xa4, 0xd5, 0x8b, 0x49, 0x6b, 0xe8, 0xa4, 0x29, + 0x46, 0x9a, 0x29, 0x46, 0x12, 0xb8, 0x5b, 0x5b, 0xe0, 0x6e, 0x6f, 0xc0, 0x6d, 0x7f, 0x0b, 0x87, + 0x1b, 0x38, 0xdc, 0x14, 0xd4, 0x3f, 0x0c, 0xb8, 0xf3, 0x34, 0x20, 0xd4, 0xf5, 0xfd, 0x0c, 0xa6, + 0x49, 0xbd, 0x54, 0x4a, 0xd7, 0x4b, 0xf5, 0xbf, 0xd4, 0x8b, 0xa1, 0x91, 0xa2, 0x18, 0xac, 0xa5, + 0x18, 0x2c, 0x55, 0x43, 0x5a, 0xe7, 0x6a, 0x64, 0x3a, 0x17, 0x7a, 0x0f, 0x40, 0x5c, 0x7a, 0x6e, + 0x5c, 0x80, 0xdf, 0xe6, 0x3b, 0x13, 0xd9, 0xa8, 0x14, 0x5f, 0xad, 0x7c, 0xbe, 0xd2, 0x15, 0xd4, + 0x87, 0x9e, 0x8a, 0x67, 0x1e, 0x2d, 0x78, 0x4c, 0xb2, 0x8a, 0xba, 0x72, 0x7f, 0x14, 0x2d, 0x58, + 0x54, 0x59, 0x0e, 0x3b, 0xdb, 0x4b, 0x66, 0x37, 0x53, 0x32, 0x4f, 0xe1, 0x20, 0x4b, 0xc9, 0x4d, + 0xe9, 0xfd, 0xab, 0x02, 0x87, 0x2f, 0x02, 0x2f, 0x97, 0xe0, 0xbc, 0xa2, 0xd9, 0x80, 0xbc, 0x9a, + 0x03, 0xf9, 0x3e, 0xd4, 0xd7, 0x71, 0xf4, 0x0a, 0x4b, 0x0a, 0xc5, 0x22, 0x8d, 0x65, 0x4d, 0xc7, + 0x32, 0x83, 0x46, 0x7d, 0xf3, 0x46, 0xcf, 0xc0, 0xdc, 0x8c, 0xf2, 0x86, 0x39, 0xb3, 0xbc, 0x92, + 0x37, 0xaf, 0x2d, 0xde, 0x37, 0xfb, 0x36, 0xdc, 0x3a, 0xc5, 0xf4, 0xa5, 0x28, 0x61, 0x09, 0x80, + 0x3d, 0x06, 0x94, 0xde, 0xbc, 0xf6, 0x27, 0xb7, 0x74, 0x7f, 0x6a, 0x20, 0x54, 0xfa, 0x4a, 0xcb, + 0xfe, 0x8a, 0xdb, 0x3e, 0xf3, 0x08, 0x0d, 0xa3, 0xab, 0x6d, 0xe0, 0xf6, 0xc0, 0x58, 0xb9, 0x6f, + 0xe5, 0x93, 0xc8, 0x3e, 0xed, 0x53, 0x1e, 0x41, 0x72, 0x54, 0x46, 0x90, 0x1e, 0x30, 0x2a, 0xe5, + 0x06, 0x8c, 0xb7, 0x80, 0x9e, 0xe3, 0x64, 0xd6, 0x79, 0xc7, 0xdb, 0xac, 0x68, 0xaa, 0xea, 0x34, + 0x99, 0xd0, 0x9c, 0xfb, 0xd8, 0x0d, 0xe2, 0xb5, 0x24, 0x56, 0x2d, 0xd9, 0x65, 0x5d, 0xbb, 0x91, + 0xeb, 0xfb, 0xd8, 0x97, 0xcf, 0x5c, 0xb2, 0xb6, 0x7f, 0x82, 0xdb, 0x9a, 0x67, 0x99, 0x03, 0xcb, + 0x95, 0xbc, 0x92, 0x9e, 0xd9, 0x27, 0xfa, 0x12, 0x1a, 0x62, 0x58, 0xe4, 0x7e, 0xbb, 0xc3, 0x7b, + 0x7a, 0x4e, 0xdc, 0x48, 0x1c, 0xc8, 0xe9, 0xd2, 0x91, 0xba, 0xc3, 0x7f, 0x5a, 0xd0, 0x55, 0xe3, + 0x8e, 0x18, 0x65, 0x91, 0x07, 0xbb, 0xe9, 0xb9, 0x0e, 0x3d, 0x28, 0x9e, 0x74, 0x33, 0xe3, 0xba, + 0xf5, 0xb0, 0x8c, 0xaa, 0xc8, 0xc0, 0xde, 0xf9, 0xac, 0x82, 0x08, 0xf4, 0xb2, 0xe3, 0x16, 0x7a, + 0x94, 0x6f, 0xa3, 0x60, 0xbe, 0xb3, 0x06, 0x65, 0xd5, 0x95, 0x5b, 0x74, 0xc9, 0xef, 0x93, 0x3e, + 0x23, 0xa1, 0x77, 0x9a, 0xd1, 0xc7, 0x32, 0xeb, 0xb8, 0xb4, 0x7e, 0xe2, 0xf7, 0x67, 0xd8, 0xd3, + 0x5e, 0x6a, 0x54, 0x80, 0x56, 0xde, 0xc4, 0x65, 0x7d, 0x52, 0x4a, 0x37, 0xf1, 0xb5, 0x82, 0xae, + 0xde, 0xe2, 0x50, 0x81, 0x81, 0xdc, 0xb7, 0xc9, 0xfa, 0xb4, 0x9c, 0x72, 0xe2, 0x8e, 0x40, 0x2f, + 0xdb, 0x5f, 0x8a, 0x78, 0x2c, 0xe8, 0x96, 0x45, 0x3c, 0x16, 0xb5, 0x2d, 0x7b, 0x07, 0xb9, 0x00, + 0xd7, 0xed, 0x05, 0xdd, 0x2f, 0x24, 0x44, 0xef, 0x4a, 0x56, 0xff, 0xdd, 0x8a, 0x89, 0x8b, 0x35, + 0xfc, 0x2f, 0x33, 0x09, 0xa0, 0x02, 0x68, 0xf2, 0x07, 0x27, 0xeb, 0x51, 0x49, 0xed, 0x4c, 0x52, + 0xb2, 0x63, 0x6d, 0x49, 0x4a, 0x6f, 0x87, 0x5b, 0x92, 0xca, 0x34, 0x3f, 0x7b, 0x07, 0x79, 0xd0, + 0x75, 0xe2, 0x40, 0xba, 0x66, 0x6d, 0x01, 0x15, 0x9c, 0xde, 0xec, 0x78, 0xd6, 0x83, 0x12, 0x9a, + 0xd7, 0xf5, 0xfd, 0x18, 0x7e, 0x6c, 0x29, 0xd5, 0x8b, 0x06, 0xff, 0x4f, 0xff, 0x8b, 0x7f, 0x03, + 0x00, 0x00, 0xff, 0xff, 0x30, 0x18, 0x95, 0x9c, 0xd7, 0x10, 0x00, 0x00, } diff --git a/pkg/repo/chartrepo_test.go b/pkg/repo/chartrepo_test.go index a2f1daeb8..ed09b5c6d 100644 --- a/pkg/repo/chartrepo_test.go +++ b/pkg/repo/chartrepo_test.go @@ -175,7 +175,7 @@ func verifyIndex(t *testing.T, actual *IndexFile) { t.Errorf("Expected %q, got %q", e.Version, g.Version) } if len(g.Keywords) != 3 { - t.Error("Expected 3 keyrwords.") + t.Error("Expected 3 keywords.") } if len(g.Maintainers) != 2 { t.Error("Expected 2 maintainers.") diff --git a/pkg/repo/index.go b/pkg/repo/index.go index 9031463f3..ac19528fa 100644 --- a/pkg/repo/index.go +++ b/pkg/repo/index.go @@ -168,6 +168,15 @@ func (i IndexFile) Get(name, version string) (*ChartVersion, error) { } } + // when customer input exact version, check whether have exact match one first + if len(version) != 0 { + for _, ver := range vs { + if version == ver.Version { + return ver, nil + } + } + } + for _, ver := range vs { test, err := semver.NewVersion(ver.Version) if err != nil { diff --git a/pkg/repo/index_test.go b/pkg/repo/index_test.go index 7c9239b7a..7e9998a4d 100644 --- a/pkg/repo/index_test.go +++ b/pkg/repo/index_test.go @@ -20,6 +20,7 @@ import ( "io/ioutil" "os" "path/filepath" + "strings" "testing" "k8s.io/helm/pkg/getter" @@ -39,14 +40,17 @@ func TestIndexFile(t *testing.T) { i.Add(&chart.Metadata{Name: "cutter", Version: "0.1.1"}, "cutter-0.1.1.tgz", "http://example.com/charts", "sha256:1234567890abc") i.Add(&chart.Metadata{Name: "cutter", Version: "0.1.0"}, "cutter-0.1.0.tgz", "http://example.com/charts", "sha256:1234567890abc") i.Add(&chart.Metadata{Name: "cutter", Version: "0.2.0"}, "cutter-0.2.0.tgz", "http://example.com/charts", "sha256:1234567890abc") + i.Add(&chart.Metadata{Name: "setter", Version: "0.1.9+alpha"}, "setter-0.1.9+alpha.tgz", "http://example.com/charts", "sha256:1234567890abc") + i.Add(&chart.Metadata{Name: "setter", Version: "0.1.9+beta"}, "setter-0.1.9+beta.tgz", "http://example.com/charts", "sha256:1234567890abc") + i.SortEntries() if i.APIVersion != APIVersionV1 { t.Error("Expected API version v1") } - if len(i.Entries) != 2 { - t.Errorf("Expected 2 charts. Got %d", len(i.Entries)) + if len(i.Entries) != 3 { + t.Errorf("Expected 3 charts. Got %d", len(i.Entries)) } if i.Entries["clipper"][0].Name != "clipper" { @@ -54,13 +58,23 @@ func TestIndexFile(t *testing.T) { } if len(i.Entries["cutter"]) != 3 { - t.Error("Expected two cutters.") + t.Error("Expected three cutters.") } // Test that the sort worked. 0.2 should be at the first index for Cutter. if v := i.Entries["cutter"][0].Version; v != "0.2.0" { t.Errorf("Unexpected first version: %s", v) } + + cv, err := i.Get("setter", "0.1.9") + if err == nil && strings.Index(cv.Metadata.Version, "0.1.9") < 0 { + t.Errorf("Unexpected version: %s", cv.Metadata.Version) + } + + cv, err = i.Get("setter", "0.1.9+alpha") + if err != nil || cv.Metadata.Version != "0.1.9+alpha" { + t.Errorf("Expected version: 0.1.9+alpha") + } } func TestLoadIndex(t *testing.T) { diff --git a/pkg/tiller/environment/environment.go b/pkg/tiller/environment/environment.go index 290337d7b..dca7c0756 100644 --- a/pkg/tiller/environment/environment.go +++ b/pkg/tiller/environment/environment.go @@ -26,8 +26,8 @@ import ( "io" "time" - "k8s.io/api/core/v1" - "k8s.io/cli-runtime/pkg/genericclioptions/resource" + v1 "k8s.io/api/core/v1" + "k8s.io/cli-runtime/pkg/resource" "k8s.io/helm/pkg/chartutil" "k8s.io/helm/pkg/engine" diff --git a/pkg/tiller/environment/environment_test.go b/pkg/tiller/environment/environment_test.go index 5c19a9b21..9e9b549d4 100644 --- a/pkg/tiller/environment/environment_test.go +++ b/pkg/tiller/environment/environment_test.go @@ -22,8 +22,8 @@ import ( "testing" "time" - "k8s.io/api/core/v1" - "k8s.io/cli-runtime/pkg/genericclioptions/resource" + v1 "k8s.io/api/core/v1" + "k8s.io/cli-runtime/pkg/resource" "k8s.io/helm/pkg/chartutil" "k8s.io/helm/pkg/kube" diff --git a/pkg/tiller/release_server.go b/pkg/tiller/release_server.go index b85118cd2..d32fd82f6 100644 --- a/pkg/tiller/release_server.go +++ b/pkg/tiller/release_server.go @@ -61,7 +61,7 @@ var ( // errInvalidRevision indicates that an invalid release revision number was provided. errInvalidRevision = errors.New("invalid release revision") //errInvalidName indicates that an invalid release name was provided - errInvalidName = errors.New("invalid release name, must match regex ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])+$ and the length must not longer than 53") + errInvalidName = errors.New("invalid release name, must match regex ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])+$ and the length must not be longer than 53") ) // ListDefaultLimit is the default limit for number of items returned in a list. @@ -115,7 +115,7 @@ func NewReleaseServer(env *environment.Environment, clientset kubernetes.Interfa // request values are not altered. func (s *ReleaseServer) reuseValues(req *services.UpdateReleaseRequest, current *release.Release) error { if req.ResetValues { - // If ResetValues is set, we comletely ignore current.Config. + // If ResetValues is set, we completely ignore current.Config. s.Log("resetting values to the chart's original version") return nil } @@ -191,11 +191,11 @@ func (s *ReleaseServer) uniqName(start string, reuse bool) (string, error) { rel := h[0] if st := rel.Info.Status.Code; reuse && (st == release.Status_DELETED || st == release.Status_FAILED) { - // Allowe re-use of names if the previous release is marked deleted. + // Allow re-use of names if the previous release is marked deleted. s.Log("name %s exists but is not in use, reusing name", start) return start, nil } else if reuse { - return "", fmt.Errorf("a released named %s is in use, cannot re-use a name that is still in use", start) + return "", fmt.Errorf("a release named %s is in use, cannot re-use a name that is still in use", start) } return "", fmt.Errorf("a release named %s already exists.\nRun: helm ls --all %s; to check the status of the release\nOr run: helm del --purge %s; to delete it", start, start, start) diff --git a/pkg/tiller/release_server_test.go b/pkg/tiller/release_server_test.go index a1502e8a2..ecf5ffd17 100644 --- a/pkg/tiller/release_server_test.go +++ b/pkg/tiller/release_server_test.go @@ -31,8 +31,8 @@ import ( "github.com/technosophos/moniker" "golang.org/x/net/context" "google.golang.org/grpc/metadata" - "k8s.io/api/core/v1" - "k8s.io/cli-runtime/pkg/genericclioptions/resource" + v1 "k8s.io/api/core/v1" + "k8s.io/cli-runtime/pkg/resource" "k8s.io/client-go/kubernetes/fake" "k8s.io/helm/pkg/helm" @@ -89,13 +89,22 @@ spec: var manifestWithKeep = `kind: ConfigMap metadata: - name: test-cm-keep + name: test-cm-keep-a annotations: "helm.sh/resource-policy": keep data: name: value ` +var manifestWithKeepEmpty = `kind: ConfigMap +metadata: + name: test-cm-keep-b + annotations: + "helm.sh/resource-policy": "" +data: + name: value +` + var manifestWithUpgradeHooks = `kind: ConfigMap metadata: name: test-cm @@ -449,23 +458,27 @@ func releaseWithKeepStub(rlsName string) *release.Release { Name: "bunnychart", }, Templates: []*chart.Template{ - {Name: "templates/configmap", Data: []byte(manifestWithKeep)}, + {Name: "templates/configmap-keep-a", Data: []byte(manifestWithKeep)}, + {Name: "templates/configmap-keep-b", Data: []byte(manifestWithKeepEmpty)}, }, } date := timestamp.Timestamp{Seconds: 242085845, Nanos: 0} - return &release.Release{ + rl := &release.Release{ Name: rlsName, Info: &release.Info{ FirstDeployed: &date, LastDeployed: &date, Status: &release.Status{Code: release.Status_DEPLOYED}, }, - Chart: ch, - Config: &chart.Config{Raw: `name: value`}, - Version: 1, - Manifest: manifestWithKeep, + Chart: ch, + Config: &chart.Config{Raw: `name: value`}, + Version: 1, } + + helm.RenderReleaseMock(rl, false) + + return rl } func MockEnvironment() *environment.Environment { diff --git a/pkg/tiller/release_uninstall_test.go b/pkg/tiller/release_uninstall_test.go index cb59b6bf5..d95a52c4d 100644 --- a/pkg/tiller/release_uninstall_test.go +++ b/pkg/tiller/release_uninstall_test.go @@ -150,7 +150,10 @@ func TestUninstallReleaseWithKeepPolicy(t *testing.T) { if res.Info == "" { t.Errorf("Expected response info to not be empty") } else { - if !strings.Contains(res.Info, "[ConfigMap] test-cm-keep") { + if !strings.Contains(res.Info, "[ConfigMap] test-cm-keep-a") { + t.Errorf("unexpected output: %s", res.Info) + } + if !strings.Contains(res.Info, "[ConfigMap] test-cm-keep-b") { t.Errorf("unexpected output: %s", res.Info) } } diff --git a/pkg/tiller/release_update_test.go b/pkg/tiller/release_update_test.go index ea1c88f62..e47e526d6 100644 --- a/pkg/tiller/release_update_test.go +++ b/pkg/tiller/release_update_test.go @@ -604,7 +604,7 @@ func TestUpdateReleasePendingInstall_Force(t *testing.T) { t.Error("Expected failed update") } - expectedError := "a released named forceful-luke is in use, cannot re-use a name that is still in use" + expectedError := "a release named forceful-luke is in use, cannot re-use a name that is still in use" got := err.Error() if err.Error() != expectedError { t.Errorf("Expected error %q, got %q", expectedError, got) diff --git a/pkg/tiller/resource_policy.go b/pkg/tiller/resource_policy.go index aa9c5d2bd..c97621fcd 100644 --- a/pkg/tiller/resource_policy.go +++ b/pkg/tiller/resource_policy.go @@ -34,17 +34,11 @@ func filterManifestsToKeep(manifests []Manifest) ([]Manifest, []Manifest) { continue } - resourcePolicyType, ok := m.Head.Metadata.Annotations[kube.ResourcePolicyAnno] - if !ok { - remaining = append(remaining, m) - continue - } - - resourcePolicyType = strings.ToLower(strings.TrimSpace(resourcePolicyType)) - if resourcePolicyType == kube.KeepPolicy { + if kube.ResourcePolicyIsKeep(m.Head.Metadata.Annotations) { keep = append(keep, m) + } else { + remaining = append(remaining, m) } - } return keep, remaining } diff --git a/pkg/tlsutil/cfg.go b/pkg/tlsutil/cfg.go index 2c1dfd340..6c2a829df 100644 --- a/pkg/tlsutil/cfg.go +++ b/pkg/tlsutil/cfg.go @@ -40,7 +40,7 @@ type Options struct { ClientAuth tls.ClientAuthType } -// ClientConfig retusn a TLS configuration for use by a Helm client. +// ClientConfig returns a TLS configuration for use by a Helm client. func ClientConfig(opts Options) (cfg *tls.Config, err error) { var cert *tls.Certificate var pool *x509.CertPool diff --git a/scripts/completions.bash b/scripts/completions.bash index c24f3d257..36cb01f15 100644 --- a/scripts/completions.bash +++ b/scripts/completions.bash @@ -1,3 +1,5 @@ +#!/usr/bin/env bash + # bash completion for helm -*- shell-script -*- __debug() diff --git a/scripts/get b/scripts/get index 9c93e1e84..5479abddb 100755 --- a/scripts/get +++ b/scripts/get @@ -77,16 +77,16 @@ verifySupported() { # checkDesiredVersion checks if the desired version is available. checkDesiredVersion() { - # Use the GitHub releases webpage for the project to find the desired version for this project. - local release_url="https://github.com/helm/helm/releases/${DESIRED_VERSION:-latest}" - if type "curl" > /dev/null; then - TAG=$(curl -SsL $release_url | awk '/\/tag\//' | 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 -q -O - $release_url | awk '/\/tag\//' | 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 - if [ "x$TAG" == "x" ]; then - echo "Cannot determine ${DESIRED_VERSION} tag." - exit 1 + if [ "x$DESIRED_VERSION" == "x" ]; then + # 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 + else + TAG=$DESIRED_VERSION fi }