diff --git a/.circleci/bootstrap.sh b/.circleci/bootstrap.sh index 978464efe..30dc0b316 100755 --- a/.circleci/bootstrap.sh +++ b/.circleci/bootstrap.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Copyright 2016 The Kubernetes Authors All rights reserved. +# 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. diff --git a/.circleci/deploy.sh b/.circleci/deploy.sh index 6ad91109d..08adad568 100755 --- a/.circleci/deploy.sh +++ b/.circleci/deploy.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Copyright 2016 The Kubernetes Authors All rights reserved. +# 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. diff --git a/.circleci/test.sh b/.circleci/test.sh index e0faf9c18..a6acd8f6a 100755 --- a/.circleci/test.sh +++ b/.circleci/test.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Copyright 2016 The Kubernetes Authors All rights reserved. +# 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. diff --git a/.github/issue_template.md b/.github/issue_template.md new file mode 100644 index 000000000..48f48e5b6 --- /dev/null +++ b/.github/issue_template.md @@ -0,0 +1,9 @@ + + +Output of `helm version`: + +Output of `kubectl version`: + +Cloud Provider/Platform (AKS, GKE, Minikube etc.): + + diff --git a/.gitignore b/.gitignore index b94f87b26..7fdfdcf2a 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ _dist/ _proto/*.pb.go bin/ +rootfs/helm rootfs/tiller rootfs/rudder vendor/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 34b4f8b16..715bf7490 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,31 +7,87 @@ The Kubernetes Helm project accepts contributions via GitHub pull requests. This Most of the time, when you find a bug in Helm, it should be reported using [GitHub issues](https://github.com/kubernetes/helm/issues). However, if you are reporting a _security vulnerability_, please email a report to -[helm-security@deis.com](mailto:helm-security@deis.com). This will give +[cncf-kubernetes-helm-security@lists.cncf.io](mailto:cncf-kubernetes-helm-security@lists.cncf.io). This will give us a chance to try to fix the issue before it is exploited in the wild. -## Contributor License Agreements +## Sign Your Work -We'd love to accept your patches! Before we can take them, we have to jump a -couple of legal hurdles. +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/)): -The Cloud Native Computing Foundation (CNCF) CLA [must be signed](https://github.com/kubernetes/community/blob/master/CLA.md) by all contributors. -Please fill out either the individual or corporate Contributor License -Agreement (CLA). +``` +Developer Certificate of Origin +Version 1.1 -Once you are CLA'ed, we'll be able to accept your pull requests. For any issues that you face during this process, -please add a comment [here](https://github.com/kubernetes/kubernetes/issues/27796) explaining the issue and we will help get it sorted out. +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +1 Letterman Drive +Suite D4700 +San Francisco, CA, 94129 -***NOTE***: Only original source code from you and other people that have -signed the CLA can be accepted into the repository. This policy does not -apply to [third_party](third_party/) and [vendor](vendor/). +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. +``` + +Then you just add a line to every git commit message: + + Signed-off-by: Joe Smith + +Use your real name (sorry, no pseudonyms or anonymous contributions.) + +If you set your `user.name` and `user.email` git configs, you can sign your +commit automatically with `git commit -s`. + +Note: If your git config information is set properly then viewing the + `git log` information for your commit will look something like this: + +``` +Author: Joe Smith +Date: Thu Feb 2 11:41:15 2018 -0800 + + Update README + + Signed-off-by: Joe Smith +``` + +Notice the `Author` and `Signed-off-by` lines match. If they don't +your PR will be rejected by the automated DCO check. ## Support Channels Whether you are a user or contributor, official support channels include: - GitHub [issues](https://github.com/kubernetes/helm/issues/new) -- Slack: #Helm room in the [Kubernetes Slack](http://slack.kubernetes.io/) +- Slack [Kubernetes Slack](http://slack.kubernetes.io/): + - User: #helm-users + - Contributor: #helm-dev Before opening a new issue or submitting a new pull request, it's helpful to search the project - it's likely that another user has already reported the issue you're facing, or it's a known issue that we're already aware of. @@ -40,20 +96,20 @@ Before opening a new issue or submitting a new pull request, it's helpful to sea We use milestones to track progress of releases. There are also 2 special milestones used for helping us keep work organized: `Upcoming - Minor` and `Upcoming - Major` -`Upcoming - Minor` is used for keeping track of issues that aren't assigned to a specific +`Upcoming - Minor` is used for keeping track of issues that aren't assigned to a specific release but could easily be addressed in a minor release. `Upcoming - Major` keeps track -of issues that will need to be addressed in a major release. For example, if the current -version is `2.2.0` an issue/PR could fall in to one of 4 different active milestones: -`2.2.1`, `2.3.0`, `Upcoming - Minor`, or `Upcoming - Major`. If an issue pertains to a -specific upcoming bug or minor release, it would go into `2.2.1` or `2.3.0`. If the issue/PR -does not have a specific milestone yet, but it is likely that it will land in a `2.X` release, -it should go into `Upcoming - Minor`. If the issue/PR is a large functionality add or change -and/or it breaks compatibility, then it should be added to the `Upcoming - Major` milestone. +of issues that will need to be addressed in a major release. For example, if the current +version is `2.2.0` an issue/PR could fall in to one of 4 different active milestones: +`2.2.1`, `2.3.0`, `Upcoming - Minor`, or `Upcoming - Major`. If an issue pertains to a +specific upcoming bug or minor release, it would go into `2.2.1` or `2.3.0`. If the issue/PR +does not have a specific milestone yet, but it is likely that it will land in a `2.X` release, +it should go into `Upcoming - Minor`. If the issue/PR is a large functionality add or change +and/or it breaks compatibility, then it should be added to the `Upcoming - Major` milestone. An issue that we are not sure we will be doing will not be added to any milestone. A milestone (and hence release) is considered done when all outstanding issues/PRs have been closed or moved to another milestone. -## Semver +## Semantic Versioning Helm maintains a strong commitment to backward compatibility. All of our changes to protocols and formats are backward compatible from Helm 2.0 until Helm 3.0. No features, flags, or commands are removed or substantially modified (other than bug fixes). @@ -75,42 +131,42 @@ Issues are used as the primary method for tracking anything to do with the Helm ### Issue Types There are 4 types of issues (each with their own corresponding [label](#labels)): -- Question: These are support or functionality inquiries that we want to have a record of for -future reference. Generally these are questions that are too complex or large to store in the -Slack channel or have particular interest to the community as a whole. Depending on the discussion, +- Question: These are support or functionality inquiries that we want to have a record of for +future reference. Generally these are questions that are too complex or large to store in the +Slack channel or have particular interest to the community as a whole. Depending on the discussion, these can turn into "Feature" or "Bug" issues. -- Proposal: Used for items (like this one) that propose a new ideas or functionality that require -a larger community discussion. This allows for feedback from others in the community before a -feature is actually developed. This is not needed for small additions. Final word on whether or -not a feature needs a proposal is up to the core maintainers. All issues that are proposals should -both have a label and an issue title of "Proposal: [the rest of the title]." A proposal can become +- Proposal: Used for items (like this one) that propose a new ideas or functionality that require +a larger community discussion. This allows for feedback from others in the community before a +feature is actually developed. This is not needed for small additions. Final word on whether or +not a feature needs a proposal is up to the core maintainers. All issues that are proposals should +both have a label and an issue title of "Proposal: [the rest of the title]." A proposal can become a "Feature" and does not require a milestone. -- Features: These track specific feature requests and ideas until they are complete. They can evolve +- Features: These track specific feature requests and ideas until they are complete. They can evolve from a "Proposal" or can be submitted individually depending on the size. - Bugs: These track bugs with the code or problems with the documentation (i.e. missing or incomplete) ### Issue Lifecycle -The issue lifecycle is mainly driven by the core maintainers, but is good information for those +The issue lifecycle is mainly driven by the core maintainers, but is good information for those contributing to Helm. All issue types follow the same general lifecycle. Differences are noted below. 1. Issue creation 2. Triage - - The maintainer in charge of triaging will apply the proper labels for the issue. This - includes labels for priority, type, and metadata (such as "starter"). The only issue - priority we will be tracking is whether or not the issue is "critical." If additional + - The maintainer in charge of triaging will apply the proper labels for the issue. This + includes labels for priority, type, and metadata (such as "starter"). The only issue + priority we will be tracking is whether or not the issue is "critical." If additional levels are needed in the future, we will add them. - - (If needed) Clean up the title to succinctly and clearly state the issue. Also ensure + - (If needed) Clean up the title to succinctly and clearly state the issue. Also ensure that proposals are prefaced with "Proposal". - - Add the issue to the correct milestone. If any questions come up, don't worry about + - Add the issue to the correct milestone. If any questions come up, don't worry about adding the issue to a milestone until the questions are answered. - We attempt to do this process at least once per work day. 3. Discussion - - "Feature" and "Bug" issues should be connected to the PR that resolves it. - - Whoever is working on a "Feature" or "Bug" issue (whether a maintainer or someone from - the community), should either assign the issue to them self or make a comment in the issue + - "Feature" and "Bug" issues should be connected to the PR that resolves it. + - Whoever is working on a "Feature" or "Bug" issue (whether a maintainer or someone from + the community), should either assign the issue to them self or make a comment in the issue saying that they are taking it. - - "Proposal" and "Question" issues should stay open until resolved or if they have not been - active for more than 30 days. This will help keep the issue queue to a manageable size and + - "Proposal" and "Question" issues should stay open until resolved or if they have not been + active for more than 30 days. This will help keep the issue queue to a manageable size and reduce noise. Should the issue need to stay open, the `keep open` label can be added. 4. Issue closure @@ -133,36 +189,36 @@ Like any good open source project, we use Pull Requests to track code changes 1. PR creation - We more than welcome PRs that are currently in progress. They are a great way to keep track of - important work that is in-flight, but useful for others to see. If a PR is a work in progress, + important work that is in-flight, but useful for others to see. If a PR is a work in progress, it **must** be prefaced with "WIP: [title]". Once the PR is ready for review, remove "WIP" from the title. - It is preferred, but not required, to have a PR tied to a specific issue. 2. Triage - - The maintainer in charge of triaging will apply the proper labels for the issue. This should - include at least a size label, `bug` or `feature`, and `awaiting review` once all labels are applied. + - The maintainer in charge of triaging will apply the proper labels for the issue. This should + include at least a size label, `bug` or `feature`, and `awaiting review` once all labels are applied. See the [Labels section](#labels) for full details on the definitions of labels - Add the PR to the correct milestone. This should be the same as the issue the PR closes. 3. Assigning reviews - - Once a review has the `awaiting review` label, maintainers will review them as schedule permits. + - Once a review has the `awaiting review` label, maintainers will review them as schedule permits. The maintainer who takes the issue should self-request a review. - - Reviews from others in the community, especially those who have encountered a bug or have - requested a feature, are highly encouraged, but not required. Maintainer reviews **are** required + - Reviews from others in the community, especially those who have encountered a bug or have + requested a feature, are highly encouraged, but not required. Maintainer reviews **are** required before any merge - - Any PR with the `size/large` label requires 2 review approvals from maintainers before it can be + - Any PR with the `size/large` label requires 2 review approvals from maintainers before it can be merged. Those with `size/medium` are per the judgement of the maintainers 4. Reviewing/Discussion - - Once a maintainer begins reviewing a PR, they will remove the `awaiting review` label and add - the `in progress` label so the person submitting knows that it is being worked on. This is + - Once a maintainer begins reviewing a PR, they will remove the `awaiting review` label and add + the `in progress` label so the person submitting knows that it is being worked on. This is especially helpful when the review may take awhile. - All reviews will be completed using Github review tool. - - A "Comment" review should be used when there are questions about the code that should be + - A "Comment" review should be used when there are questions about the code that should be answered, but that don't involve code changes. This type of review does not count as approval. - A "Changes Requested" review indicates that changes to the code need to be made before they will be merged. - Reviewers should update labels as needed (such as `needs rebase`) 5. Address comments by answering questions or changing code 6. Merge or close - - PRs should stay open until merged or if they have not been active for more than 30 days. - This will help keep the PR queue to a manageable size and reduce noise. Should the PR need + - PRs should stay open until merged or if they have not been active for more than 30 days. + This will help keep the PR queue to a manageable size and reduce noise. Should the PR need to stay open (like in the case of a WIP), the `keep open` label can be added. - If the owner of the PR is listed in `OWNERS`, that user **must** merge their own PRs or explicitly request another OWNER do that for them. @@ -171,14 +227,14 @@ Like any good open source project, we use Pull Requests to track code changes #### Documentation PRs -Documentation PRs will follow the same lifecycle as other PRs. They will also be labeled with the -`docs` label. For documentation, special attention will be paid to spelling, grammar, and clarity +Documentation PRs will follow the same lifecycle as other PRs. They will also be labeled with the +`docs` label. For documentation, special attention will be paid to spelling, grammar, and clarity (whereas those things don't matter *as* much for comments in code). ## 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 +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 throughout the work week. ## Labels @@ -213,8 +269,6 @@ The following tables define all label types used for Helm. It is split up by cat | ----- | ----------- | | `awaiting review` | The PR has been triaged and is ready for someone to review | | `breaking` | The PR has breaking changes (such as API changes) | -| `cncf-cla: no` | The PR submitter has **not** signed the project CLA. | -| `cncf-cla: yes` | The PR submitter has signed the project CLA. This is required to merge. | | `in progress` | Indicates that a maintainer is looking at the PR, even if no review has been posted yet | | `needs pick` | Indicates that the PR needs to be picked into a feature branch (generally bugfix branches). Once it has been, the `picked` label should be applied and this one removed | | `needs rebase` | A helper label used to indicate that the PR needs to be rebased before it can be merged. Used for easy filtering | @@ -222,11 +276,11 @@ The following tables define all label types used for Helm. It is split up by cat #### Size labels -Size labels are used to indicate how "dangerous" a PR is. The guidelines below are used to assign the -labels, but ultimately this can be changed by the maintainers. For example, even if a PR only makes -30 lines of changes in 1 file, but it changes key functionality, it will likely be labeled as `size/large` -because it requires sign off from multiple people. Conversely, a PR that adds a small feature, but requires -another 150 lines of tests to cover all cases, could be labeled as `size/small` even though the number +Size labels are used to indicate how "dangerous" a PR is. The guidelines below are used to assign the +labels, but ultimately this can be changed by the maintainers. For example, even if a PR only makes +30 lines of changes in 1 file, but it changes key functionality, it will likely be labeled as `size/large` +because it requires sign off from multiple people. Conversely, a PR that adds a small feature, but requires +another 150 lines of tests to cover all cases, could be labeled as `size/small` even though the number lines is greater than defined below. | Label | Description | diff --git a/LICENSE b/LICENSE index 21c57fae2..393b7a33b 100644 --- a/LICENSE +++ b/LICENSE @@ -187,7 +187,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2016 The Kubernetes Authors All Rights Reserved + 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. diff --git a/Makefile b/Makefile index 709cc301a..6264cd814 100644 --- a/Makefile +++ b/Makefile @@ -2,9 +2,8 @@ DOCKER_REGISTRY ?= gcr.io IMAGE_PREFIX ?= kubernetes-helm SHORT_NAME ?= tiller SHORT_NAME_RUDDER ?= rudder -TARGETS ?= darwin/amd64 linux/amd64 linux/386 linux/arm linux/arm64 linux/ppc64le windows/amd64 +TARGETS ?= darwin/amd64 linux/amd64 linux/386 linux/arm linux/arm64 linux/ppc64le linux/s390x windows/amd64 DIST_DIRS = find * -type d -exec -APP = helm # go option GO ?= go @@ -27,11 +26,12 @@ all: build build: GOBIN=$(BINDIR) $(GO) install $(GOFLAGS) -tags '$(TAGS)' -ldflags '$(LDFLAGS)' k8s.io/helm/cmd/... -# usage: make clean build-cross dist APP=helm|tiller VERSION=v2.0.0-alpha.3 +# usage: make clean build-cross dist VERSION=v2.0.0-alpha.3 .PHONY: build-cross build-cross: LDFLAGS += -extldflags "-static" build-cross: - CGO_ENABLED=0 gox -parallel=3 -output="_dist/{{.OS}}-{{.Arch}}/{{.Dir}}" -osarch='$(TARGETS)' $(GOFLAGS) -tags '$(TAGS)' -ldflags '$(LDFLAGS)' k8s.io/helm/cmd/$(APP) + CGO_ENABLED=0 gox -parallel=3 -output="_dist/{{.OS}}-{{.Arch}}/{{.Dir}}" -osarch='$(TARGETS)' $(GOFLAGS) $(if $(TAGS),-tags '$(TAGS)',) -ldflags '$(LDFLAGS)' k8s.io/helm/cmd/helm + CGO_ENABLED=0 gox -parallel=3 -output="_dist/{{.OS}}-{{.Arch}}/{{.Dir}}" -osarch='$(TARGETS)' $(GOFLAGS) $(if $(TAGS),-tags '$(TAGS)',) -ldflags '$(LDFLAGS)' k8s.io/helm/cmd/tiller .PHONY: dist dist: @@ -60,6 +60,7 @@ check-docker: docker-binary: BINDIR = ./rootfs docker-binary: GOFLAGS += -a -installsuffix cgo docker-binary: + GOOS=linux GOARCH=amd64 CGO_ENABLED=0 $(GO) build -o $(BINDIR)/helm $(GOFLAGS) -tags '$(TAGS)' -ldflags '$(LDFLAGS)' k8s.io/helm/cmd/helm GOOS=linux GOARCH=amd64 CGO_ENABLED=0 $(GO) build -o $(BINDIR)/tiller $(GOFLAGS) -tags '$(TAGS)' -ldflags '$(LDFLAGS)' k8s.io/helm/cmd/tiller .PHONY: docker-build @@ -120,7 +121,6 @@ coverage: HAS_GLIDE := $(shell command -v glide;) HAS_GOX := $(shell command -v gox;) HAS_GIT := $(shell command -v git;) -HAS_HG := $(shell command -v hg;) .PHONY: bootstrap bootstrap: @@ -133,9 +133,6 @@ endif ifndef HAS_GIT $(error You must install Git) -endif -ifndef HAS_HG - $(error You must install Mercurial) endif glide install --strip-vendor go build -o bin/protoc-gen-go ./vendor/github.com/golang/protobuf/protoc-gen-go diff --git a/OWNERS b/OWNERS index 32b26efa2..39f8c8448 100644 --- a/OWNERS +++ b/OWNERS @@ -28,3 +28,4 @@ emeritus: - migmartri - seh - vaikas-google + - rimusz diff --git a/README.md b/README.md index 7622fafc8..018099e01 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@ -# Kubernetes Helm +# Helm -[![CircleCI](https://circleci.com/gh/kubernetes/helm.svg?style=svg)](https://circleci.com/gh/kubernetes/helm) -[![Go Report Card](https://goreportcard.com/badge/github.com/kubernetes/helm)](https://goreportcard.com/report/github.com/kubernetes/helm) -[![GoDoc](https://godoc.org/github.com/kubernetes/helm?status.svg)](https://godoc.org/github.com/kubernetes/helm) +[![CircleCI](https://circleci.com/gh/helm/helm.svg?style=svg)](https://circleci.com/gh/helm/helm) +[![Go Report Card](https://goreportcard.com/badge/github.com/helm/helm)](https://goreportcard.com/report/github.com/helm/helm) +[![GoDoc](https://godoc.org/k8s.io/helm?status.svg)](https://godoc.org/k8s.io/helm) Helm is a tool for managing Kubernetes charts. Charts are packages of pre-configured Kubernetes resources. Use Helm to: -- Find and use [popular software packaged as Kubernetes charts](https://github.com/kubernetes/charts) -- Share your own applications as Kubernetes charts +- Find and use [popular software packaged as Helm charts](https://github.com/helm/charts) to run in Kubernetes +- Share your own applications as Helm charts - Create reproducible builds of your Kubernetes applications - Intelligently manage your Kubernetes manifest files - Manage releases of Helm packages @@ -32,15 +32,15 @@ Think of it like apt/yum/homebrew for Kubernetes. ## Install -Binary downloads of the Helm client can be found at the following links: - -- [OSX](https://kubernetes-helm.storage.googleapis.com/helm-v2.8.2-darwin-amd64.tar.gz) -- [Linux](https://kubernetes-helm.storage.googleapis.com/helm-v2.8.2-linux-amd64.tar.gz) -- [Linux 32-bit](https://kubernetes-helm.storage.googleapis.com/helm-v2.8.2-linux-386.tar.gz) -- [Windows](https://kubernetes-helm.storage.googleapis.com/helm-v2.8.2-windows-amd64.tar.gz) +Binary downloads of the Helm client can be found on [the Releases page](https://github.com/helm/helm/releases/latest). Unpack the `helm` binary and add it to your PATH and you are good to go! -macOS/[homebrew](https://brew.sh/) users can also use `brew install kubernetes-helm`. + +If you want to use a package manager: + +- [Homebrew](https://brew.sh/) users can use `brew install kubernetes-helm`. +- [Chocolatey](https://chocolatey.org/) users can use `choco install kubernetes-helm`. +- [GoFish](https://gofi.sh/) users can use `gofish install helm`. To rapidly get Helm up and running, start with the [Quick Start Guide](https://docs.helm.sh/using_helm/#quickstart-guide). @@ -53,21 +53,20 @@ Get started with the [Quick Start guide](https://docs.helm.sh/using_helm/#quicks ## Roadmap -The [Helm roadmap uses Github milestones](https://github.com/kubernetes/helm/milestones) to track the progress of the project. +The [Helm roadmap uses Github milestones](https://github.com/helm/helm/milestones) to track the progress of the project. ## Community, discussion, contribution, and support You can reach the Helm community and developers via the following channels: - [Kubernetes Slack](http://slack.k8s.io): - - #helm-users - - #helm-dev - - #charts -- Mailing Lists: - - [Helm Mailing List](https://lists.cncf.io/g/cncf-kubernetes-helm) - - [Kubernetes SIG Apps Mailing List](https://groups.google.com/forum/#!forum/kubernetes-sig-apps) -- Developer Call: Thursdays at 9:30-10:00 Pacific. [https://zoom.us/j/4526666954](https://zoom.us/j/4526666954) + - [#helm-users](https://kubernetes.slack.com/messages/helm-users) + - [#helm-dev](https://kubernetes.slack.com/messages/helm-dev) + - [#charts](https://kubernetes.slack.com/messages/charts) +- Mailing List: + - [Helm Mailing List](https://lists.cncf.io/g/cncf-helm) +- Developer Call: Thursdays at 9:30-10:00 Pacific. [https://zoom.us/j/696660622](https://zoom.us/j/696660622) ### Code of conduct -Participation in the Kubernetes community is governed by the [Kubernetes Code of Conduct](code-of-conduct.md). +Participation in the Helm community is governed by the [Code of Conduct](code-of-conduct.md). diff --git a/SECURITY_CONTACTS b/SECURITY_CONTACTS new file mode 100644 index 000000000..7298ea2d2 --- /dev/null +++ b/SECURITY_CONTACTS @@ -0,0 +1,20 @@ +# Defined below are the security contacts for this repo. +# +# They are the contact point for the Product Security Team to reach out +# to for triaging and handling of incoming issues. +# +# The below names agree to abide by the +# [Embargo Policy](https://github.com/kubernetes/sig-release/blob/master/security-release-process-documentation/security-release-process.md#embargo-policy) +# and will be removed and replaced if they violate that agreement. +# +# DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE +# INSTRUCTIONS AT https://github.com/kubernetes/helm/blob/master/CONTRIBUTING.md#reporting-a-security-issue + +adamreese +bacongobbler +mattfarina +michelleN +prydonius +SlickNik +technosophos +thomastaylor312 diff --git a/_proto/hapi/chart/chart.proto b/_proto/hapi/chart/chart.proto index 9b838fd1a..68aea8f05 100644 --- a/_proto/hapi/chart/chart.proto +++ b/_proto/hapi/chart/chart.proto @@ -1,4 +1,4 @@ -// Copyright 2016 The Kubernetes Authors All rights reserved. +// 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. diff --git a/_proto/hapi/chart/config.proto b/_proto/hapi/chart/config.proto index a1404476b..a851d212f 100644 --- a/_proto/hapi/chart/config.proto +++ b/_proto/hapi/chart/config.proto @@ -1,4 +1,4 @@ -// Copyright 2016 The Kubernetes Authors All rights reserved. +// 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. diff --git a/_proto/hapi/chart/metadata.proto b/_proto/hapi/chart/metadata.proto index 49d6a217a..0ac695ce2 100644 --- a/_proto/hapi/chart/metadata.proto +++ b/_proto/hapi/chart/metadata.proto @@ -1,4 +1,4 @@ -// Copyright 2016 The Kubernetes Authors All rights reserved. +// 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. diff --git a/_proto/hapi/chart/template.proto b/_proto/hapi/chart/template.proto index d13543ea9..879d2071a 100644 --- a/_proto/hapi/chart/template.proto +++ b/_proto/hapi/chart/template.proto @@ -1,4 +1,4 @@ -// Copyright 2016 The Kubernetes Authors All rights reserved. +// 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. diff --git a/_proto/hapi/release/hook.proto b/_proto/hapi/release/hook.proto index 22c1fedef..cf7e25bf6 100644 --- a/_proto/hapi/release/hook.proto +++ b/_proto/hapi/release/hook.proto @@ -1,4 +1,4 @@ -// Copyright 2016 The Kubernetes Authors All rights reserved. +// 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. @@ -34,10 +34,12 @@ message Hook { POST_ROLLBACK = 8; RELEASE_TEST_SUCCESS = 9; RELEASE_TEST_FAILURE = 10; + CRD_INSTALL = 11; } enum DeletePolicy { SUCCEEDED = 0; FAILED = 1; + BEFORE_HOOK_CREATION = 2; } string name = 1; // Kind is the Kubernetes kind. diff --git a/_proto/hapi/release/info.proto b/_proto/hapi/release/info.proto index e23175d3d..ee03056c7 100644 --- a/_proto/hapi/release/info.proto +++ b/_proto/hapi/release/info.proto @@ -1,4 +1,4 @@ -// Copyright 2016 The Kubernetes Authors All rights reserved. +// 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. diff --git a/_proto/hapi/release/release.proto b/_proto/hapi/release/release.proto index 4a6afa0fe..ce9208e29 100644 --- a/_proto/hapi/release/release.proto +++ b/_proto/hapi/release/release.proto @@ -1,4 +1,4 @@ -// Copyright 2016 The Kubernetes Authors All rights reserved. +// 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. diff --git a/_proto/hapi/release/status.proto b/_proto/hapi/release/status.proto index ef28a233c..aa90760b3 100644 --- a/_proto/hapi/release/status.proto +++ b/_proto/hapi/release/status.proto @@ -1,4 +1,4 @@ -// Copyright 2016 The Kubernetes Authors All rights reserved. +// 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. diff --git a/_proto/hapi/release/test_run.proto b/_proto/hapi/release/test_run.proto index 60734ae03..7c281669f 100644 --- a/_proto/hapi/release/test_run.proto +++ b/_proto/hapi/release/test_run.proto @@ -1,5 +1,5 @@ -// Copyright 2016 The Kubernetes Authors All rights reserved. +// 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. diff --git a/_proto/hapi/release/test_suite.proto b/_proto/hapi/release/test_suite.proto index 2f6feb08c..9ac6583b2 100644 --- a/_proto/hapi/release/test_suite.proto +++ b/_proto/hapi/release/test_suite.proto @@ -1,4 +1,4 @@ -// Copyright 2016 The Kubernetes Authors All rights reserved. +// 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. diff --git a/_proto/hapi/rudder/rudder.proto b/_proto/hapi/rudder/rudder.proto index 3a37c9e99..188491512 100644 --- a/_proto/hapi/rudder/rudder.proto +++ b/_proto/hapi/rudder/rudder.proto @@ -1,4 +1,4 @@ -// Copyright 2017 The Kubernetes Authors All rights reserved. +// 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. diff --git a/_proto/hapi/services/tiller.proto b/_proto/hapi/services/tiller.proto index 5897676ab..a94a90a4a 100644 --- a/_proto/hapi/services/tiller.proto +++ b/_proto/hapi/services/tiller.proto @@ -1,4 +1,4 @@ -// Copyright 2016 The Kubernetes Authors All rights reserved. +// 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. @@ -89,7 +89,7 @@ service ReleaseService { // // Releases can be retrieved in chunks by setting limit and offset. // -// Releases can be sorted according to a few pre-determined sort stategies. +// Releases can be sorted according to a few pre-determined sort strategies. message ListReleasesRequest { // Limit is the maximum number of releases to be returned. int64 limit = 1; @@ -209,6 +209,8 @@ message UpdateReleaseRequest { bool reuse_values = 10; // Force resource update through delete/recreate if needed. bool force = 11; + // Description, if set, will set the description for the updated release + string description = 12; } // UpdateReleaseResponse is the response to an update request. @@ -234,6 +236,8 @@ message RollbackReleaseRequest { bool wait = 7; // Force resource update through delete/recreate if needed. bool force = 8; + // Description, if set, will set the description for the rollback + string description = 9; } // RollbackReleaseResponse is the response to an update request. @@ -260,10 +264,10 @@ message InstallReleaseRequest { // DisableHooks causes the server to skip running any hooks for the install. bool disable_hooks = 5; - // Namepace is the kubernetes namespace of the release. + // Namespace is the kubernetes namespace of the release. string namespace = 6; - // ReuseName requests that Tiller re-uses a name, instead of erroring out. + // Reuse_name requests that Tiller re-uses a name, instead of erroring out. bool reuse_name = 7; // timeout specifies the max amount of time any kubernetes client command can run. @@ -271,6 +275,11 @@ message InstallReleaseRequest { // wait, if true, will wait until all Pods, PVCs, and Services are in a ready state // before marking the release as successful. It will wait for as long as timeout bool wait = 9; + + bool disable_crd_hook = 10; + + // Description, if set, will set the description for the installed release + string description = 11; } // InstallReleaseResponse is the response from a release installation. @@ -288,6 +297,8 @@ message UninstallReleaseRequest { bool purge = 3; // timeout specifies the max amount of time any kubernetes client command can run. int64 timeout = 4; + // Description, if set, will set the description for the uninnstalled release + string description = 5; } // UninstallReleaseResponse represents a successful response to an uninstall request. diff --git a/_proto/hapi/version/version.proto b/_proto/hapi/version/version.proto index 0ae0985b7..5c50e852f 100644 --- a/_proto/hapi/version/version.proto +++ b/_proto/hapi/version/version.proto @@ -1,4 +1,4 @@ -// Copyright 2016 The Kubernetes Authors All rights reserved. +// 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. diff --git a/cmd/helm/completion.go b/cmd/helm/completion.go index b1cd04140..b6fbc82d1 100644 --- a/cmd/helm/completion.go +++ b/cmd/helm/completion.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 @@ -82,6 +82,8 @@ func runCompletionBash(out io.Writer, cmd *cobra.Command) error { func runCompletionZsh(out io.Writer, cmd *cobra.Command) error { zshInitialization := ` +#compdef helm + __helm_bash_source() { alias shopt=':' alias _expand=_bash_expand diff --git a/cmd/helm/create.go b/cmd/helm/create.go index 556ff171d..eaea81e5b 100644 --- a/cmd/helm/create.go +++ b/cmd/helm/create.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/helm/create_test.go b/cmd/helm/create_test.go index cb7b1d387..214432b83 100644 --- a/cmd/helm/create_test.go +++ b/cmd/helm/create_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -46,7 +46,7 @@ func TestCreateCmd(t *testing.T) { defer os.Chdir(pwd) // Run a create - cmd := newCreateCmd(os.Stdout) + cmd := newCreateCmd(ioutil.Discard) if err := cmd.RunE(cmd, []string{cname}); err != nil { t.Errorf("Failed to run create: %s", err) return @@ -117,7 +117,7 @@ func TestCreateStarterCmd(t *testing.T) { defer os.Chdir(pwd) // Run a create - cmd := newCreateCmd(os.Stdout) + cmd := newCreateCmd(ioutil.Discard) cmd.ParseFlags([]string{"--starter", "starterchart"}) if err := cmd.RunE(cmd, []string{cname}); err != nil { t.Errorf("Failed to run create: %s", err) diff --git a/cmd/helm/delete.go b/cmd/helm/delete.go index e0ac8c4f6..ad7c6049a 100755 --- a/cmd/helm/delete.go +++ b/cmd/helm/delete.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -40,6 +40,7 @@ type deleteCmd struct { disableHooks bool purge bool timeout int64 + description string out io.Writer client helm.Interface @@ -81,6 +82,7 @@ func newDeleteCmd(c helm.Interface, out io.Writer) *cobra.Command { f.BoolVar(&del.disableHooks, "no-hooks", false, "prevent hooks from running during deletion") f.BoolVar(&del.purge, "purge", false, "remove the release from the store and make its name free for later use") f.Int64Var(&del.timeout, "timeout", 300, "time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks)") + f.StringVar(&del.description, "description", "", "specify a description for the release") return cmd } @@ -91,6 +93,7 @@ func (d *deleteCmd) run() error { helm.DeleteDisableHooks(d.disableHooks), helm.DeletePurge(d.purge), helm.DeleteTimeout(d.timeout), + helm.DeleteDescription(d.description), } res, err := d.client.DeleteRelease(d.name, opts...) if res != nil && res.Info != "" { diff --git a/cmd/helm/delete_test.go b/cmd/helm/delete_test.go index 829d17906..b71860e67 100644 --- a/cmd/helm/delete_test.go +++ b/cmd/helm/delete_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -61,6 +61,14 @@ func TestDelete(t *testing.T) { resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"}), rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"})}, }, + { + name: "delete with description", + args: []string{"aeneas"}, + flags: []string{"--description", "foo"}, + expected: "", + resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"}), + rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"})}, + }, { name: "delete without release", args: []string{}, diff --git a/cmd/helm/dependency.go b/cmd/helm/dependency.go index 231659691..1e3079ded 100644 --- a/cmd/helm/dependency.go +++ b/cmd/helm/dependency.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 @@ -141,7 +141,7 @@ func (l *dependencyListCmd) run() error { r, err := chartutil.LoadRequirements(c) if err != nil { if err == chartutil.ErrRequirementsNotFound { - fmt.Fprintf(l.out, "WARNING: no requirements at %s/charts\n", l.chartpath) + fmt.Fprintf(l.out, "WARNING: no requirements at %s\n", filepath.Join(l.chartpath, "charts")) return nil } return err diff --git a/cmd/helm/dependency_build.go b/cmd/helm/dependency_build.go index ec5fd14b7..3af3c1243 100644 --- a/cmd/helm/dependency_build.go +++ b/cmd/helm/dependency_build.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/cmd/helm/dependency_build_test.go b/cmd/helm/dependency_build_test.go index 2d7c88654..207313bf5 100644 --- a/cmd/helm/dependency_build_test.go +++ b/cmd/helm/dependency_build_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/cmd/helm/dependency_test.go b/cmd/helm/dependency_test.go index cc4519147..e98f436ec 100644 --- a/cmd/helm/dependency_test.go +++ b/cmd/helm/dependency_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/cmd/helm/dependency_update.go b/cmd/helm/dependency_update.go index d6a998639..a8e54137b 100644 --- a/cmd/helm/dependency_update.go +++ b/cmd/helm/dependency_update.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/cmd/helm/dependency_update_test.go b/cmd/helm/dependency_update_test.go index e29cb35de..f7ef84e6f 100644 --- a/cmd/helm/dependency_update_test.go +++ b/cmd/helm/dependency_update_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/cmd/helm/docs.go b/cmd/helm/docs.go index e5b9f7521..56e3beaf5 100644 --- a/cmd/helm/docs.go +++ b/cmd/helm/docs.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/cmd/helm/fetch.go b/cmd/helm/fetch.go index 069f57eff..d6f622bb6 100644 --- a/cmd/helm/fetch.go +++ b/cmd/helm/fetch.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/helm/fetch_test.go b/cmd/helm/fetch_test.go index 13247ee99..3fba37dd6 100644 --- a/cmd/helm/fetch_test.go +++ b/cmd/helm/fetch_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/helm/get.go b/cmd/helm/get.go index a2eb1d137..5744beb62 100644 --- a/cmd/helm/get.go +++ b/cmd/helm/get.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/helm/get_hooks.go b/cmd/helm/get_hooks.go index 1b6f2f8fe..9192db998 100644 --- a/cmd/helm/get_hooks.go +++ b/cmd/helm/get_hooks.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/helm/get_hooks_test.go b/cmd/helm/get_hooks_test.go index e578c2533..fe9133feb 100644 --- a/cmd/helm/get_hooks_test.go +++ b/cmd/helm/get_hooks_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/helm/get_manifest.go b/cmd/helm/get_manifest.go index 1c42830f0..f4ae11e58 100644 --- a/cmd/helm/get_manifest.go +++ b/cmd/helm/get_manifest.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -55,9 +55,7 @@ func newGetManifestCmd(client helm.Interface, out io.Writer) *cobra.Command { return errReleaseRequired } get.release = args[0] - if get.client == nil { - get.client = helm.NewClient(helm.Host(settings.TillerHost)) - } + get.client = ensureHelmClient(get.client) return get.run() }, } diff --git a/cmd/helm/get_manifest_test.go b/cmd/helm/get_manifest_test.go index 286b5628a..c95a1f265 100644 --- a/cmd/helm/get_manifest_test.go +++ b/cmd/helm/get_manifest_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/helm/get_test.go b/cmd/helm/get_test.go index a6e72987a..cb230a8a5 100644 --- a/cmd/helm/get_test.go +++ b/cmd/helm/get_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/helm/get_values.go b/cmd/helm/get_values.go index b6ce648e5..12a48f1da 100644 --- a/cmd/helm/get_values.go +++ b/cmd/helm/get_values.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/helm/get_values_test.go b/cmd/helm/get_values_test.go index 30b2ba4b8..35c84f2ec 100644 --- a/cmd/helm/get_values_test.go +++ b/cmd/helm/get_values_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/helm/helm.go b/cmd/helm/helm.go index 497565209..cdb6313e2 100644 --- a/cmd/helm/helm.go +++ b/cmd/helm/helm.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -30,6 +30,8 @@ import ( "k8s.io/client-go/rest" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" + // Import to initialize client auth plugins. + _ "k8s.io/client-go/plugin/pkg/client/auth" "k8s.io/helm/pkg/helm" helm_env "k8s.io/helm/pkg/helm/environment" "k8s.io/helm/pkg/helm/portforwarder" @@ -38,6 +40,7 @@ import ( ) var ( + tlsServerName string // overrides the server name used to verify the hostname on the returned certificates from the server. tlsCaCertFile string // path to TLS CA certificate file tlsCertFile string // path to TLS certificate file tlsKeyFile string // path to TLS key file @@ -156,7 +159,12 @@ func init() { func main() { cmd := newRootCmd(os.Args[1:]) if err := cmd.Execute(); err != nil { - os.Exit(1) + switch e := err.(type) { + case pluginError: + os.Exit(e.code) + default: + os.Exit(1) + } } } @@ -167,7 +175,7 @@ func markDeprecated(cmd *cobra.Command, notice string) *cobra.Command { func setupConnection() error { if settings.TillerHost == "" { - config, client, err := getKubeClient(settings.KubeContext) + config, client, err := getKubeClient(settings.KubeContext, settings.KubeConfig) if err != nil { return err } @@ -214,15 +222,15 @@ func prettyError(err error) error { } // If it's grpc's error, make it more user-friendly. if s, ok := status.FromError(err); ok { - return s.Err() + return fmt.Errorf(s.Message()) } // Else return the original error. return err } // configForContext creates a Kubernetes REST client configuration for a given kubeconfig context. -func configForContext(context string) (*rest.Config, error) { - config, err := kube.GetConfig(context).ClientConfig() +func configForContext(context string, kubeconfig string) (*rest.Config, error) { + config, err := kube.GetConfig(context, kubeconfig).ClientConfig() if err != nil { return nil, fmt.Errorf("could not get Kubernetes config for context %q: %s", context, err) } @@ -230,8 +238,8 @@ func configForContext(context string) (*rest.Config, error) { } // getKubeClient creates a Kubernetes config and client for a given kubeconfig context. -func getKubeClient(context string) (*rest.Config, kubernetes.Interface, error) { - config, err := configForContext(context) +func getKubeClient(context string, kubeconfig string) (*rest.Config, kubernetes.Interface, error) { + config, err := configForContext(context, kubeconfig) if err != nil { return nil, nil, err } @@ -245,8 +253,8 @@ func getKubeClient(context string) (*rest.Config, kubernetes.Interface, error) { // getInternalKubeClient creates a Kubernetes config and an "internal" client for a given kubeconfig context. // // Prefer the similar getKubeClient if you don't need to use such an internal client. -func getInternalKubeClient(context string) (internalclientset.Interface, error) { - config, err := configForContext(context) +func getInternalKubeClient(context string, kubeconfig string) (internalclientset.Interface, error) { + config, err := configForContext(context, kubeconfig) if err != nil { return nil, err } @@ -278,8 +286,13 @@ func newClient() helm.Interface { if tlsKeyFile == "" { tlsKeyFile = settings.Home.TLSKey() } - debug("Key=%q, Cert=%q, CA=%q\n", tlsKeyFile, tlsCertFile, tlsCaCertFile) - tlsopts := tlsutil.Options{KeyFile: tlsKeyFile, CertFile: tlsCertFile, InsecureSkipVerify: true} + debug("Host=%q, Key=%q, Cert=%q, CA=%q\n", tlsKeyFile, tlsCertFile, tlsCaCertFile) + tlsopts := tlsutil.Options{ + ServerName: tlsServerName, + KeyFile: tlsKeyFile, + CertFile: tlsCertFile, + InsecureSkipVerify: true, + } if tlsVerify { tlsopts.CaCertFile = tlsCaCertFile tlsopts.InsecureSkipVerify = false @@ -299,6 +312,7 @@ func newClient() helm.Interface { func addFlagsTLS(cmd *cobra.Command) *cobra.Command { // add flags + cmd.Flags().StringVar(&tlsServerName, "tls-hostname", settings.TillerHost, "the server name used to verify the hostname on the returned certificates from the server") cmd.Flags().StringVar(&tlsCaCertFile, "tls-ca-cert", tlsCaCertDefault, "path to TLS CA certificate file") cmd.Flags().StringVar(&tlsCertFile, "tls-cert", tlsCertDefault, "path to TLS certificate file") cmd.Flags().StringVar(&tlsKeyFile, "tls-key", tlsKeyDefault, "path to TLS key file") diff --git a/cmd/helm/helm_test.go b/cmd/helm/helm_test.go index c95caa75f..c872af8c3 100644 --- a/cmd/helm/helm_test.go +++ b/cmd/helm/helm_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -43,7 +43,10 @@ func runReleaseCases(t *testing.T, tests []releaseCase, rcmd releaseCmd) { var buf bytes.Buffer for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - c := &helm.FakeClient{Rels: tt.rels} + c := &helm.FakeClient{ + Rels: tt.rels, + Responses: tt.responses, + } cmd := rcmd(c, &buf) cmd.ParseFlags(tt.flags) err := cmd.RunE(cmd, tt.args) @@ -69,7 +72,8 @@ type releaseCase struct { err bool resp *release.Release // Rels are the available releases at the start of the test. - rels []*release.Release + rels []*release.Release + responses map[string]release.TestRun_Status } // tempHelmHome sets up a Helm Home in a temp dir. diff --git a/cmd/helm/history.go b/cmd/helm/history.go index e6366d31d..6e0b48d33 100644 --- a/cmd/helm/history.go +++ b/cmd/helm/history.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/helm/history_test.go b/cmd/helm/history_test.go index fef433742..5d5146228 100644 --- a/cmd/helm/history_test.go +++ b/cmd/helm/history_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/helm/home.go b/cmd/helm/home.go index e96edd7a1..ca21088a7 100644 --- a/cmd/helm/home.go +++ b/cmd/helm/home.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/helm/init.go b/cmd/helm/init.go index d368945ec..138fa14d7 100644 --- a/cmd/helm/init.go +++ b/cmd/helm/init.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -181,95 +181,64 @@ func (i *initCmd) run() error { i.opts.MaxHistory = i.maxHistory i.opts.Replicas = i.replicas - writeYAMLManifest := func(apiVersion, kind, body string, first, last bool) error { + writeYAMLManifests := func(manifests []string) error { w := i.out - if !first { - // YAML starting document boundary marker + for _, manifest := range manifests { if _, err := fmt.Fprintln(w, "---"); err != nil { return err } + + if _, err := fmt.Fprintln(w, manifest); err != nil { + return err + } } - if _, err := fmt.Fprintln(w, "apiVersion:", apiVersion); err != nil { - return err - } - if _, err := fmt.Fprintln(w, "kind:", kind); err != nil { - return err - } - if _, err := fmt.Fprint(w, body); err != nil { - return err - } - if !last { - return nil - } + // YAML ending document boundary marker _, err := fmt.Fprintln(w, "...") return err } if len(i.opts.Output) > 0 { - var body string + var manifests []string var err error - const tm = `{"apiVersion":"extensions/v1beta1","kind":"Deployment",` - if body, err = installer.DeploymentManifest(&i.opts); err != nil { + if manifests, err = installer.TillerManifests(&i.opts); err != nil { return err } switch i.opts.Output.String() { case "json": - var out bytes.Buffer - jsonb, err := yaml.ToJSON([]byte(body)) - if err != nil { - return err - } - buf := bytes.NewBuffer(make([]byte, 0, len(tm)+len(jsonb)-1)) - buf.WriteString(tm) - // Drop the opening object delimiter ('{'). - buf.Write(jsonb[1:]) - if err := json.Indent(&out, buf.Bytes(), "", " "); err != nil { - return err - } - if _, err = i.out.Write(out.Bytes()); err != nil { - return err + for _, manifest := range manifests { + var out bytes.Buffer + jsonb, err := yaml.ToJSON([]byte(manifest)) + if err != nil { + return err + } + buf := bytes.NewBuffer(jsonb) + if err := json.Indent(&out, buf.Bytes(), "", " "); err != nil { + return err + } + if _, err = i.out.Write(out.Bytes()); err != nil { + return err + } + fmt.Fprint(i.out, "\n") } - return nil case "yaml": - if err := writeYAMLManifest("extensions/v1beta1", "Deployment", body, true, false); err != nil { - return err - } - return nil + return writeYAMLManifests(manifests) default: return fmt.Errorf("unknown output format: %q", i.opts.Output) } } if settings.Debug { - - var body string + var manifests []string var err error - // write Deployment manifest - if body, err = installer.DeploymentManifest(&i.opts); err != nil { - return err - } - if err := writeYAMLManifest("extensions/v1beta1", "Deployment", body, true, false); err != nil { + // write Tiller manifests + if manifests, err = installer.TillerManifests(&i.opts); err != nil { return err } - // write Service manifest - if body, err = installer.ServiceManifest(i.namespace); err != nil { - return err - } - if err := writeYAMLManifest("v1", "Service", body, false, !i.opts.EnableTLS); err != nil { + if err = writeYAMLManifests(manifests); err != nil { return err } - - // write Secret manifest - if i.opts.EnableTLS { - if body, err = installer.SecretManifest(&i.opts); err != nil { - return err - } - if err := writeYAMLManifest("v1", "Secret", body, false, true); err != nil { - return err - } - } } if i.dryRun { @@ -289,7 +258,7 @@ func (i *initCmd) run() error { if !i.clientOnly { if i.kubeClient == nil { - _, c, err := getKubeClient(settings.KubeContext) + _, c, err := getKubeClient(settings.KubeContext, settings.KubeConfig) if err != nil { return fmt.Errorf("could not get kubernetes client: %s", err) } @@ -312,9 +281,12 @@ func (i *initCmd) run() error { "(Use --client-only to suppress this message, or --upgrade to upgrade Tiller to the current version.)") } } else { - fmt.Fprintln(i.out, "\nTiller (the Helm server-side component) has been installed into your Kubernetes Cluster.\n\n"+ - "Please note: by default, Tiller is deployed with an insecure 'allow unauthenticated users' policy.\n"+ - "For more information on securing your installation see: https://docs.helm.sh/using_helm/#securing-your-helm-installation") + fmt.Fprintln(i.out, "\nTiller (the Helm server-side component) has been installed into your Kubernetes Cluster.") + if !tlsVerify { + fmt.Fprintln(i.out, "\nPlease note: by default, Tiller is deployed with an insecure 'allow unauthenticated users' policy.\n"+ + "To prevent this, run `helm init` with the --tiller-tls-verify flag.\n"+ + "For more information on securing your installation see: https://docs.helm.sh/using_helm/#securing-your-helm-installation") + } } if err := i.ping(); err != nil { return err @@ -329,7 +301,7 @@ func (i *initCmd) run() error { func (i *initCmd) ping() error { if i.wait { - _, kubeClient, err := getKubeClient(settings.KubeContext) + _, kubeClient, err := getKubeClient(settings.KubeContext, settings.KubeConfig) if err != nil { return err } diff --git a/cmd/helm/init_test.go b/cmd/helm/init_test.go index 6a5767fca..fd6ef97c4 100644 --- a/cmd/helm/init_test.go +++ b/cmd/helm/init_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -18,6 +18,7 @@ package main import ( "bytes" + "io" "io/ioutil" "os" "path/filepath" @@ -32,11 +33,10 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + yamlutil "k8s.io/apimachinery/pkg/util/yaml" "k8s.io/client-go/kubernetes/fake" testcore "k8s.io/client-go/testing" - "encoding/json" - "k8s.io/helm/cmd/helm/installer" "k8s.io/helm/pkg/helm/helmpath" ) @@ -306,7 +306,7 @@ func TestInitCmd_tlsOptions(t *testing.T) { } } -// TestInitCmd_output tests that init -o formats are unmarshal-able +// TestInitCmd_output tests that init -o can be decoded func TestInitCmd_output(t *testing.T) { // This is purely defensive in this case. home, err := ioutil.TempDir("", "helm_home") @@ -320,26 +320,14 @@ func TestInitCmd_output(t *testing.T) { settings.Debug = dbg }() fc := fake.NewSimpleClientset() - tests := []struct { - expectF func([]byte, interface{}) error - expectName string - }{ - { - json.Unmarshal, - "json", - }, - { - yaml.Unmarshal, - "yaml", - }, - } + tests := []string{"json", "yaml"} for _, s := range tests { var buf bytes.Buffer cmd := &initCmd{ out: &buf, home: helmpath.Home(home), kubeClient: fc, - opts: installer.Options{Output: installer.OutputFormat(s.expectName)}, + opts: installer.Options{Output: installer.OutputFormat(s)}, namespace: v1.NamespaceDefault, } if err := cmd.run(); err != nil { @@ -348,10 +336,17 @@ func TestInitCmd_output(t *testing.T) { if got := len(fc.Actions()); got != 0 { t.Errorf("expected no server calls, got %d", got) } - d := &v1beta1.Deployment{} - if err = s.expectF(buf.Bytes(), &d); err != nil { - t.Errorf("error unmarshalling init %s output %s %s", s.expectName, err, buf.String()) + + var obj interface{} + decoder := yamlutil.NewYAMLOrJSONDecoder(&buf, 4096) + for { + err := decoder.Decode(&obj) + if err != nil { + if err == io.EOF { + break + } + t.Errorf("error decoding init %s output %s %s", s, err, buf.String()) + } } } - } diff --git a/cmd/helm/init_unix.go b/cmd/helm/init_unix.go index 1117dd487..bf61f1925 100644 --- a/cmd/helm/init_unix.go +++ b/cmd/helm/init_unix.go @@ -1,7 +1,7 @@ // +build !windows /* -Copyright 2017 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/helm/init_windows.go b/cmd/helm/init_windows.go index be17bccda..447044bba 100644 --- a/cmd/helm/init_windows.go +++ b/cmd/helm/init_windows.go @@ -1,7 +1,7 @@ // +build windows /* -Copyright 2017 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/helm/inspect.go b/cmd/helm/inspect.go index 999856959..c1861f7c5 100644 --- a/cmd/helm/inspect.go +++ b/cmd/helm/inspect.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/helm/inspect_test.go b/cmd/helm/inspect_test.go index 44d71fbbd..b9dbf2ab6 100644 --- a/cmd/helm/inspect_test.go +++ b/cmd/helm/inspect_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/helm/install.go b/cmd/helm/install.go index 1d8ec85f1..1488b87c5 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -50,8 +50,10 @@ The install argument must be a chart reference, a path to a packaged chart, a path to an unpacked chart directory or a URL. To override values in a chart, use either the '--values' flag and pass in a file -or use the '--set' flag and pass configuration from the command line, to force -a string value use '--set-string'. +or use the '--set' flag and pass configuration from the command line. To force string +values in '--set', use '--set-string' instead. In case a value is large and therefore +you want not to use neither '--values' nor '--set', use '--set-file' to read the +single large value from file. $ helm install -f myvalues.yaml ./redis @@ -63,6 +65,9 @@ or $ helm install --set-string long_int=1234567890 ./redis +or + $ helm install --set-file multiline_text=path/to/textfile + You can specify the '--values'/'-f' flag multiple times. The priority will be given to the last (right-most) file specified. For example, if both myvalues.yaml and override.yaml contained a key called 'Test', the value set in override.yaml would take precedence: @@ -106,28 +111,31 @@ charts in a repository, use 'helm search'. ` type installCmd struct { - name string - namespace string - valueFiles valueFiles - chartPath string - dryRun bool - disableHooks bool - replace bool - verify bool - keyring string - out io.Writer - client helm.Interface - values []string - stringValues []string - nameTemplate string - version string - timeout int64 - wait bool - repoURL string - username string - password string - devel bool - depUp bool + name string + namespace string + valueFiles valueFiles + chartPath string + dryRun bool + disableHooks bool + disableCRDHook bool + replace bool + verify bool + keyring string + out io.Writer + client helm.Interface + values []string + stringValues []string + fileValues []string + nameTemplate string + version string + timeout int64 + wait bool + repoURL string + username string + password string + devel bool + depUp bool + description string certFile string keyFile string @@ -190,9 +198,11 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command { f.StringVar(&inst.namespace, "namespace", "", "namespace to install the release into. Defaults to the current kube config namespace.") f.BoolVar(&inst.dryRun, "dry-run", false, "simulate an install") f.BoolVar(&inst.disableHooks, "no-hooks", false, "prevent hooks from running during install") + f.BoolVar(&inst.disableCRDHook, "no-crd-hook", false, "prevent CRD hooks from running, but run other hooks") f.BoolVar(&inst.replace, "replace", false, "re-use the given name, even if that name is already used. This is unsafe in production") f.StringArrayVar(&inst.values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)") f.StringArrayVar(&inst.stringValues, "set-string", []string{}, "set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)") + f.StringArrayVar(&inst.fileValues, "set-file", []string{}, "set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2)") f.StringVar(&inst.nameTemplate, "name-template", "", "specify template used to name the release") f.BoolVar(&inst.verify, "verify", false, "verify the package before installing it") f.StringVar(&inst.keyring, "keyring", defaultKeyring(), "location of public keys used for verification") @@ -207,6 +217,7 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command { f.StringVar(&inst.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle") f.BoolVar(&inst.devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored.") f.BoolVar(&inst.depUp, "dep-up", false, "run helm dependency update before installing the chart") + f.StringVar(&inst.description, "description", "", "specify a description for the release") return cmd } @@ -218,7 +229,7 @@ func (i *installCmd) run() error { i.namespace = defaultNamespace() } - rawVals, err := vals(i.valueFiles, i.values, i.stringValues) + rawVals, err := vals(i.valueFiles, i.values, i.stringValues, i.fileValues, i.certFile, i.keyFile, i.caFile) if err != nil { return err } @@ -256,6 +267,12 @@ func (i *installCmd) run() error { if err := man.Update(); err != nil { return prettyError(err) } + + // Update all dependencies which are present in /charts. + chartRequested, err = chartutil.Load(i.chartPath) + if err != nil { + return prettyError(err) + } } else { return prettyError(err) } @@ -273,8 +290,10 @@ func (i *installCmd) run() error { helm.InstallDryRun(i.dryRun), helm.InstallReuseName(i.replace), helm.InstallDisableHooks(i.disableHooks), + helm.InstallDisableCRDHook(i.disableCRDHook), helm.InstallTimeout(i.timeout), - helm.InstallWait(i.wait)) + helm.InstallWait(i.wait), + helm.InstallDescription(i.description)) if err != nil { return prettyError(err) } @@ -287,6 +306,10 @@ func (i *installCmd) run() error { // If this is a dry run, we can't display status. if i.dryRun { + // This is special casing to avoid breaking backward compatibility: + if res.Release.Info.Description != "Dry run complete" { + fmt.Fprintf(os.Stdout, "WARNING: %s\n", res.Release.Info.Description) + } return nil } @@ -313,11 +336,6 @@ func mergeValues(dest map[string]interface{}, src map[string]interface{}) map[st dest[k] = v continue } - // If the key doesn't exist already, then just set the key to that value - if _, exists := dest[k]; !exists { - dest[k] = nextMap - continue - } // Edge case: If the key exists in the destination, but isn't a map destMap, isMap := dest[k].(map[string]interface{}) // If the source map has a map for this key, prefer it @@ -332,8 +350,8 @@ func mergeValues(dest map[string]interface{}, src map[string]interface{}) map[st } // vals merges values from files specified via -f/--values and -// directly via --set or --set-string, marshaling them to YAML -func vals(valueFiles valueFiles, values []string, stringValues []string) ([]byte, error) { +// directly via --set or --set-string or --set-file, marshaling them to YAML +func vals(valueFiles valueFiles, values []string, stringValues []string, fileValues []string, CertFile, KeyFile, CAFile string) ([]byte, error) { base := map[string]interface{}{} // User specified a values files via -f/--values @@ -345,7 +363,7 @@ func vals(valueFiles valueFiles, values []string, stringValues []string) ([]byte if strings.TrimSpace(filePath) == "-" { bytes, err = ioutil.ReadAll(os.Stdin) } else { - bytes, err = readFile(filePath) + bytes, err = readFile(filePath, CertFile, KeyFile, CAFile) } if err != nil { @@ -373,6 +391,17 @@ func vals(valueFiles valueFiles, values []string, stringValues []string) ([]byte } } + // User specified a value via --set-file + for _, value := range fileValues { + reader := func(rs []rune) (interface{}, error) { + bytes, err := readFile(string(rs), CertFile, KeyFile, CAFile) + return string(bytes), err + } + if err := strvals.ParseIntoFile(value, base, reader); err != nil { + return []byte{}, fmt.Errorf("failed parsing --set-file data: %s", err) + } + } + return yaml.Marshal(base) } @@ -463,7 +492,7 @@ func locateChartPath(repoURL, username, password, name, version string, verify b return filename, err } - return filename, fmt.Errorf("failed to download %q", name) + return filename, fmt.Errorf("failed to download %q (hint: running `helm repo update` may help)", name) } func generateName(nameTemplate string) (string, error) { @@ -480,7 +509,7 @@ func generateName(nameTemplate string) (string, error) { } func defaultNamespace() string { - if ns, _, err := kube.GetConfig(settings.KubeContext).Namespace(); err == nil { + if ns, _, err := kube.GetConfig(settings.KubeContext, settings.KubeConfig).Namespace(); err == nil { return ns } return "default" @@ -510,7 +539,7 @@ func checkDependencies(ch *chart.Chart, reqs *chartutil.Requirements) error { } //readFile load a file from the local directory or a remote file with a url. -func readFile(filePath string) ([]byte, error) { +func readFile(filePath, CertFile, KeyFile, CAFile string) ([]byte, error) { u, _ := url.Parse(filePath) p := getter.All(settings) @@ -521,7 +550,7 @@ func readFile(filePath string) ([]byte, error) { return ioutil.ReadFile(filePath) } - getter, err := getterConstructor(filePath, "", "", "") + getter, err := getterConstructor(filePath, CertFile, KeyFile, CAFile) if err != nil { return []byte{}, err } diff --git a/cmd/helm/install_test.go b/cmd/helm/install_test.go index aa828c6ce..48d9fc8c1 100644 --- a/cmd/helm/install_test.go +++ b/cmd/helm/install_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -115,6 +115,13 @@ func TestInstall(t *testing.T) { expected: "FOOBAR", resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "FOOBAR"}), }, + { + name: "install with custom description", + args: []string{"testdata/testcharts/alpine"}, + flags: []string{"--name", "virgil", "--description", "foobar"}, + expected: "virgil", + resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "virgil", Description: "foobar"}), + }, // Install, perform chart verification along the way. { name: "install with verification, missing provenance", diff --git a/cmd/helm/installer/install.go b/cmd/helm/installer/install.go index fc81fa26b..055601440 100644 --- a/cmd/helm/installer/install.go +++ b/cmd/helm/installer/install.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -28,6 +28,7 @@ import ( "k8s.io/api/extensions/v1beta1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/client-go/kubernetes" corev1 "k8s.io/client-go/kubernetes/typed/core/v1" @@ -73,7 +74,7 @@ func Upgrade(client kubernetes.Interface, opts *Options) error { if _, err := client.ExtensionsV1beta1().Deployments(opts.Namespace).Update(obj); err != nil { return err } - // If the service does not exists that would mean we are upgrading from a Tiller version + // If the service does not exist that would mean we are upgrading from a Tiller version // that didn't deploy the service, so install it. _, err = client.CoreV1().Services(opts.Namespace).Get(serviceName, metav1.GetOptions{}) if apierrors.IsNotFound(err) { @@ -104,7 +105,7 @@ func semverCompare(image string) int { // createDeployment creates the Tiller Deployment resource. func createDeployment(client extensionsclient.DeploymentsGetter, opts *Options) error { - obj, err := deployment(opts) + obj, err := generateDeployment(opts) if err != nil { return err } @@ -113,40 +114,68 @@ func createDeployment(client extensionsclient.DeploymentsGetter, opts *Options) } -// deployment gets the deployment object that installs Tiller. -func deployment(opts *Options) (*v1beta1.Deployment, error) { - return generateDeployment(opts) +// Deployment gets a deployment object that can be used to generate a manifest +// as a string. This object should not be submitted directly to the Kubernetes +// api +func Deployment(opts *Options) (*v1beta1.Deployment, error) { + dep, err := generateDeployment(opts) + if err != nil { + return nil, err + } + dep.TypeMeta = metav1.TypeMeta{ + Kind: "Deployment", + APIVersion: "extensions/v1beta1", + } + return dep, nil } // createService creates the Tiller service resource func createService(client corev1.ServicesGetter, namespace string) error { - obj := service(namespace) + obj := generateService(namespace) _, err := client.Services(obj.Namespace).Create(obj) return err } -// service gets the service object that installs Tiller. -func service(namespace string) *v1.Service { - return generateService(namespace) +// Service gets a service object that can be used to generate a manifest as a +// string. This object should not be submitted directly to the Kubernetes api +func Service(namespace string) *v1.Service { + svc := generateService(namespace) + svc.TypeMeta = metav1.TypeMeta{ + Kind: "Service", + APIVersion: "v1", + } + return svc } -// DeploymentManifest gets the manifest (as a string) that describes the Tiller Deployment -// resource. -func DeploymentManifest(opts *Options) (string, error) { - obj, err := deployment(opts) +// TillerManifests gets the Deployment, Service, and Secret (if tls-enabled) manifests +func TillerManifests(opts *Options) ([]string, error) { + dep, err := Deployment(opts) if err != nil { - return "", err + return []string{}, err + } + + svc := Service(opts.Namespace) + + objs := []runtime.Object{dep, svc} + + if opts.EnableTLS { + secret, err := Secret(opts) + if err != nil { + return []string{}, err + } + objs = append(objs, secret) + } + + manifests := make([]string, len(objs)) + for i, obj := range objs { + o, err := yaml.Marshal(obj) + if err != nil { + return []string{}, err + } + manifests[i] = string(o) } - buf, err := yaml.Marshal(obj) - return string(buf), err -} -// ServiceManifest gets the manifest (as a string) that describes the Tiller Service -// resource. -func ServiceManifest(namespace string) (string, error) { - obj := service(namespace) - buf, err := yaml.Marshal(obj) - return string(buf), err + return manifests, err } func generateLabels(labels map[string]string) map[string]string { @@ -321,14 +350,20 @@ func generateService(namespace string) *v1.Service { return s } -// SecretManifest gets the manifest (as a string) that describes the Tiller Secret resource. -func SecretManifest(opts *Options) (string, error) { - o, err := generateSecret(opts) +// Secret gets a secret object that can be used to generate a manifest as a +// string. This object should not be submitted directly to the Kubernetes api +func Secret(opts *Options) (*v1.Secret, error) { + secret, err := generateSecret(opts) if err != nil { - return "", err + return nil, err + } + + secret.TypeMeta = metav1.TypeMeta{ + Kind: "Secret", + APIVersion: "v1", } - buf, err := yaml.Marshal(o) - return string(buf), err + + return secret, nil } // createSecret creates the Tiller secret resource. diff --git a/cmd/helm/installer/install_test.go b/cmd/helm/installer/install_test.go index dbb7143e3..d5f3dfec0 100644 --- a/cmd/helm/installer/install_test.go +++ b/cmd/helm/installer/install_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -34,7 +34,7 @@ import ( "k8s.io/helm/pkg/version" ) -func TestDeploymentManifest(t *testing.T) { +func TestDeployment(t *testing.T) { tests := []struct { name string image string @@ -48,14 +48,10 @@ func TestDeploymentManifest(t *testing.T) { } for _, tt := range tests { - o, err := DeploymentManifest(&Options{Namespace: v1.NamespaceDefault, ImageSpec: tt.image, UseCanary: tt.canary}) + dep, err := Deployment(&Options{Namespace: v1.NamespaceDefault, ImageSpec: tt.image, UseCanary: tt.canary}) if err != nil { t.Fatalf("%s: error %q", tt.name, err) } - var dep v1beta1.Deployment - if err := yaml.Unmarshal([]byte(o), &dep); err != nil { - t.Fatalf("%s: error %q", tt.name, err) - } if got := dep.Spec.Template.Spec.Containers[0].Image; got != tt.expect { t.Errorf("%s: expected image %q, got %q", tt.name, tt.expect, got) @@ -71,7 +67,7 @@ func TestDeploymentManifest(t *testing.T) { } } -func TestDeploymentManifestForServiceAccount(t *testing.T) { +func TestDeploymentForServiceAccount(t *testing.T) { tests := []struct { name string image string @@ -84,22 +80,18 @@ func TestDeploymentManifestForServiceAccount(t *testing.T) { {"withoutSA", "", false, "gcr.io/kubernetes-helm/tiller:latest", "IfNotPresent", ""}, } for _, tt := range tests { - o, err := DeploymentManifest(&Options{Namespace: v1.NamespaceDefault, ImageSpec: tt.image, UseCanary: tt.canary, ServiceAccount: tt.serviceAccount}) + d, err := Deployment(&Options{Namespace: v1.NamespaceDefault, ImageSpec: tt.image, UseCanary: tt.canary, ServiceAccount: tt.serviceAccount}) if err != nil { t.Fatalf("%s: error %q", tt.name, err) } - var d v1beta1.Deployment - if err := yaml.Unmarshal([]byte(o), &d); err != nil { - t.Fatalf("%s: error %q", tt.name, err) - } if got := d.Spec.Template.Spec.ServiceAccountName; got != tt.serviceAccount { t.Errorf("%s: expected service account value %q, got %q", tt.name, tt.serviceAccount, got) } } } -func TestDeploymentManifest_WithTLS(t *testing.T) { +func TestDeployment_WithTLS(t *testing.T) { tests := []struct { opts Options name string @@ -126,15 +118,11 @@ func TestDeploymentManifest_WithTLS(t *testing.T) { }, } for _, tt := range tests { - o, err := DeploymentManifest(&tt.opts) + d, err := Deployment(&tt.opts) if err != nil { t.Fatalf("%s: error %q", tt.name, err) } - var d v1beta1.Deployment - if err := yaml.Unmarshal([]byte(o), &d); err != nil { - t.Fatalf("%s: error %q", tt.name, err) - } // verify environment variable in deployment reflect the use of tls being enabled. if got := d.Spec.Template.Spec.Containers[0].Env[2].Value; got != tt.verify { t.Errorf("%s: expected tls verify env value %q, got %q", tt.name, tt.verify, got) @@ -146,14 +134,7 @@ func TestDeploymentManifest_WithTLS(t *testing.T) { } func TestServiceManifest(t *testing.T) { - o, err := ServiceManifest(v1.NamespaceDefault) - if err != nil { - t.Fatalf("error %q", err) - } - var svc v1.Service - if err := yaml.Unmarshal([]byte(o), &svc); err != nil { - t.Fatalf("error %q", err) - } + svc := Service(v1.NamespaceDefault) if got := svc.ObjectMeta.Namespace; got != v1.NamespaceDefault { t.Errorf("expected namespace %s, got %s", v1.NamespaceDefault, got) @@ -161,7 +142,7 @@ func TestServiceManifest(t *testing.T) { } func TestSecretManifest(t *testing.T) { - o, err := SecretManifest(&Options{ + obj, err := Secret(&Options{ VerifyTLS: true, EnableTLS: true, Namespace: v1.NamespaceDefault, @@ -174,11 +155,6 @@ func TestSecretManifest(t *testing.T) { t.Fatalf("error %q", err) } - var obj v1.Secret - if err := yaml.Unmarshal([]byte(o), &obj); err != nil { - t.Fatalf("error %q", err) - } - if got := obj.ObjectMeta.Namespace; got != v1.NamespaceDefault { t.Errorf("expected namespace %s, got %s", v1.NamespaceDefault, got) } @@ -362,13 +338,13 @@ func TestInstall_canary(t *testing.T) { func TestUpgrade(t *testing.T) { image := "gcr.io/kubernetes-helm/tiller:v2.0.0" serviceAccount := "newServiceAccount" - existingDeployment, _ := deployment(&Options{ + existingDeployment, _ := generateDeployment(&Options{ Namespace: v1.NamespaceDefault, ImageSpec: "imageToReplace:v1.0.0", ServiceAccount: "serviceAccountToReplace", UseCanary: false, }) - existingService := service(v1.NamespaceDefault) + existingService := generateService(v1.NamespaceDefault) fc := &fake.Clientset{} fc.AddReactor("get", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { @@ -403,7 +379,7 @@ func TestUpgrade(t *testing.T) { func TestUpgrade_serviceNotFound(t *testing.T) { image := "gcr.io/kubernetes-helm/tiller:v2.0.0" - existingDeployment, _ := deployment(&Options{ + existingDeployment, _ := generateDeployment(&Options{ Namespace: v1.NamespaceDefault, ImageSpec: "imageToReplace", UseCanary: false, @@ -446,13 +422,13 @@ func TestUpgrade_serviceNotFound(t *testing.T) { func TestUgrade_newerVersion(t *testing.T) { image := "gcr.io/kubernetes-helm/tiller:v2.0.0" serviceAccount := "newServiceAccount" - existingDeployment, _ := deployment(&Options{ + existingDeployment, _ := generateDeployment(&Options{ Namespace: v1.NamespaceDefault, ImageSpec: "imageToReplace:v100.5.0", ServiceAccount: "serviceAccountToReplace", UseCanary: false, }) - existingService := service(v1.NamespaceDefault) + existingService := generateService(v1.NamespaceDefault) fc := &fake.Clientset{} fc.AddReactor("get", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { @@ -506,13 +482,13 @@ func TestUgrade_newerVersion(t *testing.T) { func TestUpgrade_identical(t *testing.T) { image := "gcr.io/kubernetes-helm/tiller:v2.0.0" serviceAccount := "newServiceAccount" - existingDeployment, _ := deployment(&Options{ + existingDeployment, _ := generateDeployment(&Options{ Namespace: v1.NamespaceDefault, ImageSpec: "imageToReplace:v2.0.0", ServiceAccount: "serviceAccountToReplace", UseCanary: false, }) - existingService := service(v1.NamespaceDefault) + existingService := generateService(v1.NamespaceDefault) fc := &fake.Clientset{} fc.AddReactor("get", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { @@ -547,13 +523,13 @@ func TestUpgrade_identical(t *testing.T) { func TestUpgrade_canaryClient(t *testing.T) { image := "gcr.io/kubernetes-helm/tiller:canary" serviceAccount := "newServiceAccount" - existingDeployment, _ := deployment(&Options{ + existingDeployment, _ := generateDeployment(&Options{ Namespace: v1.NamespaceDefault, ImageSpec: "imageToReplace:v1.0.0", ServiceAccount: "serviceAccountToReplace", UseCanary: false, }) - existingService := service(v1.NamespaceDefault) + existingService := generateService(v1.NamespaceDefault) fc := &fake.Clientset{} fc.AddReactor("get", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { @@ -588,13 +564,13 @@ func TestUpgrade_canaryClient(t *testing.T) { func TestUpgrade_canaryServer(t *testing.T) { image := "gcr.io/kubernetes-helm/tiller:v2.0.0" serviceAccount := "newServiceAccount" - existingDeployment, _ := deployment(&Options{ + existingDeployment, _ := generateDeployment(&Options{ Namespace: v1.NamespaceDefault, ImageSpec: "imageToReplace:canary", ServiceAccount: "serviceAccountToReplace", UseCanary: false, }) - existingService := service(v1.NamespaceDefault) + existingService := generateService(v1.NamespaceDefault) fc := &fake.Clientset{} fc.AddReactor("get", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { @@ -634,7 +610,8 @@ func tlsTestFile(t *testing.T, path string) string { } return path } -func TestDeploymentManifest_WithNodeSelectors(t *testing.T) { + +func TestDeployment_WithNodeSelectors(t *testing.T) { tests := []struct { opts Options name string @@ -658,15 +635,11 @@ func TestDeploymentManifest_WithNodeSelectors(t *testing.T) { }, } for _, tt := range tests { - o, err := DeploymentManifest(&tt.opts) + d, err := Deployment(&tt.opts) if err != nil { t.Fatalf("%s: error %q", tt.name, err) } - var d v1beta1.Deployment - if err := yaml.Unmarshal([]byte(o), &d); err != nil { - t.Fatalf("%s: error %q", tt.name, err) - } // Verify that environment variables in Deployment reflect the use of TLS being enabled. got := d.Spec.Template.Spec.NodeSelector for k, v := range tt.expect { @@ -676,7 +649,8 @@ func TestDeploymentManifest_WithNodeSelectors(t *testing.T) { } } } -func TestDeploymentManifest_WithSetValues(t *testing.T) { + +func TestDeployment_WithSetValues(t *testing.T) { tests := []struct { opts Options name string @@ -703,11 +677,17 @@ func TestDeploymentManifest_WithSetValues(t *testing.T) { }, } for _, tt := range tests { - o, err := DeploymentManifest(&tt.opts) + d, err := Deployment(&tt.opts) if err != nil { t.Fatalf("%s: error %q", tt.name, err) } - values, err := chartutil.ReadValues([]byte(o)) + + o, err := yaml.Marshal(d) + if err != nil { + t.Errorf("Error marshaling Deployment: %s", err) + } + + values, err := chartutil.ReadValues(o) if err != nil { t.Errorf("Error converting Deployment manifest to Values: %s", err) } diff --git a/cmd/helm/installer/options.go b/cmd/helm/installer/options.go index 13cf43dcc..95aa3988d 100644 --- a/cmd/helm/installer/options.go +++ b/cmd/helm/installer/options.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -50,7 +50,7 @@ type Options struct { // Force allows to force upgrading tiller if deployed version is greater than current version ForceUpgrade bool - // ImageSpec indentifies the image Tiller will use when deployed. + // ImageSpec identifies the image Tiller will use when deployed. // // Valid if and only if UseCanary is false. ImageSpec string diff --git a/cmd/helm/installer/uninstall.go b/cmd/helm/installer/uninstall.go index 818827ddb..54e79bdf4 100644 --- a/cmd/helm/installer/uninstall.go +++ b/cmd/helm/installer/uninstall.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -19,10 +19,8 @@ package installer // import "k8s.io/helm/cmd/helm/installer" import ( apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion" - "k8s.io/kubernetes/pkg/kubectl" ) const ( @@ -52,8 +50,7 @@ func deleteService(client coreclient.ServicesGetter, namespace string) error { // We need to use the reaper instead of the kube API because GC for deployment dependents // is not yet supported at the k8s server level (<= 1.5) func deleteDeployment(client internalclientset.Interface, namespace string) error { - reaper, _ := kubectl.ReaperFor(extensions.Kind("Deployment"), client) - err := reaper.Stop(namespace, deploymentName, 0, nil) + err := client.Extensions().Deployments(namespace).Delete(deploymentName, &metav1.DeleteOptions{}) return ingoreNotFound(err) } diff --git a/cmd/helm/installer/uninstall_test.go b/cmd/helm/installer/uninstall_test.go index 91b257d47..7e5be8aaa 100644 --- a/cmd/helm/installer/uninstall_test.go +++ b/cmd/helm/installer/uninstall_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -34,8 +34,8 @@ func TestUninstall(t *testing.T) { t.Errorf("unexpected error: %#+v", err) } - if actions := fc.Actions(); len(actions) != 7 { - t.Errorf("unexpected actions: %v, expected 7 actions got %d", actions, len(actions)) + if actions := fc.Actions(); len(actions) != 3 { + t.Errorf("unexpected actions: %v, expected 3 actions got %d", actions, len(actions)) } } @@ -50,8 +50,8 @@ func TestUninstall_serviceNotFound(t *testing.T) { t.Errorf("unexpected error: %#+v", err) } - if actions := fc.Actions(); len(actions) != 7 { - t.Errorf("unexpected actions: %v, expected 7 actions got %d", actions, len(actions)) + if actions := fc.Actions(); len(actions) != 3 { + t.Errorf("unexpected actions: %v, expected 3 actions got %d", actions, len(actions)) } } @@ -66,8 +66,8 @@ func TestUninstall_deploymentNotFound(t *testing.T) { t.Errorf("unexpected error: %#+v", err) } - if actions := fc.Actions(); len(actions) != 7 { - t.Errorf("unexpected actions: %v, expected 7 actions got %d", actions, len(actions)) + if actions := fc.Actions(); len(actions) != 3 { + t.Errorf("unexpected actions: %v, expected 3 actions got %d", actions, len(actions)) } } @@ -82,7 +82,7 @@ func TestUninstall_secretNotFound(t *testing.T) { t.Errorf("unexpected error: %#+v", err) } - if actions := fc.Actions(); len(actions) != 7 { - t.Errorf("unexpected actions: %v, expect 7 actions got %d", actions, len(actions)) + if actions := fc.Actions(); len(actions) != 3 { + t.Errorf("unexpected actions: %v, expect 3 actions got %d", actions, len(actions)) } } diff --git a/cmd/helm/lint.go b/cmd/helm/lint.go index 6e08f2747..d0159d34b 100644 --- a/cmd/helm/lint.go +++ b/cmd/helm/lint.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -47,6 +47,7 @@ type lintCmd struct { valueFiles valueFiles values []string sValues []string + fValues []string namespace string strict bool paths []string @@ -73,7 +74,8 @@ func newLintCmd(out io.Writer) *cobra.Command { cmd.Flags().VarP(&l.valueFiles, "values", "f", "specify values in a YAML file (can specify multiple)") cmd.Flags().StringArrayVar(&l.values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)") cmd.Flags().StringArrayVar(&l.sValues, "set-string", []string{}, "set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)") - cmd.Flags().StringVar(&l.namespace, "namespace", "default", "namespace to install the release into (only used if --install is set)") + cmd.Flags().StringArrayVar(&l.fValues, "set-file", []string{}, "set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2)") + cmd.Flags().StringVar(&l.namespace, "namespace", "default", "namespace to put the release into") cmd.Flags().BoolVar(&l.strict, "strict", false, "fail on lint warnings") return cmd @@ -101,6 +103,9 @@ func (l *lintCmd) run() error { if linter, err := lintChart(path, rvals, l.namespace, l.strict); err != nil { fmt.Println("==> Skipping", path) fmt.Println(err) + if err == errLintNoChart { + failures = failures + 1 + } } else { fmt.Println("==> Linting", path) @@ -169,6 +174,12 @@ func lintChart(path string, vals []byte, namespace string, strict bool) (support return lint.All(chartPath, vals, namespace, strict), nil } +// vals merges values from files specified via -f/--values and +// directly via --set or --set-string or --set-file, marshaling them to YAML +// +// This func is implemented intentionally and separately from the `vals` func for the `install` and `upgrade` comammdsn. +// Compared to the alternative func, this func lacks the parameters for tls opts - ca key, cert, and ca cert. +// That's because this command, `lint`, is explicitly forbidden from making server connections. func (l *lintCmd) vals() ([]byte, error) { base := map[string]interface{}{} @@ -201,5 +212,16 @@ func (l *lintCmd) vals() ([]byte, error) { } } + // User specified a value via --set-file + for _, value := range l.fValues { + reader := func(rs []rune) (interface{}, error) { + bytes, err := ioutil.ReadFile(string(rs)) + return string(bytes), err + } + if err := strvals.ParseIntoFile(value, base, reader); err != nil { + return []byte{}, fmt.Errorf("failed parsing --set-file data: %s", err) + } + } + return yaml.Marshal(base) } diff --git a/cmd/helm/lint_test.go b/cmd/helm/lint_test.go index 7f045153c..67775893b 100644 --- a/cmd/helm/lint_test.go +++ b/cmd/helm/lint_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -28,6 +28,7 @@ var ( archivedChartPathWithHyphens = "testdata/testcharts/compressedchart-with-hyphens-0.1.0.tgz" invalidArchivedChartPath = "testdata/testcharts/invalidcompressedchart0.1.0.tgz" chartDirPath = "testdata/testcharts/decompressedchart/" + chartMissingManifest = "testdata/testcharts/chart-missing-manifest" ) func TestLintChart(t *testing.T) { @@ -46,4 +47,8 @@ func TestLintChart(t *testing.T) { if _, err := lintChart(invalidArchivedChartPath, values, namespace, strict); err == nil { t.Errorf("Expected a chart parsing error") } + + if _, err := lintChart(chartMissingManifest, values, namespace, strict); err == nil { + t.Errorf("Expected a chart parsing error") + } } diff --git a/cmd/helm/list.go b/cmd/helm/list.go index 0219d60f2..ed70702d5 100644 --- a/cmd/helm/list.go +++ b/cmd/helm/list.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -17,10 +17,12 @@ limitations under the License. package main import ( + "encoding/json" "fmt" "io" "strings" + "github.com/ghodss/yaml" "github.com/gosuri/uitable" "github.com/spf13/cobra" @@ -75,6 +77,22 @@ type listCmd struct { pending bool client helm.Interface colWidth uint + output string +} + +type listResult struct { + Next string + Releases []listRelease +} + +type listRelease struct { + Name string + Revision int32 + Updated string + Status string + Chart string + AppVersion string + Namespace string } func newListCmd(client helm.Interface, out io.Writer) *cobra.Command { @@ -114,6 +132,7 @@ func newListCmd(client helm.Interface, out io.Writer) *cobra.Command { f.BoolVar(&list.pending, "pending", false, "show pending releases") f.StringVar(&list.namespace, "namespace", "", "show releases within a specific namespace") f.UintVar(&list.colWidth, "col-width", 60, "specifies the max column width of output") + f.StringVar(&list.output, "output", "", "output the specified format (json or yaml)") // TODO: Do we want this as a feature of 'helm list'? //f.BoolVar(&list.superseded, "history", true, "show historical releases") @@ -147,24 +166,21 @@ func (l *listCmd) run() error { if err != nil { return prettyError(err) } - - if len(res.Releases) == 0 { + if res == nil { return nil } - if res.Next != "" && !l.short { - fmt.Fprintf(l.out, "\tnext: %s\n", res.Next) - } + rels := filterList(res.GetReleases()) - rels := filterList(res.Releases) + result := getListResult(rels, res.Next) - if l.short { - for _, r := range rels { - fmt.Fprintln(l.out, r.Name) - } - return nil + output, err := formatResult(l.output, l.short, result, l.colWidth) + + if err != nil { + return prettyError(err) } - fmt.Fprintln(l.out, formatList(rels, l.colWidth)) + + fmt.Fprintln(l.out, output) return nil } @@ -233,18 +249,98 @@ func (l *listCmd) statusCodes() []release.Status_Code { return status } -func formatList(rels []*release.Release, colWidth uint) string { - table := uitable.New() +func getListResult(rels []*release.Release, next string) listResult { + listReleases := []listRelease{} + for _, r := range rels { + md := r.GetChart().GetMetadata() + t := "-" + if tspb := r.GetInfo().GetLastDeployed(); tspb != nil { + t = timeconv.String(tspb) + } + + lr := listRelease{ + Name: r.GetName(), + Revision: r.GetVersion(), + Updated: t, + Status: r.GetInfo().GetStatus().GetCode().String(), + Chart: fmt.Sprintf("%s-%s", md.GetName(), md.GetVersion()), + AppVersion: md.GetAppVersion(), + Namespace: r.GetNamespace(), + } + listReleases = append(listReleases, lr) + } + + return listResult{ + Releases: listReleases, + Next: next, + } +} +func shortenListResult(result listResult) []string { + names := []string{} + for _, r := range result.Releases { + names = append(names, r.Name) + } + + return names +} + +func formatResult(format string, short bool, result listResult, colWidth uint) (string, error) { + var output string + var err error + + var shortResult []string + var finalResult interface{} + if short { + shortResult = shortenListResult(result) + finalResult = shortResult + } else { + finalResult = result + } + + switch format { + case "": + if short { + output = formatTextShort(shortResult) + } else { + output = formatText(result, colWidth) + } + case "json": + o, e := json.Marshal(finalResult) + if e != nil { + err = fmt.Errorf("Failed to Marshal JSON output: %s", e) + } else { + output = string(o) + } + case "yaml": + o, e := yaml.Marshal(finalResult) + if e != nil { + err = fmt.Errorf("Failed to Marshal YAML output: %s", e) + } else { + output = string(o) + } + default: + err = fmt.Errorf("Unknown output format \"%s\"", format) + } + return output, err +} + +func formatText(result listResult, colWidth uint) string { + nextOutput := "" + if result.Next != "" { + nextOutput = fmt.Sprintf("\tnext: %s\n", result.Next) + } + + table := uitable.New() table.MaxColWidth = colWidth - table.AddRow("NAME", "REVISION", "UPDATED", "STATUS", "CHART", "NAMESPACE") - for _, r := range rels { - c := fmt.Sprintf("%s-%s", r.Chart.Metadata.Name, r.Chart.Metadata.Version) - t := timeconv.String(r.Info.LastDeployed) - s := r.Info.Status.Code.String() - v := r.Version - n := r.Namespace - table.AddRow(r.Name, v, t, s, c, n) - } - return table.String() + table.AddRow("NAME", "REVISION", "UPDATED", "STATUS", "CHART", "APP VERSION", "NAMESPACE") + for _, lr := range result.Releases { + table.AddRow(lr.Name, lr.Revision, lr.Updated, lr.Status, lr.Chart, lr.AppVersion, lr.Namespace) + } + + return fmt.Sprintf("%s%s", nextOutput, table.String()) +} + +func formatTextShort(shortResult []string) string { + return strings.Join(shortResult, "\n") } diff --git a/cmd/helm/list_test.go b/cmd/helm/list_test.go index d853fa6b1..934f10712 100644 --- a/cmd/helm/list_test.go +++ b/cmd/helm/list_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -18,16 +18,41 @@ package main import ( "io" + "regexp" "testing" "github.com/spf13/cobra" + "io/ioutil" + "os" + + "k8s.io/helm/pkg/chartutil" "k8s.io/helm/pkg/helm" + "k8s.io/helm/pkg/proto/hapi/chart" "k8s.io/helm/pkg/proto/hapi/release" ) func TestListCmd(t *testing.T) { + tmpChart, _ := ioutil.TempDir("testdata", "tmp") + defer os.RemoveAll(tmpChart) + cfile := &chart.Metadata{ + Name: "foo", + Description: "A Helm chart for Kubernetes", + Version: "0.1.0-beta.1", + AppVersion: "2.X.A", + } + chartPath, err := chartutil.Create(cfile, tmpChart) + if err != nil { + t.Errorf("Error creating chart for list: %v", err) + } + ch, _ := chartutil.Load(chartPath) + tests := []releaseCase{ + { + name: "empty", + rels: []*release.Release{}, + expected: "", + }, { name: "with a release", rels: []*release.Release{ @@ -40,7 +65,85 @@ func TestListCmd(t *testing.T) { rels: []*release.Release{ helm.ReleaseMock(&helm.MockReleaseOptions{Name: "atlas"}), }, - expected: "NAME \tREVISION\tUPDATED \tSTATUS \tCHART \tNAMESPACE\natlas\t1 \t(.*)\tDEPLOYED\tfoo-0.1.0-beta.1\tdefault \n", + expected: "NAME \tREVISION\tUPDATED \tSTATUS \tCHART \tAPP VERSION\tNAMESPACE\natlas\t1 \t(.*)\tDEPLOYED\tfoo-0.1.0-beta.1\t \tdefault \n", + }, + { + name: "list with appVersion", + rels: []*release.Release{ + helm.ReleaseMock(&helm.MockReleaseOptions{Name: "atlas", Chart: ch}), + }, + expected: "NAME \tREVISION\tUPDATED \tSTATUS \tCHART \tAPP VERSION\tNAMESPACE\natlas\t1 \t(.*)\tDEPLOYED\tfoo-0.1.0-beta.1\t2.X.A \tdefault \n", + }, + { + name: "with json output", + flags: []string{"--max", "1", "--output", "json"}, + rels: []*release.Release{ + helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide"}), + helm.ReleaseMock(&helm.MockReleaseOptions{Name: "atlas-guide"}), + }, + expected: regexp.QuoteMeta(`{"Next":"atlas-guide","Releases":[{"Name":"thomas-guide","Revision":1,"Updated":"`) + `([^"]*)` + regexp.QuoteMeta(`","Status":"DEPLOYED","Chart":"foo-0.1.0-beta.1","AppVersion":"","Namespace":"default"}]} +`), + }, + { + name: "with yaml output", + flags: []string{"--max", "1", "--output", "yaml"}, + rels: []*release.Release{ + helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide"}), + helm.ReleaseMock(&helm.MockReleaseOptions{Name: "atlas-guide"}), + }, + expected: regexp.QuoteMeta(`Next: atlas-guide +Releases: +- AppVersion: "" + Chart: foo-0.1.0-beta.1 + Name: thomas-guide + Namespace: default + Revision: 1 + Status: DEPLOYED + Updated: `) + `(.*)` + ` + +`, + }, + { + name: "with short json output", + flags: []string{"-q", "--output", "json"}, + rels: []*release.Release{ + helm.ReleaseMock(&helm.MockReleaseOptions{Name: "atlas"}), + }, + expected: regexp.QuoteMeta(`["atlas"] +`), + }, + { + name: "with short yaml output", + flags: []string{"-q", "--output", "yaml"}, + rels: []*release.Release{ + helm.ReleaseMock(&helm.MockReleaseOptions{Name: "atlas"}), + }, + expected: regexp.QuoteMeta(`- atlas + +`), + }, + { + name: "with json output without next", + flags: []string{"--output", "json"}, + rels: []*release.Release{}, + expected: regexp.QuoteMeta(`{"Next":"","Releases":[]} +`), + }, + { + name: "with yaml output without next", + flags: []string{"--output", "yaml"}, + rels: []*release.Release{}, + expected: regexp.QuoteMeta(`Next: "" +Releases: [] + +`), + }, + { + name: "with unknown output format", + flags: []string{"--output", "_unknown_"}, + rels: []*release.Release{}, + err: true, + expected: regexp.QuoteMeta(``), }, { name: "list, one deployed, one failed", diff --git a/cmd/helm/load_plugins.go b/cmd/helm/load_plugins.go index ef24e7883..158a69c88 100644 --- a/cmd/helm/load_plugins.go +++ b/cmd/helm/load_plugins.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 @@ -22,12 +22,18 @@ import ( "os/exec" "path/filepath" "strings" + "syscall" "github.com/spf13/cobra" "k8s.io/helm/pkg/plugin" ) +type pluginError struct { + error + code int +} + // loadPlugins loads plugins into the command list. // // This follows a different pattern than the other commands because it has @@ -87,7 +93,11 @@ func loadPlugins(baseCmd *cobra.Command, out io.Writer) { if err := prog.Run(); err != nil { if eerr, ok := err.(*exec.ExitError); ok { os.Stderr.Write(eerr.Stderr) - return fmt.Errorf("plugin %q exited with error", md.Name) + status := eerr.Sys().(syscall.WaitStatus) + return pluginError{ + error: fmt.Errorf("plugin %q exited with error", md.Name), + code: status.ExitStatus(), + } } return err } @@ -131,7 +141,7 @@ func manuallyProcessArgs(args []string) ([]string, []string) { switch a := args[i]; a { case "--debug": known = append(known, a) - case "--host", "--kube-context", "--home": + case "--host", "--kube-context", "--home", "--tiller-namespace": known = append(known, a, args[i+1]) i++ default: diff --git a/cmd/helm/package.go b/cmd/helm/package.go index ed44382c7..81603e67b 100644 --- a/cmd/helm/package.go +++ b/cmd/helm/package.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/helm/package_test.go b/cmd/helm/package_test.go index 4404586e0..7ed9829a5 100644 --- a/cmd/helm/package_test.go +++ b/cmd/helm/package_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/cmd/helm/plugin.go b/cmd/helm/plugin.go index cf0b02f09..fbdd1245b 100644 --- a/cmd/helm/plugin.go +++ b/cmd/helm/plugin.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/cmd/helm/plugin_install.go b/cmd/helm/plugin_install.go index f36178808..7d77be3fc 100644 --- a/cmd/helm/plugin_install.go +++ b/cmd/helm/plugin_install.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/cmd/helm/plugin_list.go b/cmd/helm/plugin_list.go index e7618f38a..9693baaa2 100644 --- a/cmd/helm/plugin_list.go +++ b/cmd/helm/plugin_list.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/cmd/helm/plugin_remove.go b/cmd/helm/plugin_remove.go index ec1154734..f30e5b516 100644 --- a/cmd/helm/plugin_remove.go +++ b/cmd/helm/plugin_remove.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/cmd/helm/plugin_test.go b/cmd/helm/plugin_test.go index 2a4a0e9aa..2d06c3797 100644 --- a/cmd/helm/plugin_test.go +++ b/cmd/helm/plugin_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/cmd/helm/plugin_update.go b/cmd/helm/plugin_update.go index d3778764d..f9d5a3fac 100644 --- a/cmd/helm/plugin_update.go +++ b/cmd/helm/plugin_update.go @@ -1,5 +1,5 @@ /* -Copyright 2017 The Kubernetes Authors All rights reserved. +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 diff --git a/cmd/helm/printer.go b/cmd/helm/printer.go index ebb24bf7d..e98b71c64 100644 --- a/cmd/helm/printer.go +++ b/cmd/helm/printer.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/helm/release_testing.go b/cmd/helm/release_testing.go index bdfa87a60..0c9debb3f 100644 --- a/cmd/helm/release_testing.go +++ b/cmd/helm/release_testing.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/helm/release_testing_test.go b/cmd/helm/release_testing_test.go index 02ab1883c..f4f64c16d 100644 --- a/cmd/helm/release_testing_test.go +++ b/cmd/helm/release_testing_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -17,55 +17,50 @@ limitations under the License. package main import ( - "bytes" + "io" "testing" + "github.com/spf13/cobra" "k8s.io/helm/pkg/helm" "k8s.io/helm/pkg/proto/hapi/release" ) func TestReleaseTesting(t *testing.T) { - tests := []struct { - name string - args []string - flags []string - responses map[string]release.TestRun_Status - fail bool - }{ + tests := []releaseCase{ { name: "basic test", args: []string{"example-release"}, flags: []string{}, responses: map[string]release.TestRun_Status{"PASSED: green lights everywhere": release.TestRun_SUCCESS}, - fail: false, + err: false, }, { name: "test failure", args: []string{"example-fail"}, flags: []string{}, responses: map[string]release.TestRun_Status{"FAILURE: red lights everywhere": release.TestRun_FAILURE}, - fail: true, + err: true, }, { name: "test unknown", args: []string{"example-unknown"}, flags: []string{}, responses: map[string]release.TestRun_Status{"UNKNOWN: yellow lights everywhere": release.TestRun_UNKNOWN}, - fail: false, + err: false, }, { name: "test error", args: []string{"example-error"}, flags: []string{}, responses: map[string]release.TestRun_Status{"ERROR: yellow lights everywhere": release.TestRun_FAILURE}, - fail: true, + err: true, }, { name: "test running", args: []string{"example-running"}, flags: []string{}, responses: map[string]release.TestRun_Status{"RUNNING: things are happpeningggg": release.TestRun_RUNNING}, - fail: false, + err: false, }, { name: "multiple tests example", @@ -78,29 +73,11 @@ func TestReleaseTesting(t *testing.T) { "FAILURE: good thing u checked :)": release.TestRun_FAILURE, "RUNNING: things are happpeningggg yet again": release.TestRun_RUNNING, "PASSED: feel free to party again": release.TestRun_SUCCESS}, - fail: true, + err: true, }, } - for _, tt := range tests { - c := &helm.FakeClient{Responses: tt.responses} - - buf := bytes.NewBuffer(nil) - cmd := newReleaseTestCmd(c, buf) - cmd.ParseFlags(tt.flags) - - err := cmd.RunE(cmd, tt.args) - if err == nil && tt.fail { - t.Errorf("%q did not fail but should have failed", tt.name) - } - - if err != nil { - if tt.fail { - continue - } else { - t.Errorf("%q reported error: %s", tt.name, err) - } - } - - } + runReleaseCases(t, tests, func(c *helm.FakeClient, out io.Writer) *cobra.Command { + return newReleaseTestCmd(c, out) + }) } diff --git a/cmd/helm/repo.go b/cmd/helm/repo.go index 8acc762e2..9f1dc8928 100644 --- a/cmd/helm/repo.go +++ b/cmd/helm/repo.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/helm/repo_add.go b/cmd/helm/repo_add.go index 77a64cc89..bfb3f0174 100644 --- a/cmd/helm/repo_add.go +++ b/cmd/helm/repo_add.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -22,9 +22,11 @@ import ( "github.com/spf13/cobra" + "golang.org/x/crypto/ssh/terminal" "k8s.io/helm/pkg/getter" "k8s.io/helm/pkg/helm/helmpath" "k8s.io/helm/pkg/repo" + "syscall" ) type repoAddCmd struct { @@ -73,6 +75,16 @@ func newRepoAddCmd(out io.Writer) *cobra.Command { } func (a *repoAddCmd) run() error { + if a.username != "" && a.password == "" { + fmt.Fprint(a.out, "Password:") + password, err := readPassword() + fmt.Fprintln(a.out) + if err != nil { + return err + } + a.password = password + } + if err := addRepository(a.name, a.url, a.username, a.password, a.home, a.certFile, a.keyFile, a.caFile, a.noupdate); err != nil { return err } @@ -80,6 +92,14 @@ func (a *repoAddCmd) run() error { return nil } +func readPassword() (string, error) { + password, err := terminal.ReadPassword(int(syscall.Stdin)) + if err != nil { + return "", err + } + return string(password), nil +} + func addRepository(name, url, username, password string, home helmpath.Home, certFile, keyFile, caFile string, noUpdate bool) error { f, err := repo.LoadRepositoriesFile(home.RepositoryFile()) if err != nil { diff --git a/cmd/helm/repo_add_test.go b/cmd/helm/repo_add_test.go index 157b1cc5b..5a458cef7 100644 --- a/cmd/helm/repo_add_test.go +++ b/cmd/helm/repo_add_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/helm/repo_index.go b/cmd/helm/repo_index.go index 95e4b8aac..b3f49fb97 100644 --- a/cmd/helm/repo_index.go +++ b/cmd/helm/repo_index.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -19,6 +19,7 @@ package main import ( "fmt" "io" + "os" "path/filepath" "github.com/spf13/cobra" @@ -86,12 +87,19 @@ func index(dir, url, mergeTo string) error { return err } if mergeTo != "" { - i2, err := repo.LoadIndexFile(mergeTo) - if err != nil { - return fmt.Errorf("Merge failed: %s", err) + // if index.yaml is missing then create an empty one to merge into + var i2 *repo.IndexFile + if _, err := os.Stat(mergeTo); os.IsNotExist(err) { + i2 = repo.NewIndexFile() + i2.WriteFile(mergeTo, 0644) + } else { + i2, err = repo.LoadIndexFile(mergeTo) + if err != nil { + return fmt.Errorf("Merge failed: %s", err) + } } i.Merge(i2) } i.SortEntries() - return i.WriteFile(out, 0755) + return i.WriteFile(out, 0644) } diff --git a/cmd/helm/repo_index_test.go b/cmd/helm/repo_index_test.go index bd1010dd7..0d5571ef7 100644 --- a/cmd/helm/repo_index_test.go +++ b/cmd/helm/repo_index_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -112,6 +112,36 @@ func TestRepoIndexCmd(t *testing.T) { if vs[0].Version != expectedVersion { t.Errorf("expected %q, got %q", expectedVersion, vs[0].Version) } + + // test that index.yaml gets generated on merge even when it doesn't exist + if err := os.Remove(destIndex); err != nil { + t.Fatal(err) + } + + c.ParseFlags([]string{"--merge", destIndex}) + if err := c.RunE(c, []string{dir}); err != nil { + t.Error(err) + } + + _, err = repo.LoadIndexFile(destIndex) + if err != nil { + t.Fatal(err) + } + + // verify it didn't create an empty index.yaml and the merged happened + if len(index.Entries) != 2 { + t.Errorf("expected 2 entries, got %d: %#v", len(index.Entries), index.Entries) + } + + vs = index.Entries["compressedchart"] + if len(vs) != 3 { + t.Errorf("expected 3 versions, got %d: %#v", len(vs), vs) + } + + expectedVersion = "0.3.0" + if vs[0].Version != expectedVersion { + t.Errorf("expected %q, got %q", expectedVersion, vs[0].Version) + } } func linkOrCopy(old, new string) error { diff --git a/cmd/helm/repo_list.go b/cmd/helm/repo_list.go index 0f795b2b0..36887c69b 100644 --- a/cmd/helm/repo_list.go +++ b/cmd/helm/repo_list.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/helm/repo_remove.go b/cmd/helm/repo_remove.go index 201ee9ca8..f13b8dadb 100644 --- a/cmd/helm/repo_remove.go +++ b/cmd/helm/repo_remove.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -41,13 +41,18 @@ func newRepoRemoveCmd(out io.Writer) *cobra.Command { Aliases: []string{"rm"}, Short: "remove a chart repository", RunE: func(cmd *cobra.Command, args []string) error { - if err := checkArgsLength(len(args), "name of chart repository"); err != nil { - return err + if len(args) == 0 { + return fmt.Errorf("need at least one argument, name of chart repository") } - remove.name = args[0] - remove.home = settings.Home - return remove.run() + remove.home = settings.Home + for i := 0; i < len(args); i++ { + remove.name = args[i] + if err := remove.run(); err != nil { + return err + } + } + return nil }, } diff --git a/cmd/helm/repo_remove_test.go b/cmd/helm/repo_remove_test.go index 174a44495..f52c3afc4 100644 --- a/cmd/helm/repo_remove_test.go +++ b/cmd/helm/repo_remove_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -18,6 +18,7 @@ package main import ( "bytes" + "io/ioutil" "os" "strings" "testing" @@ -79,3 +80,66 @@ func TestRepoRemove(t *testing.T) { t.Errorf("%s was not successfully removed from repositories list", testName) } } + +func TestRepoRemove_NoArguments(t *testing.T) { + cmd := newRepoRemoveCmd(ioutil.Discard) + if err := cmd.RunE(cmd, []string{}); err == nil { + t.Errorf("Expected an error since no repo names were provided") + } +} + +func TestRepoRemove_MultipleRepos(t *testing.T) { + ts, thome, err := repotest.NewTempServer("testdata/testserver/*.*") + if err != nil { + t.Fatal(err) + } + + hh := helmpath.Home(thome) + cleanup := resetEnv() + defer func() { + ts.Stop() + os.RemoveAll(thome.String()) + cleanup() + }() + if err := ensureTestHome(hh, t); err != nil { + t.Fatal(err) + } + + settings.Home = thome + + repoFoo := testName + "foo" + repoBar := testName + "bar" + + if err := addRepository(repoFoo, ts.URL(), "", "", hh, "", "", "", true); err != nil { + t.Error(err) + } + if err := addRepository(repoBar, ts.URL(), "", "", hh, "", "", "", true); err != nil { + t.Error(err) + } + + b := bytes.NewBuffer(nil) + + cmd := newRepoRemoveCmd(b) + if err := cmd.RunE(cmd, []string{repoFoo, repoBar}); err != nil { + t.Error(err) + } + + if !strings.Contains(b.String(), repoFoo) { + t.Errorf("Expected %q in output, found: %q", repoFoo, b.String()) + } + if !strings.Contains(b.String(), repoBar) { + t.Errorf("Expected %q in output, found: %q", repoBar, b.String()) + } + + f, err := repo.LoadRepositoriesFile(hh.RepositoryFile()) + if err != nil { + t.Error(err) + } + + if f.Has(repoFoo) { + t.Errorf("%s was not successfully removed from repositories list", repoFoo) + } + if f.Has(repoBar) { + t.Errorf("%s was not successfully removed from repositories list", repoBar) + } +} diff --git a/cmd/helm/repo_update.go b/cmd/helm/repo_update.go index 51e5c0868..291b21b72 100644 --- a/cmd/helm/repo_update.go +++ b/cmd/helm/repo_update.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/helm/repo_update_test.go b/cmd/helm/repo_update_test.go index 68f964f32..71dc87966 100644 --- a/cmd/helm/repo_update_test.go +++ b/cmd/helm/repo_update_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/cmd/helm/reset.go b/cmd/helm/reset.go index 9d3e17e03..5b0914e82 100644 --- a/cmd/helm/reset.go +++ b/cmd/helm/reset.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -86,7 +86,7 @@ func newResetCmd(client helm.Interface, out io.Writer) *cobra.Command { // runReset uninstalls tiller from Kubernetes Cluster and deletes local config func (d *resetCmd) run() error { if d.kubeClient == nil { - c, err := getInternalKubeClient(settings.KubeContext) + c, err := getInternalKubeClient(settings.KubeContext, settings.KubeConfig) if err != nil { return fmt.Errorf("could not get kubernetes client: %s", err) } diff --git a/cmd/helm/reset_test.go b/cmd/helm/reset_test.go index 458736a63..8a74e8af5 100644 --- a/cmd/helm/reset_test.go +++ b/cmd/helm/reset_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -31,40 +31,58 @@ import ( "k8s.io/helm/pkg/proto/hapi/release" ) +type resetCase struct { + name string + err bool + resp []*release.Release + removeHelmHome bool + force bool + expectedActions int + expectedOutput string +} + func TestResetCmd(t *testing.T) { - home, err := ioutil.TempDir("", "helm_home") - if err != nil { - t.Fatal(err) - } - defer os.Remove(home) - var buf bytes.Buffer - c := &helm.FakeClient{} - fc := fake.NewSimpleClientset() - cmd := &resetCmd{ - out: &buf, - home: helmpath.Home(home), - client: c, - kubeClient: fc, - namespace: core.NamespaceDefault, - } - if err := cmd.run(); err != nil { - t.Errorf("unexpected error: %v", err) - } - actions := fc.Actions() - if len(actions) != 3 { - t.Errorf("Expected 3 actions, got %d", len(actions)) - } - expected := "Tiller (the Helm server-side component) has been uninstalled from your Kubernetes Cluster." - if !strings.Contains(buf.String(), expected) { - t.Errorf("expected %q, got %q", expected, buf.String()) - } - if _, err := os.Stat(home); err != nil { - t.Errorf("Helm home directory %s does not exists", home) - } + verifyResetCmd(t, resetCase{ + name: "test reset command", + expectedActions: 3, + expectedOutput: "Tiller (the Helm server-side component) has been uninstalled from your Kubernetes Cluster.", + }) } func TestResetCmd_removeHelmHome(t *testing.T) { + verifyResetCmd(t, resetCase{ + name: "test reset command - remove helm home", + removeHelmHome: true, + expectedActions: 3, + expectedOutput: "Tiller (the Helm server-side component) has been uninstalled from your Kubernetes Cluster.", + }) +} + +func TestReset_deployedReleases(t *testing.T) { + verifyResetCmd(t, resetCase{ + name: "test reset command - deployed releases", + resp: []*release.Release{ + helm.ReleaseMock(&helm.MockReleaseOptions{Name: "atlas-guide", StatusCode: release.Status_DEPLOYED}), + }, + err: true, + expectedOutput: "there are still 1 deployed releases (Tip: use --force to remove Tiller. Releases will not be deleted.)", + }) +} + +func TestReset_forceFlag(t *testing.T) { + verifyResetCmd(t, resetCase{ + name: "test reset command - force flag", + force: true, + resp: []*release.Release{ + helm.ReleaseMock(&helm.MockReleaseOptions{Name: "atlas-guide", StatusCode: release.Status_DEPLOYED}), + }, + expectedActions: 3, + expectedOutput: "Tiller (the Helm server-side component) has been uninstalled from your Kubernetes Cluster.", + }) +} + +func verifyResetCmd(t *testing.T, tc resetCase) { home, err := ioutil.TempDir("", "helm_home") if err != nil { t.Fatal(err) @@ -72,99 +90,42 @@ func TestResetCmd_removeHelmHome(t *testing.T) { defer os.Remove(home) var buf bytes.Buffer - c := &helm.FakeClient{} + c := &helm.FakeClient{ + Rels: tc.resp, + } fc := fake.NewSimpleClientset() cmd := &resetCmd{ - removeHelmHome: true, + removeHelmHome: tc.removeHelmHome, + force: tc.force, out: &buf, home: helmpath.Home(home), client: c, kubeClient: fc, namespace: core.NamespaceDefault, } - if err := cmd.run(); err != nil { - t.Errorf("unexpected error: %v", err) - } - actions := fc.Actions() - if len(actions) != 3 { - t.Errorf("Expected 3 actions, got %d", len(actions)) - } - expected := "Tiller (the Helm server-side component) has been uninstalled from your Kubernetes Cluster." - if !strings.Contains(buf.String(), expected) { - t.Errorf("expected %q, got %q", expected, buf.String()) - } - if _, err := os.Stat(home); err == nil { - t.Errorf("Helm home directory %s already exists", home) - } -} - -func TestReset_deployedReleases(t *testing.T) { - home, err := ioutil.TempDir("", "helm_home") - if err != nil { - t.Fatal(err) - } - defer os.Remove(home) - var buf bytes.Buffer - resp := []*release.Release{ - helm.ReleaseMock(&helm.MockReleaseOptions{Name: "atlas-guide", StatusCode: release.Status_DEPLOYED}), - } - c := &helm.FakeClient{ - Rels: resp, - } - fc := fake.NewSimpleClientset() - cmd := &resetCmd{ - out: &buf, - home: helmpath.Home(home), - client: c, - kubeClient: fc, - namespace: core.NamespaceDefault, - } err = cmd.run() - expected := "there are still 1 deployed releases (Tip: use --force to remove Tiller. Releases will not be deleted.)" - if !strings.Contains(err.Error(), expected) { + if !tc.err && err != nil { t.Errorf("unexpected error: %v", err) } - if _, err := os.Stat(home); err != nil { - t.Errorf("Helm home directory %s does not exists", home) - } -} -func TestReset_forceFlag(t *testing.T) { - home, err := ioutil.TempDir("", "helm_home") - if err != nil { - t.Fatal(err) + got := buf.String() + if tc.err { + got = err.Error() } - defer os.Remove(home) - var buf bytes.Buffer - resp := []*release.Release{ - helm.ReleaseMock(&helm.MockReleaseOptions{Name: "atlas-guide", StatusCode: release.Status_DEPLOYED}), - } - c := &helm.FakeClient{ - Rels: resp, - } - fc := fake.NewSimpleClientset() - cmd := &resetCmd{ - force: true, - out: &buf, - home: helmpath.Home(home), - client: c, - kubeClient: fc, - namespace: core.NamespaceDefault, - } - if err := cmd.run(); err != nil { - t.Errorf("unexpected error: %v", err) - } actions := fc.Actions() - if len(actions) != 3 { - t.Errorf("Expected 3 actions, got %d", len(actions)) + if tc.expectedActions > 0 && len(actions) != tc.expectedActions { + t.Errorf("Expected %d actions, got %d", tc.expectedActions, len(actions)) + } + if !strings.Contains(got, tc.expectedOutput) { + t.Errorf("expected %q, got %q", tc.expectedOutput, got) } - expected := "Tiller (the Helm server-side component) has been uninstalled from your Kubernetes Cluster." - if !strings.Contains(buf.String(), expected) { - t.Errorf("expected %q, got %q", expected, buf.String()) + _, err = os.Stat(home) + if !tc.removeHelmHome && err != nil { + t.Errorf("Helm home directory %s does not exist", home) } - if _, err := os.Stat(home); err != nil { - t.Errorf("Helm home directory %s does not exists", home) + if tc.removeHelmHome && err == nil { + t.Errorf("Helm home directory %s exists", home) } } diff --git a/cmd/helm/rollback.go b/cmd/helm/rollback.go index 889b6ae28..5c85afc3b 100644 --- a/cmd/helm/rollback.go +++ b/cmd/helm/rollback.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -45,6 +45,7 @@ type rollbackCmd struct { client helm.Interface timeout int64 wait bool + description string } func newRollbackCmd(c helm.Interface, out io.Writer) *cobra.Command { @@ -83,6 +84,7 @@ func newRollbackCmd(c helm.Interface, out io.Writer) *cobra.Command { f.BoolVar(&rollback.disableHooks, "no-hooks", false, "prevent hooks from running during rollback") f.Int64Var(&rollback.timeout, "timeout", 300, "time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks)") f.BoolVar(&rollback.wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment are in a ready state before marking the release as successful. It will wait for as long as --timeout") + f.StringVar(&rollback.description, "description", "", "specify a description for the release") return cmd } @@ -96,7 +98,8 @@ func (r *rollbackCmd) run() error { helm.RollbackDisableHooks(r.disableHooks), helm.RollbackVersion(r.revision), helm.RollbackTimeout(r.timeout), - helm.RollbackWait(r.wait)) + helm.RollbackWait(r.wait), + helm.RollbackDescription(r.description)) if err != nil { return prettyError(err) } diff --git a/cmd/helm/rollback_test.go b/cmd/helm/rollback_test.go index f1479b2eb..a98a4096a 100644 --- a/cmd/helm/rollback_test.go +++ b/cmd/helm/rollback_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -45,6 +45,12 @@ func TestRollbackCmd(t *testing.T) { flags: []string{"--wait"}, expected: "Rollback was a success! Happy Helming!", }, + { + name: "rollback a release with description", + args: []string{"funny-honey", "1"}, + flags: []string{"--description", "foo"}, + expected: "Rollback was a success! Happy Helming!", + }, { name: "rollback a release without revision", args: []string{"funny-honey"}, diff --git a/cmd/helm/search.go b/cmd/helm/search.go index 845bfd0be..84f328d41 100644 --- a/cmd/helm/search.go +++ b/cmd/helm/search.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -47,6 +47,7 @@ type searchCmd struct { versions bool regexp bool version string + colWidth uint } func newSearchCmd(out io.Writer) *cobra.Command { @@ -66,6 +67,7 @@ func newSearchCmd(out io.Writer) *cobra.Command { f.BoolVarP(&sc.regexp, "regexp", "r", false, "use regular expressions for searching") f.BoolVarP(&sc.versions, "versions", "l", false, "show the long listing, with each version of each chart on its own line") f.StringVarP(&sc.version, "version", "v", "", "search using semantic versioning constraints") + f.UintVar(&sc.colWidth, "col-width", 60, "specifies the max column width of output") return cmd } @@ -93,7 +95,7 @@ func (s *searchCmd) run(args []string) error { return err } - fmt.Fprintln(s.out, s.formatSearchResults(data)) + fmt.Fprintln(s.out, s.formatSearchResults(data, s.colWidth)) return nil } @@ -126,12 +128,12 @@ func (s *searchCmd) applyConstraint(res []*search.Result) ([]*search.Result, err return data, nil } -func (s *searchCmd) formatSearchResults(res []*search.Result) string { +func (s *searchCmd) formatSearchResults(res []*search.Result, colWidth uint) string { if len(res) == 0 { return "No results found" } table := uitable.New() - table.MaxColWidth = 50 + table.MaxColWidth = colWidth table.AddRow("NAME", "CHART VERSION", "APP VERSION", "DESCRIPTION") for _, r := range res { table.AddRow(r.Name, r.Chart.Version, r.Chart.AppVersion, r.Chart.Description) diff --git a/cmd/helm/search/search.go b/cmd/helm/search/search.go index 6c4cb4aa4..04acb8690 100644 --- a/cmd/helm/search/search.go +++ b/cmd/helm/search/search.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/helm/search/search_test.go b/cmd/helm/search/search_test.go index 574f55448..8432685fa 100644 --- a/cmd/helm/search/search_test.go +++ b/cmd/helm/search/search_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/helm/search_test.go b/cmd/helm/search_test.go index 734f752f5..233f94572 100644 --- a/cmd/helm/search_test.go +++ b/cmd/helm/search_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/helm/serve.go b/cmd/helm/serve.go index 21ae36da1..81f2785c3 100644 --- a/cmd/helm/serve.go +++ b/cmd/helm/serve.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/helm/status.go b/cmd/helm/status.go index b73b6f56e..be057a28e 100644 --- a/cmd/helm/status.go +++ b/cmd/helm/status.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/helm/status_test.go b/cmd/helm/status_test.go index 616b027f3..4a00b8698 100644 --- a/cmd/helm/status_test.go +++ b/cmd/helm/status_test.go @@ -1,5 +1,5 @@ /* -Copyright 2017 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/helm/template.go b/cmd/helm/template.go index c04bc2dc8..54eb9ff49 100644 --- a/cmd/helm/template.go +++ b/cmd/helm/template.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -63,18 +63,20 @@ To render just one template in a chart, use '-x': ` type templateCmd struct { - namespace string - valueFiles valueFiles - chartPath string - out io.Writer - values []string - stringValues []string - nameTemplate string - showNotes bool - releaseName string - renderFiles []string - kubeVersion string - outputDir string + namespace string + valueFiles valueFiles + chartPath string + out io.Writer + values []string + stringValues []string + fileValues []string + nameTemplate string + showNotes bool + releaseName string + releaseIsUpgrade bool + renderFiles []string + kubeVersion string + outputDir string } func newTemplateCmd(out io.Writer) *cobra.Command { @@ -93,11 +95,13 @@ func newTemplateCmd(out io.Writer) *cobra.Command { f := cmd.Flags() f.BoolVar(&t.showNotes, "notes", false, "show the computed NOTES.txt file as well") f.StringVarP(&t.releaseName, "name", "n", "RELEASE-NAME", "release name") + f.BoolVar(&t.releaseIsUpgrade, "is-upgrade", false, "set .Release.IsUpgrade instead of .Release.IsInstall") f.StringArrayVarP(&t.renderFiles, "execute", "x", []string{}, "only execute the given templates") f.VarP(&t.valueFiles, "values", "f", "specify values in a YAML file (can specify multiple)") f.StringVar(&t.namespace, "namespace", "", "namespace to install the release into") f.StringArrayVar(&t.values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)") f.StringArrayVar(&t.stringValues, "set-string", []string{}, "set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)") + f.StringArrayVar(&t.fileValues, "set-file", []string{}, "set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2)") f.StringVar(&t.nameTemplate, "name-template", "", "specify template used to name the release") f.StringVar(&t.kubeVersion, "kube-version", defaultKubeVersion, "kubernetes version used as Capabilities.KubeVersion.Major/Minor") f.StringVar(&t.outputDir, "output-dir", "", "writes the executed templates to files in output-dir instead of stdout") @@ -117,31 +121,10 @@ func (t *templateCmd) run(cmd *cobra.Command, args []string) error { } else { return err } - // verify specified templates exist relative to chart - rf := []string{} - var af string - var err error - if len(t.renderFiles) > 0 { - for _, f := range t.renderFiles { - if !filepath.IsAbs(f) { - af, err = filepath.Abs(filepath.Join(t.chartPath, f)) - if err != nil { - return fmt.Errorf("could not resolve template path: %s", err) - } - } else { - af = f - } - rf = append(rf, af) - - if _, err := os.Stat(af); err != nil { - return fmt.Errorf("could not resolve template path: %s", err) - } - } - } // verify that output-dir exists if provided if t.outputDir != "" { - _, err = os.Stat(t.outputDir) + _, err := os.Stat(t.outputDir) if os.IsNotExist(err) { return fmt.Errorf("output-dir '%s' does not exist", t.outputDir) } @@ -151,7 +134,7 @@ func (t *templateCmd) run(cmd *cobra.Command, args []string) error { t.namespace = defaultNamespace() } // get combined values and create config - rawVals, err := vals(t.valueFiles, t.values, t.stringValues) + rawVals, err := vals(t.valueFiles, t.values, t.stringValues, t.fileValues, "", "", "") if err != nil { return err } @@ -180,6 +163,8 @@ func (t *templateCmd) run(cmd *cobra.Command, args []string) error { } options := chartutil.ReleaseOptions{ Name: t.releaseName, + IsInstall: !t.releaseIsUpgrade, + IsUpgrade: t.releaseIsUpgrade, Time: timeconv.Now(), Namespace: t.namespace, } @@ -232,19 +217,7 @@ func (t *templateCmd) run(cmd *cobra.Command, args []string) error { m := tiller.Manifest{Name: k, Content: v, Head: &util.SimpleHead{Kind: h}} listManifests = append(listManifests, m) } - in := func(needle string, haystack []string) bool { - // make needle path absolute - d := strings.Split(needle, string(os.PathSeparator)) - dd := d[1:] - an := filepath.Join(t.chartPath, strings.Join(dd, string(os.PathSeparator))) - - for _, h := range haystack { - if h == an { - return true - } - } - return false - } + if settings.Debug { rel := &release.Release{ Name: t.releaseName, @@ -257,10 +230,47 @@ func (t *templateCmd) run(cmd *cobra.Command, args []string) error { printRelease(os.Stdout, rel) } - for _, m := range tiller.SortByKind(listManifests) { - if len(t.renderFiles) > 0 && !in(m.Name, rf) { - continue + var manifestsToRender []tiller.Manifest + + // if we have a list of files to render, then check that each of the + // provided files exists in the chart. + if len(t.renderFiles) > 0 { + for _, f := range t.renderFiles { + missing := true + if !filepath.IsAbs(f) { + newF, err := filepath.Abs(filepath.Join(t.chartPath, f)) + if err != nil { + return fmt.Errorf("could not turn template path %s into absolute path: %s", f, err) + } + f = newF + } + + for _, manifest := range listManifests { + // manifest.Name is rendered using linux-style filepath separators on Windows as + // well as macOS/linux. + manifestPathSplit := strings.Split(manifest.Name, "/") + // remove the chart name from the path + manifestPathSplit = manifestPathSplit[1:] + toJoin := append([]string{t.chartPath}, manifestPathSplit...) + manifestPath := filepath.Join(toJoin...) + + // if the filepath provided matches a manifest path in the + // chart, render that manifest + if f == manifestPath { + manifestsToRender = append(manifestsToRender, manifest) + missing = false + } + } + if missing { + return fmt.Errorf("could not find template %s in chart", f) + } } + } else { + // no renderFiles provided, render all manifests in the chart + manifestsToRender = listManifests + } + + for _, m := range tiller.SortByKind(manifestsToRender) { data := m.Content b := filepath.Base(m.Name) if !t.showNotes && b == "NOTES.txt" { @@ -303,7 +313,7 @@ func writeToFile(outputDir string, name string, data string) error { defer f.Close() - _, err = f.WriteString(fmt.Sprintf("##---\n# Source: %s\n%s", name, data)) + _, err = f.WriteString(fmt.Sprintf("---\n# Source: %s\n%s", name, data)) if err != nil { return err diff --git a/cmd/helm/template_test.go b/cmd/helm/template_test.go index eefa46774..64924c2f2 100644 --- a/cmd/helm/template_test.go +++ b/cmd/helm/template_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -27,10 +27,13 @@ import ( "testing" ) -var chartPath = "./../../pkg/chartutil/testdata/subpop/charts/subchart1" +var ( + subchart1ChartPath = "./../../pkg/chartutil/testdata/subpop/charts/subchart1" + frobnitzChartPath = "./../../pkg/chartutil/testdata/frobnitz" +) func TestTemplateCmd(t *testing.T) { - absChartPath, err := filepath.Abs(chartPath) + subchart1AbsChartPath, err := filepath.Abs(subchart1ChartPath) if err != nil { t.Fatal(err) } @@ -40,74 +43,109 @@ func TestTemplateCmd(t *testing.T) { args []string expectKey string expectValue string + expectError string }{ { name: "check_name", desc: "check for a known name in chart", - args: []string{chartPath}, + args: []string{subchart1ChartPath}, expectKey: "subchart1/templates/service.yaml", expectValue: "protocol: TCP\n name: nginx", }, { name: "check_set_name", desc: "verify --set values exist", - args: []string{chartPath, "-x", "templates/service.yaml", "--set", "service.name=apache"}, + args: []string{subchart1ChartPath, "-x", "templates/service.yaml", "--set", "service.name=apache"}, expectKey: "subchart1/templates/service.yaml", expectValue: "protocol: TCP\n name: apache", }, { name: "check_execute", desc: "verify --execute single template", - args: []string{chartPath, "-x", "templates/service.yaml", "--set", "service.name=apache"}, + args: []string{subchart1ChartPath, "-x", "templates/service.yaml", "--set", "service.name=apache"}, expectKey: "subchart1/templates/service.yaml", expectValue: "protocol: TCP\n name: apache", }, + { + name: "check_execute_non_existent", + desc: "verify --execute fails on a template that doesn't exist", + args: []string{subchart1ChartPath, "-x", "templates/thisdoesn'texist.yaml"}, + expectError: "could not find template", + }, { name: "check_execute_absolute", desc: "verify --execute single template", - args: []string{chartPath, "-x", absChartPath + "/" + "templates/service.yaml", "--set", "service.name=apache"}, + args: []string{subchart1ChartPath, "-x", subchart1AbsChartPath + "/" + "templates/service.yaml", "--set", "service.name=apache"}, expectKey: "subchart1/templates/service.yaml", expectValue: "protocol: TCP\n name: apache", }, + { + name: "check_execute_subchart_template", + desc: "verify --execute single template on a subchart template", + args: []string{subchart1ChartPath, "-x", "charts/subcharta/templates/service.yaml", "--set", "subcharta.service.name=foobar"}, + expectKey: "subchart1/charts/subcharta/templates/service.yaml", + expectValue: "protocol: TCP\n name: foobar", + }, + { + name: "check_execute_subchart_template_for_tgz_subchart", + desc: "verify --execute single template on a subchart template where the subchart is a .tgz in the chart directory", + args: []string{frobnitzChartPath, "-x", "charts/mariner/templates/placeholder.tpl", "--set", "mariner.name=moon"}, + expectKey: "frobnitz/charts/mariner/templates/placeholder.tpl", + expectValue: "Goodbye moon", + }, { name: "check_namespace", desc: "verify --namespace", - args: []string{chartPath, "--namespace", "test"}, + args: []string{subchart1ChartPath, "--namespace", "test"}, expectKey: "subchart1/templates/service.yaml", expectValue: "namespace: \"test\"", }, { name: "check_release_name", desc: "verify --release exists", - args: []string{chartPath, "--name", "test"}, + args: []string{subchart1ChartPath, "--name", "test"}, expectKey: "subchart1/templates/service.yaml", expectValue: "release-name: \"test\"", }, + { + name: "check_release_is_install", + desc: "verify --is-upgrade toggles .Release.IsInstall", + args: []string{subchart1ChartPath, "--is-upgrade=false"}, + expectKey: "subchart1/templates/service.yaml", + expectValue: "release-is-install: \"true\"", + }, + { + name: "check_release_is_upgrade", + desc: "verify --is-upgrade toggles .Release.IsUpgrade", + args: []string{subchart1ChartPath, "--is-upgrade", "true"}, + expectKey: "subchart1/templates/service.yaml", + expectValue: "release-is-upgrade: \"true\"", + }, { name: "check_notes", desc: "verify --notes shows notes", - args: []string{chartPath, "--notes", "true"}, + args: []string{subchart1ChartPath, "--notes", "true"}, expectKey: "subchart1/templates/NOTES.txt", expectValue: "Sample notes for subchart1", }, { name: "check_values_files", desc: "verify --values files values exist", - args: []string{chartPath, "--values", chartPath + "/charts/subchartA/values.yaml"}, + args: []string{subchart1ChartPath, "--values", subchart1ChartPath + "/charts/subchartA/values.yaml"}, expectKey: "subchart1/templates/service.yaml", expectValue: "name: apache", }, { name: "check_name_template", desc: "verify --name-template result exists", - args: []string{chartPath, "--name-template", "foobar-{{ b64enc \"abc\" }}-baz"}, + args: []string{subchart1ChartPath, "--name-template", "foobar-{{ b64enc \"abc\" }}-baz"}, expectKey: "subchart1/templates/service.yaml", expectValue: "release-name: \"foobar-YWJj-baz\"", }, { name: "check_kube_version", desc: "verify --kube-version overrides the kubernetes version", - args: []string{chartPath, "--kube-version", "1.6"}, + args: []string{subchart1ChartPath, "--kube-version", "1.6"}, expectKey: "subchart1/templates/service.yaml", expectValue: "kube-version/major: \"1\"\n kube-version/minor: \"6\"\n kube-version/gitversion: \"v1.6.0\"", }, @@ -115,7 +153,8 @@ func TestTemplateCmd(t *testing.T) { var buf bytes.Buffer for _, tt := range tests { - t.Run(tt.name, func(T *testing.T) { + tt := tt + t.Run(tt.name, func(t *testing.T) { // capture stdout old := os.Stdout r, w, _ := os.Pipe() @@ -125,8 +164,20 @@ func TestTemplateCmd(t *testing.T) { cmd := newTemplateCmd(out) cmd.SetArgs(tt.args) err := cmd.Execute() - if err != nil { - t.Errorf("expected: %v, got %v", tt.expectValue, err) + + if tt.expectError != "" { + if err == nil { + t.Errorf("expected err: %s, but no error occurred", tt.expectError) + } + // non nil error, check if it contains the expected error + if strings.Contains(err.Error(), tt.expectError) { + // had the error we were looking for, this test case is + // done + return + } + t.Fatalf("expected err: %q, got: %q", tt.expectError, err) + } else if err != nil { + t.Errorf("expected no error, got %v", err) } // restore stdout w.Close() diff --git a/cmd/helm/testdata/testcharts/alpine/templates/alpine-pod.yaml b/cmd/helm/testdata/testcharts/alpine/templates/alpine-pod.yaml index 424920782..b8ae22b6c 100644 --- a/cmd/helm/testdata/testcharts/alpine/templates/alpine-pod.yaml +++ b/cmd/helm/testdata/testcharts/alpine/templates/alpine-pod.yaml @@ -6,12 +6,12 @@ metadata: # The "heritage" label is used to track which tool deployed a given chart. # It is useful for admins who want to see what releases a particular tool # is responsible for. - heritage: {{.Release.Service | quote }} + app.kubernetes.io/managed-by: {{.Release.Service | quote }} # The "release" convention makes it easy to tie a release to all of the # Kubernetes resources that were created as part of that release. - release: {{.Release.Name | quote }} + app.kubernetes.io/instance: {{.Release.Name | quote }} # This makes it easy to audit chart usage. - chart: "{{.Chart.Name}}-{{.Chart.Version}}" + helm.sh/chart: "{{.Chart.Name}}-{{.Chart.Version}}" values: {{.Values.test.Name}} annotations: "helm.sh/created": {{.Release.Time.Seconds | quote }} diff --git a/cmd/helm/testdata/testcharts/novals/templates/alpine-pod.yaml b/cmd/helm/testdata/testcharts/novals/templates/alpine-pod.yaml index c15ab8efc..f569d556c 100644 --- a/cmd/helm/testdata/testcharts/novals/templates/alpine-pod.yaml +++ b/cmd/helm/testdata/testcharts/novals/templates/alpine-pod.yaml @@ -6,12 +6,12 @@ metadata: # The "heritage" label is used to track which tool deployed a given chart. # It is useful for admins who want to see what releases a particular tool # is responsible for. - heritage: {{.Release.Service | quote }} + app.kubernetes.io/managed-by: {{.Release.Service | quote }} # The "release" convention makes it easy to tie a release to all of the # Kubernetes resources that were created as part of that release. - release: {{.Release.Name | quote }} + app.kubernetes.io/instance: {{.Release.Name | quote }} # This makes it easy to audit chart usage. - chart: "{{.Chart.Name}}-{{.Chart.Version}}" + helm.sh/chart: "{{.Chart.Name}}-{{.Chart.Version}}" annotations: "helm.sh/created": {{.Release.Time.Seconds | quote }} spec: diff --git a/cmd/helm/testdata/testcharts/signtest/alpine/templates/alpine-pod.yaml b/cmd/helm/testdata/testcharts/signtest/alpine/templates/alpine-pod.yaml index 08cf3c2c1..c34fa8c47 100644 --- a/cmd/helm/testdata/testcharts/signtest/alpine/templates/alpine-pod.yaml +++ b/cmd/helm/testdata/testcharts/signtest/alpine/templates/alpine-pod.yaml @@ -3,7 +3,7 @@ kind: Pod metadata: name: {{.Release.Name}}-{{.Chart.Name}} labels: - heritage: {{.Release.Service}} + app.kubernetes.io/managed-by: {{.Release.Service}} chartName: {{.Chart.Name}} chartVersion: {{.Chart.Version | quote}} annotations: diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go index 125796762..23875289c 100644 --- a/cmd/helm/upgrade.go +++ b/cmd/helm/upgrade.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -29,28 +29,57 @@ import ( ) const upgradeDesc = ` -This command upgrades a release to a new version of a chart. +This command upgrades a release to a specified version of a chart and/or updates chart values. -The upgrade arguments must be a release and chart. The chart -argument can be either: a chart reference('stable/mariadb'), a path to a chart directory, -a packaged chart, or a fully qualified URL. For chart references, the latest -version will be specified unless the '--version' flag is set. +Required arguments are release and chart. The chart argument can be one of: + - a chart reference('stable/mariadb'); use '--version' and '--devel' flags for versions other than latest, + - a path to a chart directory, + - a packaged chart, + - a fully qualified URL. -To override values in a chart, use either the '--values' flag and pass in a file -or use the '--set' flag and pass configuration from the command line, to force string -values, use '--set-string'. +To customize the chart values, use any of + - '--values'/'-f' to pass in a yaml file holding settings, + - '--set' to provide one or more key=val pairs directly, + - '--set-string' to provide key=val forcing val to be stored as a string, + - '--set-file' to provide key=path to read a single large value from a file at path. -You can specify the '--values'/'-f' flag multiple times. The priority will be given to the -last (right-most) file specified. For example, if both myvalues.yaml and override.yaml -contained a key called 'Test', the value set in override.yaml would take precedence: +To edit or append to the existing customized values, add the + '--reuse-values' flag, otherwise any existing customized values are ignored. + +If no chart value arguments are provided on the command line, any existing customized values are carried +forward. If you want to revert to just the values provided in the chart, use the '--reset-values' flag. + +You can specify any of the chart value flags multiple times. The priority will be given to the last +(right-most) value specified. For example, if both myvalues.yaml and override.yaml contained a key +called 'Test', the value set in override.yaml would take precedence: $ helm upgrade -f myvalues.yaml -f override.yaml redis ./redis -You can specify the '--set' flag multiple times. The priority will be given to the -last (right-most) set specified. For example, if both 'bar' and 'newbar' values are -set for a key called 'foo', the 'newbar' value would take precedence: +Note that the key name provided to the '--set', '--set-string' and '--set-file' flags can reference +structure elements. Examples: + - mybool=TRUE + - livenessProbe.timeoutSeconds=10 + - metrics.annotations[0]=hey,metrics.annotations[1]=ho + +which sets the top level key mybool to true, the nested timeoutSeconds to 10, and two array values, respectively. + +Note that the value side of the key=val provided to '--set' and '--set-string' flags will pass through +shell evaluation followed by yaml type parsing to produce the final value. This may alter inputs with +special characters in unexpected ways, for example + + $ helm upgrade --set pwd=3jk$o2,z=f\30.e redis ./redis + +results in "pwd: 3jk" and "z: f30.e". Use single quotes to avoid shell evaluation and argument delimiters, +and use backslash to escape yaml special characters: + + $ helm upgrade --set pwd='3jk$o2z=f\\30.e' redis ./redis + +which results in the expected "pwd: 3jk$o2z=f\30.e". If a single quote occurs in your value then follow +your shell convention for escaping it; for example in bash: + + $ helm upgrade --set pwd='3jk$o2z=f\\30with'\''quote' - $ helm upgrade --set foo=bar --set foo=newbar redis ./redis +which results in "pwd: 3jk$o2z=f\30with'quote". ` type upgradeCmd struct { @@ -65,6 +94,7 @@ type upgradeCmd struct { valueFiles valueFiles values []string stringValues []string + fileValues []string verify bool keyring string install bool @@ -78,6 +108,7 @@ type upgradeCmd struct { username string password string devel bool + description string certFile string keyFile string @@ -121,6 +152,7 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command { f.BoolVar(&upgrade.force, "force", false, "force resource update through delete/recreate if needed") f.StringArrayVar(&upgrade.values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)") f.StringArrayVar(&upgrade.stringValues, "set-string", []string{}, "set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)") + f.StringArrayVar(&upgrade.fileValues, "set-file", []string{}, "set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2)") f.BoolVar(&upgrade.disableHooks, "disable-hooks", false, "disable pre/post upgrade hooks. DEPRECATED. Use no-hooks") f.BoolVar(&upgrade.disableHooks, "no-hooks", false, "disable pre/post upgrade hooks") f.BoolVar(&upgrade.verify, "verify", false, "verify the provenance of the chart before upgrading") @@ -130,7 +162,7 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command { f.StringVar(&upgrade.version, "version", "", "specify the exact chart version to use. If this is not specified, the latest version is used") f.Int64Var(&upgrade.timeout, "timeout", 300, "time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks)") f.BoolVar(&upgrade.resetValues, "reset-values", false, "when upgrading, reset the values to the ones built into the chart") - f.BoolVar(&upgrade.reuseValues, "reuse-values", false, "when upgrading, reuse the last release's values, and merge in any new values. If '--reset-values' is specified, this is ignored.") + f.BoolVar(&upgrade.reuseValues, "reuse-values", false, "when upgrading, reuse the last release's values and merge in any overrides from the command line via --set and -f. If '--reset-values' is specified, this is ignored.") f.BoolVar(&upgrade.wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment are in a ready state before marking the release as successful. It will wait for as long as --timeout") f.StringVar(&upgrade.repoURL, "repo", "", "chart repository url where to locate the requested chart") f.StringVar(&upgrade.username, "username", "", "chart repository username where to locate the requested chart") @@ -139,6 +171,7 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command { f.StringVar(&upgrade.keyFile, "key-file", "", "identify HTTPS client using this SSL key file") f.StringVar(&upgrade.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle") f.BoolVar(&upgrade.devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored.") + f.StringVar(&upgrade.description, "description", "", "specify the description to use for the upgrade, rather than the default") f.MarkDeprecated("disable-hooks", "use --no-hooks instead") @@ -187,15 +220,17 @@ func (u *upgradeCmd) run() error { keyring: u.keyring, values: u.values, stringValues: u.stringValues, + fileValues: u.fileValues, namespace: u.namespace, timeout: u.timeout, wait: u.wait, + description: u.description, } return ic.run() } } - rawVals, err := vals(u.valueFiles, u.values, u.stringValues) + rawVals, err := vals(u.valueFiles, u.values, u.stringValues, u.fileValues, u.certFile, u.keyFile, u.caFile) if err != nil { return err } @@ -224,7 +259,8 @@ func (u *upgradeCmd) run() error { helm.UpgradeTimeout(u.timeout), helm.ResetValues(u.resetValues), helm.ReuseValues(u.reuseValues), - helm.UpgradeWait(u.wait)) + helm.UpgradeWait(u.wait), + helm.UpgradeDescription(u.description)) if err != nil { return fmt.Errorf("UPGRADE FAILED: %v", prettyError(err)) } diff --git a/cmd/helm/upgrade_test.go b/cmd/helm/upgrade_test.go index 187d3593e..60b529f63 100644 --- a/cmd/helm/upgrade_test.go +++ b/cmd/helm/upgrade_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -139,6 +139,14 @@ func TestUpgradeCmd(t *testing.T) { expected: "Release \"crazy-bunny\" has been upgraded. Happy Helming!\n", rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "crazy-bunny", Version: 1, Chart: ch})}, }, + { + name: "install a release with 'upgrade --install' and custom description", + args: []string{"crazy-bunny", chartPath}, + flags: []string{"-i", "--description", "foo"}, + resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "crazy-bunny", Version: 1, Chart: ch, Description: "foo"}), + expected: "Release \"crazy-bunny\" has been upgraded. Happy Helming!\n", + rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "crazy-bunny", Version: 1, Chart: ch, Description: "foo"})}, + }, { name: "upgrade a release with wait", args: []string{"crazy-bunny", chartPath}, @@ -147,6 +155,14 @@ func TestUpgradeCmd(t *testing.T) { expected: "Release \"crazy-bunny\" has been upgraded. Happy Helming!\n", rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "crazy-bunny", Version: 2, Chart: ch2})}, }, + { + name: "upgrade a release with description", + args: []string{"crazy-bunny", chartPath}, + flags: []string{"--description", "foo"}, + resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "crazy-bunny", Version: 2, Chart: ch2}), + expected: "Release \"crazy-bunny\" has been upgraded. Happy Helming!\n", + rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "crazy-bunny", Version: 2, Chart: ch2, Description: "foo"})}, + }, { name: "upgrade a release with missing dependencies", args: []string{"bonkers-bunny", missingDepsPath}, diff --git a/cmd/helm/verify.go b/cmd/helm/verify.go index e82eb4e33..bbc8347c1 100644 --- a/cmd/helm/verify.go +++ b/cmd/helm/verify.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/cmd/helm/verify_test.go b/cmd/helm/verify_test.go index 6e8b906fc..4d683df75 100644 --- a/cmd/helm/verify_test.go +++ b/cmd/helm/verify_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/cmd/helm/version.go b/cmd/helm/version.go index d541067a0..922e744b2 100644 --- a/cmd/helm/version.go +++ b/cmd/helm/version.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -73,12 +73,6 @@ func newVersionCmd(c helm.Interface, out io.Writer) *cobra.Command { if !version.showClient && !version.showServer { version.showClient, version.showServer = true, true } - if version.showServer { - // We do this manually instead of in PreRun because we only - // need a tunnel if server version is requested. - setupConnection() - } - version.client = ensureHelmClient(version.client) return version.run() }, } @@ -108,6 +102,13 @@ func (v *versionCmd) run() error { return tpl(v.template, data, v.out) } + // We do this manually instead of in PreRun because we only + // need a tunnel if server version is requested. + if err := setupConnection(); err != nil { + return err + } + v.client = ensureHelmClient(v.client) + if settings.Debug { k8sVersion, err := getK8sVersion() if err != nil { @@ -115,7 +116,6 @@ func (v *versionCmd) run() error { } fmt.Fprintf(v.out, "Kubernetes: %#v\n", k8sVersion) } - resp, err := v.client.GetVersion() if err != nil { if grpc.Code(err) == codes.Unimplemented { @@ -135,7 +135,7 @@ func (v *versionCmd) run() error { func getK8sVersion() (*apiVersion.Info, error) { var v *apiVersion.Info - _, client, err := getKubeClient(settings.KubeContext) + _, client, err := getKubeClient(settings.KubeContext, settings.KubeConfig) if err != nil { return v, err } diff --git a/cmd/helm/version_test.go b/cmd/helm/version_test.go index e25724f4c..5519131c2 100644 --- a/cmd/helm/version_test.go +++ b/cmd/helm/version_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/cmd/rudder/rudder.go b/cmd/rudder/rudder.go index 30ece3998..8897e78be 100644 --- a/cmd/rudder/rudder.go +++ b/cmd/rudder/rudder.go @@ -1,5 +1,5 @@ /* -Copyright 2017 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/tiller/probes.go b/cmd/tiller/probes.go index 144ad8a1b..7d209aa42 100644 --- a/cmd/tiller/probes.go +++ b/cmd/tiller/probes.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/tiller/probes_test.go b/cmd/tiller/probes_test.go index 0b13460e0..d13979a8a 100644 --- a/cmd/tiller/probes_test.go +++ b/cmd/tiller/probes_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/tiller/tiller.go b/cmd/tiller/tiller.go index 5d2db3816..4c3623e59 100644 --- a/cmd/tiller/tiller.go +++ b/cmd/tiller/tiller.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -37,6 +37,8 @@ import ( healthpb "google.golang.org/grpc/health/grpc_health_v1" "google.golang.org/grpc/keepalive" + // Import to initialize client auth plugins. + _ "k8s.io/client-go/plugin/pkg/client/auth" "k8s.io/helm/pkg/kube" "k8s.io/helm/pkg/proto/hapi/services" "k8s.io/helm/pkg/storage" @@ -85,7 +87,7 @@ var ( // rootServer is the root gRPC server. // - // Each gRPC service registers itself to this server during init(). + // Each gRPC service registers itself to this server during start(). rootServer *grpc.Server // env is the default environment. diff --git a/cmd/tiller/tiller_test.go b/cmd/tiller/tiller_test.go index 0698e9d94..9ce153fc7 100644 --- a/cmd/tiller/tiller_test.go +++ b/cmd/tiller/tiller_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/cmd/tiller/trace.go b/cmd/tiller/trace.go index 71d7e8f72..126bbf83a 100644 --- a/cmd/tiller/trace.go +++ b/cmd/tiller/trace.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/docs/index.md b/docs/README.md similarity index 100% rename from docs/index.md rename to docs/README.md diff --git a/docs/chart_best_practices/README.md b/docs/chart_best_practices/README.md index 58cc65407..1160dc287 100644 --- a/docs/chart_best_practices/README.md +++ b/docs/chart_best_practices/README.md @@ -17,5 +17,5 @@ may find that their internal interests override our suggestions here. - Kubernetes Resources: - [Pods and Pod Specs](pods.md): See the best practices for working with pod specifications. - [Role-Based Access Control](rbac.md): Guidance on creating and using service accounts, roles, and role bindings. - - [Third Party Resources](third_party_resources.md): Third Party Resources (TPRs) have their own associated best practices. + - [Custom Resource Definitions](custom_resource_definitions.md): Custom Resource Definitions (CRDs) have their own associated best practices. diff --git a/docs/chart_best_practices/conventions.md b/docs/chart_best_practices/conventions.md index 324ef88f9..524928e25 100644 --- a/docs/chart_best_practices/conventions.md +++ b/docs/chart_best_practices/conventions.md @@ -4,19 +4,21 @@ This part of the Best Practices Guide explains general conventions. ## Chart Names -Chart names should be lower case letters and numbers. Words _may_ be separated with dashes (-): +Chart names should use lower case letters and numbers, and start with a letter. -Examples: +Hyphens (-) are allowed, but are known to be a little trickier to work with in Helm templates (see [issue #2192](https://github.com/helm/helm/issues/2192) for more information). + +Here are a few examples of good chart names from the [Helm Community Charts](https://github.com/helm/charts): ``` drupal -nginx-lego -aws-cluster-autoscaler +cert-manager +oauth2-proxy ``` Neither uppercase letters nor underscores should be used in chart names. Dots should not be used in chart names. -The directory that contains a chart MUST have the same name as the chart. Thus, the chart `nginx-lego` MUST be created in a directory called `nginx-lego/`. This is not merely a stylistic detail, but a requirement of the Helm Chart format. +The directory that contains a chart MUST have the same name as the chart. Thus, the chart `cert-manager` MUST be created in a directory called `cert-manager/`. This is not merely a stylistic detail, but a requirement of the Helm Chart format. ## Version Numbers diff --git a/docs/chart_best_practices/custom_resource_definitions.md b/docs/chart_best_practices/custom_resource_definitions.md new file mode 100644 index 000000000..96690dc9b --- /dev/null +++ b/docs/chart_best_practices/custom_resource_definitions.md @@ -0,0 +1,37 @@ +# Custom Resource Definitions + +This section of the Best Practices Guide deals with creating and using Custom Resource Definition +objects. + +When working with Custom Resource Definitions (CRDs), it is important to distinguish +two different pieces: + +- There is a declaration of a CRD. This is the YAML file that has the kind `CustomResourceDefinition` +- Then there are resources that _use_ the CRD. Say a CRD defines `foo.example.com/v1`. Any resource + that has `apiVersion: example.com/v1` and kind `Foo` is a resource that uses the CRD. + +## Install a CRD Declaration Before Using the Resource + +Helm is optimized to load as many resources into Kubernetes as fast as possible. +By design, Kubernetes can take an entire set of manifests and bring them all +online (this is called the reconciliation loop). + +But there's a difference with CRDs. + +For a CRD, the declaration must be registered before any resources of that CRDs +kind(s) can be used. And the registration process sometimes takes a few seconds. + +### Method 1: Separate Charts + +One way to do this is to put the CRD definition in one chart, and then put any +resources that use that CRD in _another_ chart. + +In this method, each chart must be installed separately. + +### Method 2: Pre-install Hooks + +To package the two together, add a `pre-install` hook to the CRD definition so +that it is fully installed before the rest of the chart is executed. + +Note that if you create the CRD with a `pre-install` hook, that CRD definition +will not be deleted when `helm delete` is run. diff --git a/docs/chart_best_practices/labels.md b/docs/chart_best_practices/labels.md index 7c3ac51db..a43ad9087 100644 --- a/docs/chart_best_practices/labels.md +++ b/docs/chart_best_practices/labels.md @@ -10,7 +10,7 @@ An item of metadata should be a label under the following conditions: - It is used by Kubernetes to identify this resource - It is useful to expose to operators for the purpose of querying the system. -For example, we suggest using `chart: NAME-VERSION` as a label so that operators +For example, we suggest using `helm.sh/chart: NAME-VERSION` as a label so that operators can conveniently find all of the instances of a particular chart to use. If an item of metadata is not used for querying, it should be set as an annotation @@ -25,8 +25,12 @@ are recommended, and _should_ be placed onto a chart for global consistency. Tho Name|Status|Description -----|------|---------- -heritage | REC | This should always be set to `{{ .Release.Service }}`. It is for finding all things managed by Tiller. -release | REC | This should be the `{{ .Release.Name }}`. -chart | REC | This should be the chart name and version: `{{ .Chart.Name }}-{{ .Chart.Version \| replace "+" "_" }}`. -app | REC | This should be the app name, reflecting the entire app. Usually `{{ template "name" . }}` is used for this. This is used by many Kubernetes manifests, and is not Helm-specific. -component | OPT | This is a common label for marking the different roles that pieces may play in an application. For example, `component: frontend`. +`app.kubernetes.io/name` | REC | This should be the app name, reflecting the entire app. Usually `{{ template "name" . }}` is used for this. This is used by many Kubernetes manifests, and is not Helm-specific. +`helm.sh/chart` | REC | This should be the chart name and version: `{{ .Chart.Name }}-{{ .Chart.Version \| replace "+" "_" }}`. +`app.kubernetes.io/managed-by` | REC | This should always be set to `{{ .Release.Service }}`. It is for finding all things managed by Tiller. +`app.kubernetes.io/instance` | REC | This should be the `{{ .Release.Name }}`. It aid in differentiating between different instances of the same application. +`app.kubernetes.io/version` | OPT | The version of the app and can be set to `{{ .Chart.AppVersion }}`. +`app.kubernetes.io/component` | OPT | This is a common label for marking the different roles that pieces may play in an application. For example, `app.kubernetes.io/component: frontend`. +`app.kubernetes.io/part-of` | OPT | When multiple charts or pieces of software are used together to make one application. For example, application software and a database to produce a website. This can be set to the top level application being supported. + +You can find more information on the Kubernetes labels, prefixed with `app.kubernetes.io`, in the [Kubernetes documentation](https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/). \ No newline at end of file diff --git a/docs/chart_best_practices/pods.md b/docs/chart_best_practices/pods.md index 3f26b0253..bc9b42dd9 100644 --- a/docs/chart_best_practices/pods.md +++ b/docs/chart_best_practices/pods.md @@ -52,11 +52,11 @@ All PodTemplate sections should specify a selector. For example: ```yaml selector: matchLabels: - app: MyName + app.kubernetes.io/name: MyName template: metadata: labels: - app: MyName + app.kubernetes.io/name: MyName ``` This is a good practice because it makes the relationship between the set and diff --git a/docs/chart_best_practices/templates.md b/docs/chart_best_practices/templates.md index c9995ea0a..7b21c5fea 100644 --- a/docs/chart_best_practices/templates.md +++ b/docs/chart_best_practices/templates.md @@ -155,7 +155,7 @@ Template comments should be used when documenting features of a template, such a ```yaml {{- /* mychart.shortname provides a 6 char truncated version of the release name. -*/ }} +*/ -}} {{ define "mychart.shortname" -}} {{ .Release.Name | trunc 6 }} {{- end -}} diff --git a/docs/chart_best_practices/third_party_resources.md b/docs/chart_best_practices/third_party_resources.md deleted file mode 100644 index cb0fcc754..000000000 --- a/docs/chart_best_practices/third_party_resources.md +++ /dev/null @@ -1,38 +0,0 @@ -# Third Party Resources - -This section of the Best Practices Guide deals with creating and using Third Party Resource -objects. - -When working with Third Party Resources (TPRs), it is important to distinguish -two different pieces: - -- There is a declaration of a TPR. This is the YAML file that has the kind `ThirdPartyResource` -- Then there are resources that _use_ the TPR. Say a TPR defines `foo.example.com/v1`. Any resource - that has `apiVersion: example.com/v1` and kind `Foo` is a resource that uses the - TPR. - -## Install a TPR Declaration Before Using the Resource - -Helm is optimized to load as many resources into Kubernetes as fast as possible. -By design, Kubernetes can take an entire set of manifests and bring them all -online (this is called the reconciliation loop). - -But there's a difference with TPRs. - -For a TPR, the declaration must be registered before any resources of that TPRs -kind(s) can be used. And the registration process sometimes takes a few seconds. - -### Method 1: Separate Charts - -One way to do this is to put the TPR definition in one chart, and then put any -resources that use that TPR in _another_ chart. - -In this method, each chart must be installed separately. - -### Method 2: Pre-install Hooks - -To package the two together, add a `pre-install` hook to the TPR definition so -that it is fully installed before the rest of the chart is executed. - -Note that if you create the TPR with a `pre-install` hook, that TPR definition -will not be deleted when `helm delete` is run. diff --git a/docs/chart_best_practices/values.md b/docs/chart_best_practices/values.md index 2962e7d45..28e3a3eac 100644 --- a/docs/chart_best_practices/values.md +++ b/docs/chart_best_practices/values.md @@ -93,6 +93,7 @@ There are three potential sources of values: - A chart's `values.yaml` file - A values file supplied by `helm install -f` or `helm upgrade -f` - The values passed to a `--set` or `--set-string` flag on `helm install` or `helm upgrade` +- The content of a file passed to `--set-file` flag on `helm install` or `helm upgrade` When designing the structure of your values, keep in mind that users of your chart may want to override them via either the `-f` flag or with the `--set` diff --git a/docs/chart_repository.md b/docs/chart_repository.md index 5a24249b8..01d457e63 100644 --- a/docs/chart_repository.md +++ b/docs/chart_repository.md @@ -275,7 +275,7 @@ fantastic-charts https://fantastic-charts.storage.googleapis.com If the charts are backed by HTTP basic authentication, you can also supply the username and password here: -``console +```console $ helm repo add fantastic-charts https://fantastic-charts.storage.googleapis.com --username my-username --password my-password $ helm repo list fantastic-charts https://fantastic-charts.storage.googleapis.com diff --git a/docs/chart_repository_sync_example.md b/docs/chart_repository_sync_example.md index 2fff70de9..de140c636 100644 --- a/docs/chart_repository_sync_example.md +++ b/docs/chart_repository_sync_example.md @@ -3,7 +3,7 @@ ## Prerequisites * Install the [gsutil](https://cloud.google.com/storage/docs/gsutil) tool. *We rely heavily on the gsutil rsync functionality* -* Be sure to have access to the helm binary +* Be sure to have access to the Helm binary * _Optional: We recommend you set [object versioning](https://cloud.google.com/storage/docs/gsutil/addlhelp/ObjectVersioningandConcurrencyControl#top_of_page) on your GCS bucket in case you accidentally delete something._ ## Set up a local chart repository directory @@ -16,7 +16,7 @@ $ mv alpine-0.1.0.tgz fantastic-charts/ ``` ## Generate an updated index.yaml -Use helm to generate an updated index.yaml file by passing in the directory path and the url of the remote repository to the `helm repo index` command like this: +Use Helm to generate an updated index.yaml file by passing in the directory path and the url of the remote repository to the `helm repo index` command like this: ```console $ helm repo index fantastic-charts/ --url https://fantastic-charts.storage.googleapis.com diff --git a/docs/chart_template_guide/accessing_files.md b/docs/chart_template_guide/accessing_files.md index 250fd9520..c959002b7 100644 --- a/docs/chart_template_guide/accessing_files.md +++ b/docs/chart_template_guide/accessing_files.md @@ -119,9 +119,10 @@ You have multiple options with Globs: ```yaml -{{ range $path := .Files.Glob "**.yaml" }} -{{ $path }}: | -{{ .Files.Get $path }} +{{ $root := . }} +{{ range $path, $bytes := .Files.Glob "**.yaml" }} +{{ $path }}: |- +{{ $root.Files.Get $path }} {{ end }} ``` @@ -129,7 +130,7 @@ Or ```yaml {{ range $path, $bytes := .Files.Glob "foo/*" }} -{{ $path }}: '{{ b64enc $bytes }}' +{{ base $path }}: '{{ $root.Files.Get $path | b64enc }}' {{ end }} ``` diff --git a/docs/chart_template_guide/control_structures.md b/docs/chart_template_guide/control_structures.md index 7575ebc35..1844bd393 100644 --- a/docs/chart_template_guide/control_structures.md +++ b/docs/chart_template_guide/control_structures.md @@ -53,10 +53,10 @@ data: myvalue: "Hello World" drink: {{ .Values.favorite.drink | default "tea" | quote }} food: {{ .Values.favorite.food | upper | quote }} - {{ if eq .Values.favorite.drink "coffee" }}mug: true{{ end }} + {{ if (.Values.favorite.drink) and eq .Values.favorite.drink "coffee" }}mug: true{{ end }} ``` -Since we commented out `drink: coffee` in our last example, the output should not include a `mug: true` flag. But if we add that line back into our `values.yaml` file, the output should look like this: +Note that `.Values.favorite.drink` must be defined or else it will throw an error when comparing it to "coffee". Since we commented out `drink: coffee` in our last example, the output should not include a `mug: true` flag. But if we add that line back into our `values.yaml` file, the output should look like this: ```yaml # Source: mychart/templates/configmap.yaml diff --git a/docs/chart_template_guide/functions_and_pipelines.md b/docs/chart_template_guide/functions_and_pipelines.md index 54eb8e24f..66176fc59 100644 --- a/docs/chart_template_guide/functions_and_pipelines.md +++ b/docs/chart_template_guide/functions_and_pipelines.md @@ -1,6 +1,6 @@ # Template Functions and Pipelines -So far, we've seen how to place information into a template. But that information is placed into the template unmodified. Sometimes we want to transform the supplied data in a way that makes it more useable to us. +So far, we've seen how to place information into a template. But that information is placed into the template unmodified. Sometimes we want to transform the supplied data in a way that makes it more usable to us. Let's start with a best practice: When injecting strings from the `.Values` object into the template, we ought to quote these strings. We can do that by calling the `quote` function in the template directive: diff --git a/docs/chart_template_guide/named_templates.md b/docs/chart_template_guide/named_templates.md index 042842427..33425d102 100644 --- a/docs/chart_template_guide/named_templates.md +++ b/docs/chart_template_guide/named_templates.md @@ -105,7 +105,7 @@ data: {{- end }} ``` -As mentioned above, **template names are global**. As a result of this, if two templates are declared with the same name the last occurance will be the one that is used. Since templates in subcharts are compiled together with top-level templates, it is best to name your templates with _chart specific names_. A popular naming convention is to prefix each defined template with the name of the chart: `{{ define "mychart.labels" }}`. +As mentioned above, **template names are global**. As a result of this, if two templates are declared with the same name the last occurrence will be the one that is used. Since templates in subcharts are compiled together with top-level templates, it is best to name your templates with _chart specific names_. A popular naming convention is to prefix each defined template with the name of the chart: `{{ define "mychart.labels" }}`. ## Setting the scope of a template diff --git a/docs/chart_template_guide/subcharts_and_globals.md b/docs/chart_template_guide/subcharts_and_globals.md index 33274effe..a288556d8 100644 --- a/docs/chart_template_guide/subcharts_and_globals.md +++ b/docs/chart_template_guide/subcharts_and_globals.md @@ -201,7 +201,7 @@ will only accept a string literal. The Go template language provides a `block` keyword that allows developers to provide a default implementation which is overridden later. In Helm charts, blocks are not -the best tool for overriding because it if multiple implementations of the same block +the best tool for overriding because if multiple implementations of the same block are provided, the one selected is unpredictable. The suggestion is to instead use `include`. diff --git a/docs/chart_template_guide/variables.md b/docs/chart_template_guide/variables.md index b55e6e422..d924fe2cf 100644 --- a/docs/chart_template_guide/variables.md +++ b/docs/chart_template_guide/variables.md @@ -113,11 +113,11 @@ metadata: labels: # Many helm templates would use `.` below, but that will not work, # however `$` will work here - app: {{ template "fullname" $ }} + app.kubernetes.io/name: {{ template "fullname" $ }} # I cannot reference .Chart.Name, but I can do $.Chart.Name - chart: "{{ $.Chart.Name }}-{{ $.Chart.Version }}" - release: "{{ $.Release.Name }}" - heritage: "{{ $.Release.Service }}" + helm.sh/chart: "{{ $.Chart.Name }}-{{ $.Chart.Version }}" + app.kubernetes.io/instance: "{{ $.Release.Name }}" + app.kubernetes.io/managed-by: "{{ $.Release.Service }}" type: kubernetes.io/tls data: tls.crt: {{ .certificate }} diff --git a/docs/charts.md b/docs/charts.md index 8722e6862..0414136ce 100644 --- a/docs/charts.md +++ b/docs/charts.md @@ -27,8 +27,8 @@ wordpress/ README.md # OPTIONAL: A human-readable README file requirements.yaml # OPTIONAL: A YAML file listing dependencies for the chart values.yaml # The default configuration values for this chart - charts/ # OPTIONAL: A directory containing any charts upon which this chart depends. - templates/ # OPTIONAL: A directory of templates that, when combined with values, + charts/ # A directory containing any charts upon which this chart depends. + templates/ # A directory of templates that, when combined with values, # will generate valid Kubernetes manifest files. templates/NOTES.txt # OPTIONAL: A plain text file containing short usage notes ``` @@ -36,13 +36,12 @@ wordpress/ Helm reserves use of the `charts/` and `templates/` directories, and of the listed file names. Other files will be left as they are. -While the `charts` and `templates` directories are optional there must be at least one chart dependency or template file for the chart to be valid. - ## The Chart.yaml File The `Chart.yaml` file is required for a chart. It contains the following fields: ```yaml +apiVersion: The chart API version, always "v1" (required) name: The name of the chart (required) version: A SemVer 2 version (required) kubeVersion: A SemVer range of compatible Kubernetes versions (optional) @@ -266,7 +265,7 @@ dependencies: - name: subchart1 repository: http://localhost:10191 version: 0.1.0 - condition: subchart1.enabled, global.subchart1.enabled + condition: subchart1.enabled,global.subchart1.enabled tags: - front-end - subchart1 @@ -304,7 +303,6 @@ The `--set` parameter can be used as usual to alter tag and condition values. ```` helm install --set tags.front-end=true --set subchart2.enabled=false - ```` ##### Tags and Condition Resolution @@ -528,15 +526,15 @@ metadata: name: deis-database namespace: deis labels: - heritage: deis + app.kubernetes.io/managed-by: deis spec: replicas: 1 selector: - app: deis-database + app.kubernetes.io/name: deis-database template: metadata: labels: - app: deis-database + app.kubernetes.io/name: deis-database spec: serviceAccount: deis-database containers: @@ -665,15 +663,15 @@ metadata: name: deis-database namespace: deis labels: - heritage: deis + app.kubernetes.io/managed-by: deis spec: replicas: 1 selector: - app: deis-database + app.kubernetes.io/name: deis-database template: metadata: labels: - app: deis-database + app.kubernetes.io/name: deis-database spec: serviceAccount: deis-database containers: @@ -850,7 +848,7 @@ considerations in mind: - The `Chart.yaml` will be overwritten by the generator. - Users will expect to modify such a chart's contents, so documentation should indicate how users can do so. -- All occurences of `` will be replaced with the specified chart +- All occurrences of `` will be replaced with the specified chart name so that starter charts can be used as templates. Currently the only way to add a chart to `$HELM_HOME/starters` is to manually diff --git a/docs/charts_hooks.md b/docs/charts_hooks.md index 5fc9462e4..59c9c91a2 100644 --- a/docs/charts_hooks.md +++ b/docs/charts_hooks.md @@ -16,6 +16,17 @@ Hooks work like regular templates, but they have special annotations that cause Helm to utilize them differently. In this section, we cover the basic usage pattern for hooks. +Hooks are declared as an annotation in the metadata section of a manifest: + +```yaml +apiVersion: ... +kind: .... +metadata: + annotations: + "helm.sh/hook": "pre-install" +# ... +``` + ## The Available Hooks The following hooks are defined: @@ -36,6 +47,8 @@ The following hooks are defined: rendered, but before any resources have been rolled back. - post-rollback: Executes on a rollback request after all resources have been modified. +- crd-install: Adds CRD resources before any other checks are run. This is used + only on CRD definitions that are used by other manifests in the chart. ## Hooks and the Release Lifecycle @@ -62,7 +75,7 @@ hooks, the lifecycle is altered like this: Kubernetes) 5. Tiller sorts hooks by weight (assigning a weight of 0 by default) and by name for those hooks with the same weight in ascending order. 6. Tiller then loads the hook with the lowest weight first (negative to positive) -7. Tiller waits until the hook is "Ready" +7. Tiller waits until the hook is "Ready" (except for CRDs) 8. Tiller loads the resulting resources into Kubernetes. Note that if the `--wait` flag is set, Tiller will wait until all resources are in a ready state and will not run the `post-install` hook until they are ready. @@ -114,9 +127,9 @@ kind: Job metadata: name: "{{.Release.Name}}" labels: - heritage: {{.Release.Service | quote }} - release: {{.Release.Name | quote }} - chart: "{{.Chart.Name}}-{{.Chart.Version}}" + app.kubernetes.io/managed-by: {{.Release.Service | quote }} + app.kubernetes.io/instance: {{.Release.Name | quote }} + helm.sh/chart: "{{.Chart.Name}}-{{.Chart.Version}}" annotations: # This is what defines this resource as a hook. Without this line, the # job is considered part of the release. @@ -128,9 +141,9 @@ spec: metadata: name: "{{.Release.Name}}" labels: - heritage: {{.Release.Service | quote }} - release: {{.Release.Name | quote }} - chart: "{{.Chart.Name}}-{{.Chart.Version}}" + app.kubernetes.io/managed-by: {{.Release.Service | quote }} + app.kubernetes.io/instance: {{.Release.Name | quote }} + helm.sh/chart: "{{.Chart.Name}}-{{.Chart.Version}}" spec: restartPolicy: Never containers: @@ -170,8 +183,7 @@ deterministic executing order. Weights are defined using the following annotatio ``` Hook weights can be positive or negative numbers but must be represented as -strings. When Tiller starts the execution cycle of hooks of a particular Kind it -will sort those hooks in ascending order. +strings. When Tiller starts the execution cycle of hooks of a particular kind (ex. the `pre-install` hooks or `post-install` hooks, etc.) it will sort those hooks in ascending order. It is also possible to define policies that determine when to delete corresponding hook resources. Hook deletion policies are defined using the following annotation: @@ -180,4 +192,66 @@ It is also possible to define policies that determine when to delete correspondi "helm.sh/hook-delete-policy": hook-succeeded ``` -When using `"helm.sh/hook-delete-policy"` annotation, you can choose its value from `"hook-succeeded"` and `"hook-failed"`. The value `"hook-succeeded"` specifies Tiller should delete the hook after the hook is successfully executed, while the value `"hook-failed"`specifies Tiller should delete the hook if the hook failed during execution. +You can choose one or more defined annotation values: + +* `"hook-succeeded"` specifies Tiller should delete the hook after the hook is successfully executed. +* `"hook-failed"` specifies Tiller should delete the hook if the hook failed during execution. +* `"before-hook-creation"` specifies Tiller should delete the previous hook before the new hook is launched. + +### Defining a CRD with the `crd-install` Hook + +Custom Resource Definitions (CRDs) are a special kind in Kubernetes. They provide +a way to define other kinds. + +On occasion, a chart needs to both define a kind and then use it. This is done +with the `crd-install` hook. + +The `crd-install` hook is executed very early during an installation, before +the rest of the manifests are verified. CRDs can be annotated with this hook so +that they are installed before any instances of that CRD are referenced. In this +way, when verification happens later, the CRDs will be available. + +Here is an example of defining a CRD with a hook, and an instance of the CRD: + +```yaml +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: crontabs.stable.example.com + annotations: + "helm.sh/hook": crd-install +spec: + group: stable.example.com + version: v1 + scope: Namespaced + names: + plural: crontabs + singular: crontab + kind: CronTab + shortNames: + - ct +``` + +And: + +```yaml +apiVersion: stable.example.com/v1 +kind: CronTab +metadata: + name: {{ .Release.Name }}-inst +``` + +Both of these can now be in the same chart, provided that the CRD is correctly +annotated. + +### Automatically delete hook from previous release + +When helm release being updated it is possible, that hook resource already exists in cluster. By default helm will try to create resource and fail with `"... already exists"` error. + +One might choose `"helm.sh/hook-delete-policy": "before-hook-creation"` over `"helm.sh/hook-delete-policy": "hook-succeeded,hook-failed"` because: + +* It is convenient to keep failed hook job resource in kubernetes for example for manual debug. +* It may be necessary to keep succeeded hook resource in kubernetes for some reason. +* At the same time it is not desirable to do manual resource deletion before helm release upgrade. + +`"helm.sh/hook-delete-policy": "before-hook-creation"` annotation on hook causes tiller to remove the hook from previous release if there is one before the new hook is launched and can be used with another policy. diff --git a/docs/charts_tips_and_tricks.md b/docs/charts_tips_and_tricks.md index 484d8b936..a83b44457 100644 --- a/docs/charts_tips_and_tricks.md +++ b/docs/charts_tips_and_tricks.md @@ -106,6 +106,43 @@ For example: The above will render the template when .Values.foo is defined, but will fail to render and exit when .Values.foo is undefined. +## Using the 'tpl' Function + +The `tpl` function allows developers to evaluate strings as templates inside a template. +This is useful to pass a template string as a value to a chart or render external configuration files. +Syntax: `{{ tpl TEMPLATE_STRING VALUES }}` + +Examples: +``` +# values +template: "{{ .Values.name }}" +name: "Tom" + +# template +{{ tpl .Values.template . }} + +# output +Tom +``` + +Rendering a external configuration file: +``` +# external configuration file conf/app.conf +firstName={{ .Values.firstName }} +lastName={{ .Values.lastName }} + +# values +firstName: Peter +lastName: Parker + +# template +{{ tpl (.Files.Get "conf/app.conf") . }} + +# output +firstName=Peter +lastName=Parker +``` + ## Creating Image Pull Secrets Image pull secrets are essentially a combination of _registry_, _username_, and _password_. You may need them in an application you are deploying, but to create them requires running _base64_ a couple of times. We can write a helper template to compose the Docker configuration file for use as the Secret's payload. Here is an example: diff --git a/docs/developers.md b/docs/developers.md index 5095bf1a0..e18c28d5d 100644 --- a/docs/developers.md +++ b/docs/developers.md @@ -10,7 +10,6 @@ Helm and Tiller. - A Kubernetes cluster w/ kubectl (optional) - The gRPC toolchain - Git -- Mercurial ## Building Helm/Tiller diff --git a/docs/examples/README.md b/docs/examples/README.md index 723040ca8..f936e1551 100644 --- a/docs/examples/README.md +++ b/docs/examples/README.md @@ -14,6 +14,5 @@ It simply deploys a single pod running Alpine Linux. The `nginx` chart shows how to compose several resources into one chart, and it illustrates more complex template usage. -It deploys a `deployment` (which creates a `replica set`), a `config -map`, and a `service`. The replica set starts an nginx pod. The config +It deploys a `Deployment` (which creates a `ReplicaSet`), a `ConfigMap`, and a `Service`. The replica set starts an nginx pod. The config map stores the files that the nginx server can serve. diff --git a/docs/examples/alpine/templates/alpine-pod.yaml b/docs/examples/alpine/templates/alpine-pod.yaml index da9caef78..1fc299b6d 100644 --- a/docs/examples/alpine/templates/alpine-pod.yaml +++ b/docs/examples/alpine/templates/alpine-pod.yaml @@ -3,16 +3,16 @@ kind: Pod metadata: name: {{ template "alpine.fullname" . }} labels: - # The "heritage" label is used to track which tool deployed a given chart. + # The "app.kubernetes.io/managed-by" label is used to track which tool deployed a given chart. # It is useful for admins who want to see what releases a particular tool # is responsible for. - heritage: {{ .Release.Service }} - # The "release" convention makes it easy to tie a release to all of the + app.kubernetes.io/managed-by: {{ .Release.Service }} + # The "app.kubernetes.io/instance" convention makes it easy to tie a release to all of the # Kubernetes resources that were created as part of that release. - release: {{ .Release.Name }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} # This makes it easy to audit chart usage. - chart: {{ .Chart.Name }}-{{ .Chart.Version }} - app: {{ template "alpine.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + app.kubernetes.io/name: {{ template "alpine.name" . }} spec: # This shows how to use a simple value. This will look for a passed-in value called restartPolicy. restartPolicy: {{ .Values.restartPolicy }} diff --git a/docs/examples/nginx/templates/configmap.yaml b/docs/examples/nginx/templates/configmap.yaml index b90d6c0c7..0141cbc69 100644 --- a/docs/examples/nginx/templates/configmap.yaml +++ b/docs/examples/nginx/templates/configmap.yaml @@ -4,10 +4,10 @@ kind: ConfigMap metadata: name: {{ template "nginx.fullname" . }} labels: - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - chart: {{ .Chart.Name }}-{{ .Chart.Version }} - app: {{ template "nginx.name" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + app.kubernetes.io/name: {{ template "nginx.name" . }} data: # When the config map is mounted as a volume, these will be created as files. index.html: {{ .Values.index | quote }} diff --git a/docs/examples/nginx/templates/deployment.yaml b/docs/examples/nginx/templates/deployment.yaml index 5fa2633ea..08850935a 100644 --- a/docs/examples/nginx/templates/deployment.yaml +++ b/docs/examples/nginx/templates/deployment.yaml @@ -6,16 +6,16 @@ metadata: # multiple times into the same namespace. name: {{ template "nginx.fullname" . }} labels: - # The "heritage" label is used to track which tool deployed a given chart. + # The "app.kubernetes.io/managed-by" label is used to track which tool deployed a given chart. # It is useful for admins who want to see what releases a particular tool # is responsible for. - heritage: {{ .Release.Service }} - # The "release" convention makes it easy to tie a release to all of the + app.kubernetes.io/managed-by: {{ .Release.Service }} + # The "app.kubernetes.io/instance" convention makes it easy to tie a release to all of the # Kubernetes resources that were created as part of that release. - release: {{ .Release.Name }} + app.kubernetes.io/instance: {{ .Release.Name }} # This makes it easy to audit chart usage. - chart: {{ .Chart.Name }}-{{ .Chart.Version }} - app: {{ template "nginx.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + app.kubernetes.io/name: {{ template "nginx.name" . }} spec: replicas: {{ .Values.replicaCount }} template: @@ -26,8 +26,8 @@ spec: {{ toYaml .Values.podAnnotations | indent 8 }} {{- end }} labels: - app: {{ template "nginx.name" . }} - release: {{ .Release.Name }} + app.kubernetes.io/name: {{ template "nginx.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} spec: containers: - name: {{ template "nginx.name" . }} diff --git a/docs/examples/nginx/templates/post-install-job.yaml b/docs/examples/nginx/templates/post-install-job.yaml index 9ec90cd0a..6e32086ab 100644 --- a/docs/examples/nginx/templates/post-install-job.yaml +++ b/docs/examples/nginx/templates/post-install-job.yaml @@ -3,16 +3,16 @@ kind: Job metadata: name: {{ template "nginx.fullname" . }} labels: - # The "heritage" label is used to track which tool deployed a given chart. + # The "app.kubernetes.io/managed-by" label is used to track which tool deployed a given chart. # It is useful for admins who want to see what releases a particular tool # is responsible for. - heritage: {{ .Release.Service }} - # The "release" convention makes it easy to tie a release to all of the + app.kubernetes.io/managed-by: {{ .Release.Service }} + # The "app.kubernetes.io/instance" convention makes it easy to tie a release to all of the # Kubernetes resources that were created as part of that release. - release: {{ .Release.Name }} + app.kubernetes.io/instance: {{ .Release.Name }} # This makes it easy to audit chart usage. - chart: {{ .Chart.Name }}-{{ .Chart.Version }} - app: {{ template "nginx.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + app.kubernetes.io/name: {{ template "nginx.name" . }} annotations: # This is what defines this resource as a hook. Without this line, the # job is considered part of the release. @@ -22,8 +22,8 @@ spec: metadata: name: {{ template "nginx.fullname" . }} labels: - release: {{ .Release.Name }} - app: {{ template "nginx.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/name: {{ template "nginx.name" . }} spec: # This shows how to use a simple value. This will look for a passed-in value # called restartPolicy. If it is not found, it will use the default value. diff --git a/docs/examples/nginx/templates/pre-install-secret.yaml b/docs/examples/nginx/templates/pre-install-secret.yaml index 6392f9684..07a9504b5 100644 --- a/docs/examples/nginx/templates/pre-install-secret.yaml +++ b/docs/examples/nginx/templates/pre-install-secret.yaml @@ -5,10 +5,10 @@ kind: Secret metadata: name: {{ template "nginx.fullname" . }} labels: - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - chart: {{ .Chart.Name }}-{{ .Chart.Version }} - app: {{ template "nginx.name" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + app.kubernetes.io/name: {{ template "nginx.name" . }} # This declares the resource to be a hook. By convention, we also name the # file "pre-install-XXX.yaml", but Helm itself doesn't care about file names. annotations: diff --git a/docs/examples/nginx/templates/service-test.yaml b/docs/examples/nginx/templates/service-test.yaml index 3913ead9c..ffb37e9f4 100644 --- a/docs/examples/nginx/templates/service-test.yaml +++ b/docs/examples/nginx/templates/service-test.yaml @@ -3,10 +3,10 @@ kind: Pod metadata: name: "{{ template "nginx.fullname" . }}-service-test" labels: - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - chart: {{ .Chart.Name }}-{{ .Chart.Version }} - app: {{ template "nginx.name" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + app.kubernetes.io/name: {{ template "nginx.name" . }} annotations: "helm.sh/hook": test-success spec: diff --git a/docs/examples/nginx/templates/service.yaml b/docs/examples/nginx/templates/service.yaml index 1481e34f0..03f7aa2c6 100644 --- a/docs/examples/nginx/templates/service.yaml +++ b/docs/examples/nginx/templates/service.yaml @@ -6,10 +6,10 @@ metadata: {{ toYaml .Values.service.annotations | indent 4 }} {{- end }} labels: - app: {{ template "nginx.name" . }} - chart: {{ .Chart.Name }}-{{ .Chart.Version }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} + app.kubernetes.io/name: {{ template "nginx.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} name: {{ template "nginx.fullname" . }} spec: # Provides options for the service so chart users have the full choice @@ -35,5 +35,5 @@ spec: nodePort: {{ .Values.service.nodePort }} {{- end }} selector: - app: {{ template "nginx.name" . }} - release: {{ .Release.Name }} + app.kubernetes.io/name: {{ template "nginx.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} diff --git a/docs/helm/helm.md b/docs/helm/helm.md index 8592cad7c..67ac9a4a2 100644 --- a/docs/helm/helm.md +++ b/docs/helm/helm.md @@ -4,7 +4,6 @@ The Helm package manager for Kubernetes. ### Synopsis - The Kubernetes package manager To begin working with Helm, run the 'helm init' command: @@ -33,14 +32,17 @@ Environment: ``` --debug enable verbose output + -h, --help help for helm --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm completion](helm_completion.md) - Generate autocompletions script for the specified shell (bash or zsh) * [helm create](helm_create.md) - create a new chart with the given name * [helm delete](helm_delete.md) - given a release name, delete the release from Kubernetes @@ -68,4 +70,4 @@ Environment: * [helm verify](helm_verify.md) - verify that a chart at the given path has been signed and is valid * [helm version](helm_version.md) - print the client/server version information -###### Auto generated by spf13/cobra on 14-Mar-2018 +###### Auto generated by spf13/cobra on 1-Aug-2018 diff --git a/docs/helm/helm_completion.md b/docs/helm/helm_completion.md index 994205d88..440393076 100644 --- a/docs/helm/helm_completion.md +++ b/docs/helm/helm_completion.md @@ -5,7 +5,6 @@ Generate autocompletions script for the specified shell (bash or zsh) ### Synopsis - Generate autocompletions script for Helm for the specified shell (bash or zsh). This command can generate shell autocompletions. e.g. @@ -18,7 +17,13 @@ Can be sourced as such ``` -helm completion SHELL +helm completion SHELL [flags] +``` + +### Options + +``` + -h, --help help for completion ``` ### Options inherited from parent commands @@ -28,11 +33,13 @@ helm completion SHELL --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 1-Aug-2018 diff --git a/docs/helm/helm_create.md b/docs/helm/helm_create.md index 6e0f3de78..0e20d9860 100644 --- a/docs/helm/helm_create.md +++ b/docs/helm/helm_create.md @@ -5,7 +5,6 @@ create a new chart with the given name ### Synopsis - This command creates a chart directory along with the common files and directories used in a chart. @@ -31,12 +30,13 @@ will be overwritten, but other files will be left alone. ``` -helm create NAME +helm create NAME [flags] ``` ### Options ``` + -h, --help help for create -p, --starter string the named Helm starter scaffold ``` @@ -47,11 +47,13 @@ helm create NAME --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 1-Aug-2018 diff --git a/docs/helm/helm_delete.md b/docs/helm/helm_delete.md index 5d41cd7ea..3c6a46844 100644 --- a/docs/helm/helm_delete.md +++ b/docs/helm/helm_delete.md @@ -5,7 +5,6 @@ given a release name, delete the release from Kubernetes ### Synopsis - This command takes a release name, and then deletes the release from Kubernetes. It removes all of the resources associated with the last release of the chart. @@ -20,15 +19,18 @@ helm delete [flags] RELEASE_NAME [...] ### Options ``` - --dry-run simulate a delete - --no-hooks prevent hooks from running during deletion - --purge remove the release from the store and make its name free for later use - --timeout int time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks) (default 300) - --tls enable TLS for request - --tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem") - --tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem") - --tls-key string path to TLS key file (default "$HELM_HOME/key.pem") - --tls-verify enable TLS for request and verify remote + --description string specify a description for the release + --dry-run simulate a delete + -h, --help help for delete + --no-hooks prevent hooks from running during deletion + --purge remove the release from the store and make its name free for later use + --timeout int time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks) (default 300) + --tls enable TLS for request + --tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem") + --tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem") + --tls-hostname string the server name used to verify the hostname on the returned certificates from the server + --tls-key string path to TLS key file (default "$HELM_HOME/key.pem") + --tls-verify enable TLS for request and verify remote ``` ### Options inherited from parent commands @@ -38,11 +40,13 @@ helm delete [flags] RELEASE_NAME [...] --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 10-Aug-2018 diff --git a/docs/helm/helm_dependency.md b/docs/helm/helm_dependency.md index 34d49e20a..317860bdb 100644 --- a/docs/helm/helm_dependency.md +++ b/docs/helm/helm_dependency.md @@ -5,7 +5,6 @@ manage a chart's dependencies ### Synopsis - Manage the dependencies of a chart. Helm charts store their dependencies in 'charts/'. For chart developers, it is @@ -54,6 +53,12 @@ repository added to helm by "helm add repo". Version matching is also supported for this case. +### Options + +``` + -h, --help help for dependency +``` + ### Options inherited from parent commands ``` @@ -61,14 +66,16 @@ for this case. --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm](helm.md) - The Helm package manager for Kubernetes. * [helm dependency build](helm_dependency_build.md) - rebuild the charts/ directory based on the requirements.lock file * [helm dependency list](helm_dependency_list.md) - list the dependencies for the given chart * [helm dependency update](helm_dependency_update.md) - update charts/ based on the contents of requirements.yaml -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 1-Aug-2018 diff --git a/docs/helm/helm_dependency_build.md b/docs/helm/helm_dependency_build.md index 0413a9a85..fba70f2ec 100644 --- a/docs/helm/helm_dependency_build.md +++ b/docs/helm/helm_dependency_build.md @@ -5,7 +5,6 @@ rebuild the charts/ directory based on the requirements.lock file ### Synopsis - Build out the charts/ directory from the requirements.lock file. Build is used to reconstruct a chart's dependencies to the state specified in @@ -23,6 +22,7 @@ helm dependency build [flags] CHART ### Options ``` + -h, --help help for build --keyring string keyring containing public keys (default "~/.gnupg/pubring.gpg") --verify verify the packages against signatures ``` @@ -34,11 +34,13 @@ helm dependency build [flags] CHART --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm dependency](helm_dependency.md) - manage a chart's dependencies -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 1-Aug-2018 diff --git a/docs/helm/helm_dependency_list.md b/docs/helm/helm_dependency_list.md index b4343081c..da754c5d1 100644 --- a/docs/helm/helm_dependency_list.md +++ b/docs/helm/helm_dependency_list.md @@ -5,7 +5,6 @@ list the dependencies for the given chart ### Synopsis - List all of the dependencies declared in a chart. This can take chart archives and chart directories as input. It will not alter @@ -19,6 +18,12 @@ if it cannot find a requirements.yaml. helm dependency list [flags] CHART ``` +### Options + +``` + -h, --help help for list +``` + ### Options inherited from parent commands ``` @@ -26,11 +31,13 @@ helm dependency list [flags] CHART --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm dependency](helm_dependency.md) - manage a chart's dependencies -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 1-Aug-2018 diff --git a/docs/helm/helm_dependency_update.md b/docs/helm/helm_dependency_update.md index 3c90ff779..88bf3fafd 100644 --- a/docs/helm/helm_dependency_update.md +++ b/docs/helm/helm_dependency_update.md @@ -5,7 +5,6 @@ update charts/ based on the contents of requirements.yaml ### Synopsis - Update the on-disk dependencies to mirror the requirements.yaml file. This command verifies that the required charts, as expressed in 'requirements.yaml', @@ -27,6 +26,7 @@ helm dependency update [flags] CHART ### Options ``` + -h, --help help for update --keyring string keyring containing public keys (default "~/.gnupg/pubring.gpg") --skip-refresh do not refresh the local repository cache --verify verify the packages against signatures @@ -39,11 +39,13 @@ helm dependency update [flags] CHART --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm dependency](helm_dependency.md) - manage a chart's dependencies -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 1-Aug-2018 diff --git a/docs/helm/helm_fetch.md b/docs/helm/helm_fetch.md index 1ddef65fa..81c0a9596 100644 --- a/docs/helm/helm_fetch.md +++ b/docs/helm/helm_fetch.md @@ -5,7 +5,6 @@ download a chart from a repository and (optionally) unpack it in local directory ### Synopsis - Retrieve a package from a package repository, and download it locally. This is useful for fetching packages to inspect, modify, or repackage. It can @@ -31,6 +30,7 @@ helm fetch [flags] [chart URL | repo/chartname] [...] --cert-file string identify HTTPS client using this SSL certificate file -d, --destination string location to write the chart. If this and tardir are specified, tardir is appended to this (default ".") --devel use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored. + -h, --help help for fetch --key-file string identify HTTPS client using this SSL key file --keyring string keyring containing public keys (default "~/.gnupg/pubring.gpg") --password string chart repository password @@ -50,9 +50,13 @@ helm fetch [flags] [chart URL | repo/chartname] [...] --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm](helm.md) - The Helm package manager for Kubernetes. + +###### Auto generated by spf13/cobra on 1-Aug-2018 diff --git a/docs/helm/helm_get.md b/docs/helm/helm_get.md index 9cd70e520..e7337b533 100644 --- a/docs/helm/helm_get.md +++ b/docs/helm/helm_get.md @@ -5,7 +5,6 @@ download a named release ### Synopsis - This command shows the details of a named release. It can be used to get extended information about the release, including: @@ -25,12 +24,14 @@ helm get [flags] RELEASE_NAME ### Options ``` - --revision int32 get the named release with revision - --tls enable TLS for request - --tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem") - --tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem") - --tls-key string path to TLS key file (default "$HELM_HOME/key.pem") - --tls-verify enable TLS for request and verify remote + -h, --help help for get + --revision int32 get the named release with revision + --tls enable TLS for request + --tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem") + --tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem") + --tls-hostname string the server name used to verify the hostname on the returned certificates from the server + --tls-key string path to TLS key file (default "$HELM_HOME/key.pem") + --tls-verify enable TLS for request and verify remote ``` ### Options inherited from parent commands @@ -40,14 +41,16 @@ helm get [flags] RELEASE_NAME --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm](helm.md) - The Helm package manager for Kubernetes. * [helm get hooks](helm_get_hooks.md) - download all hooks for a named release * [helm get manifest](helm_get_manifest.md) - download the manifest for a named release * [helm get values](helm_get_values.md) - download the values file for a named release -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 10-Aug-2018 diff --git a/docs/helm/helm_get_hooks.md b/docs/helm/helm_get_hooks.md index 85fa5d04b..d7097fd59 100644 --- a/docs/helm/helm_get_hooks.md +++ b/docs/helm/helm_get_hooks.md @@ -5,7 +5,6 @@ download all hooks for a named release ### Synopsis - This command downloads hooks for a given release. Hooks are formatted in YAML and separated by the YAML '---\n' separator. @@ -18,12 +17,14 @@ helm get hooks [flags] RELEASE_NAME ### Options ``` - --revision int32 get the named release with revision - --tls enable TLS for request - --tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem") - --tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem") - --tls-key string path to TLS key file (default "$HELM_HOME/key.pem") - --tls-verify enable TLS for request and verify remote + -h, --help help for hooks + --revision int32 get the named release with revision + --tls enable TLS for request + --tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem") + --tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem") + --tls-hostname string the server name used to verify the hostname on the returned certificates from the server + --tls-key string path to TLS key file (default "$HELM_HOME/key.pem") + --tls-verify enable TLS for request and verify remote ``` ### Options inherited from parent commands @@ -33,11 +34,13 @@ helm get hooks [flags] RELEASE_NAME --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm get](helm_get.md) - download a named release -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 10-Aug-2018 diff --git a/docs/helm/helm_get_manifest.md b/docs/helm/helm_get_manifest.md index a00c1be56..60bfeac0b 100644 --- a/docs/helm/helm_get_manifest.md +++ b/docs/helm/helm_get_manifest.md @@ -5,7 +5,6 @@ download the manifest for a named release ### Synopsis - This command fetches the generated manifest for a given release. A manifest is a YAML-encoded representation of the Kubernetes resources that @@ -20,12 +19,14 @@ helm get manifest [flags] RELEASE_NAME ### Options ``` - --revision int32 get the named release with revision - --tls enable TLS for request - --tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem") - --tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem") - --tls-key string path to TLS key file (default "$HELM_HOME/key.pem") - --tls-verify enable TLS for request and verify remote + -h, --help help for manifest + --revision int32 get the named release with revision + --tls enable TLS for request + --tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem") + --tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem") + --tls-hostname string the server name used to verify the hostname on the returned certificates from the server + --tls-key string path to TLS key file (default "$HELM_HOME/key.pem") + --tls-verify enable TLS for request and verify remote ``` ### Options inherited from parent commands @@ -35,11 +36,13 @@ helm get manifest [flags] RELEASE_NAME --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm get](helm_get.md) - download a named release -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 10-Aug-2018 diff --git a/docs/helm/helm_get_values.md b/docs/helm/helm_get_values.md index d8944b475..7208d5885 100644 --- a/docs/helm/helm_get_values.md +++ b/docs/helm/helm_get_values.md @@ -5,7 +5,6 @@ download the values file for a named release ### Synopsis - This command downloads a values file for a given release. @@ -16,13 +15,15 @@ helm get values [flags] RELEASE_NAME ### Options ``` - -a, --all dump all (computed) values - --revision int32 get the named release with revision - --tls enable TLS for request - --tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem") - --tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem") - --tls-key string path to TLS key file (default "$HELM_HOME/key.pem") - --tls-verify enable TLS for request and verify remote + -a, --all dump all (computed) values + -h, --help help for values + --revision int32 get the named release with revision + --tls enable TLS for request + --tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem") + --tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem") + --tls-hostname string the server name used to verify the hostname on the returned certificates from the server + --tls-key string path to TLS key file (default "$HELM_HOME/key.pem") + --tls-verify enable TLS for request and verify remote ``` ### Options inherited from parent commands @@ -32,11 +33,13 @@ helm get values [flags] RELEASE_NAME --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm get](helm_get.md) - download a named release -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 10-Aug-2018 diff --git a/docs/helm/helm_history.md b/docs/helm/helm_history.md index ac51a8994..7f0a68928 100755 --- a/docs/helm/helm_history.md +++ b/docs/helm/helm_history.md @@ -5,7 +5,6 @@ fetch release history ### Synopsis - History prints historical revisions for a given release. A default maximum of 256 revisions will be returned. Setting '--max' @@ -28,14 +27,16 @@ helm history [flags] RELEASE_NAME ### Options ``` - --col-width uint specifies the max column width of output (default 60) - --max int32 maximum number of revision to include in history (default 256) - -o, --output string prints the output in the specified format (json|table|yaml) (default "table") - --tls enable TLS for request - --tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem") - --tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem") - --tls-key string path to TLS key file (default "$HELM_HOME/key.pem") - --tls-verify enable TLS for request and verify remote + --col-width uint specifies the max column width of output (default 60) + -h, --help help for history + --max int32 maximum number of revision to include in history (default 256) + -o, --output string prints the output in the specified format (json|table|yaml) (default "table") + --tls enable TLS for request + --tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem") + --tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem") + --tls-hostname string the server name used to verify the hostname on the returned certificates from the server + --tls-key string path to TLS key file (default "$HELM_HOME/key.pem") + --tls-verify enable TLS for request and verify remote ``` ### Options inherited from parent commands @@ -45,11 +46,13 @@ helm history [flags] RELEASE_NAME --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 14-Mar-2018 +###### Auto generated by spf13/cobra on 10-Aug-2018 diff --git a/docs/helm/helm_home.md b/docs/helm/helm_home.md index bdccd756f..192302424 100644 --- a/docs/helm/helm_home.md +++ b/docs/helm/helm_home.md @@ -5,13 +5,18 @@ displays the location of HELM_HOME ### Synopsis - This command displays the location of HELM_HOME. This is where any helm configuration files live. ``` -helm home +helm home [flags] +``` + +### Options + +``` + -h, --help help for home ``` ### Options inherited from parent commands @@ -21,11 +26,13 @@ helm home --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 1-Aug-2018 diff --git a/docs/helm/helm_init.md b/docs/helm/helm_init.md index 5374488af..430cc3d0e 100644 --- a/docs/helm/helm_init.md +++ b/docs/helm/helm_init.md @@ -5,7 +5,6 @@ initialize Helm on both client and server ### Synopsis - This command installs Tiller (the Helm server-side component) onto your Kubernetes Cluster and sets up local configuration in $HELM_HOME (default ~/.helm/). @@ -27,7 +26,7 @@ To dump a manifest containing the Tiller deployment YAML, combine the ``` -helm init +helm init [flags] ``` ### Options @@ -37,6 +36,7 @@ helm init -c, --client-only if set does not install Tiller --dry-run do not install local or remote --force-upgrade force upgrade of Tiller to the current helm version + -h, --help help for init --history-max int limit the maximum number of revisions saved per release. Use 0 for no limit. --local-repo-url string URL for local repository (default "http://127.0.0.1:8879/charts") --net-host install Tiller with net=host @@ -64,11 +64,13 @@ helm init --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 1-Aug-2018 diff --git a/docs/helm/helm_inspect.md b/docs/helm/helm_inspect.md index e46b3dbf4..86689eeaa 100644 --- a/docs/helm/helm_inspect.md +++ b/docs/helm/helm_inspect.md @@ -5,7 +5,6 @@ inspect a chart ### Synopsis - This command inspects a chart and displays information. It takes a chart reference ('stable/drupal'), a full path to a directory or packaged chart, or a URL. @@ -13,7 +12,7 @@ Inspect prints the contents of the Chart.yaml file and the values.yaml file. ``` -helm inspect [CHART] +helm inspect [CHART] [flags] ``` ### Options @@ -21,6 +20,7 @@ helm inspect [CHART] ``` --ca-file string chart repository url where to locate the requested chart --cert-file string verify certificates of HTTPS-enabled servers using this CA bundle + -h, --help help for inspect --key-file string identify HTTPS client using this SSL key file --keyring string path to the keyring containing public verification keys (default "~/.gnupg/pubring.gpg") --password string chart repository password where to locate the requested chart @@ -37,14 +37,16 @@ helm inspect [CHART] --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm](helm.md) - The Helm package manager for Kubernetes. * [helm inspect chart](helm_inspect_chart.md) - shows inspect chart * [helm inspect readme](helm_inspect_readme.md) - shows inspect readme * [helm inspect values](helm_inspect_values.md) - shows inspect values -###### Auto generated by spf13/cobra on 14-Mar-2018 +###### Auto generated by spf13/cobra on 1-Aug-2018 diff --git a/docs/helm/helm_inspect_chart.md b/docs/helm/helm_inspect_chart.md index cd1328b59..2b9adbb7e 100644 --- a/docs/helm/helm_inspect_chart.md +++ b/docs/helm/helm_inspect_chart.md @@ -5,13 +5,12 @@ shows inspect chart ### Synopsis - This command inspects a chart (directory, file, or URL) and displays the contents of the Charts.yaml file ``` -helm inspect chart [CHART] +helm inspect chart [CHART] [flags] ``` ### Options @@ -19,6 +18,7 @@ helm inspect chart [CHART] ``` --ca-file string chart repository url where to locate the requested chart --cert-file string verify certificates of HTTPS-enabled servers using this CA bundle + -h, --help help for chart --key-file string identify HTTPS client using this SSL key file --keyring string path to the keyring containing public verification keys (default "~/.gnupg/pubring.gpg") --password string chart repository password where to locate the requested chart @@ -35,11 +35,13 @@ helm inspect chart [CHART] --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm inspect](helm_inspect.md) - inspect a chart -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 1-Aug-2018 diff --git a/docs/helm/helm_inspect_readme.md b/docs/helm/helm_inspect_readme.md index 9dd9ebd43..d222cd53a 100644 --- a/docs/helm/helm_inspect_readme.md +++ b/docs/helm/helm_inspect_readme.md @@ -5,13 +5,12 @@ shows inspect readme ### Synopsis - This command inspects a chart (directory, file, or URL) and displays the contents of the README file ``` -helm inspect readme [CHART] +helm inspect readme [CHART] [flags] ``` ### Options @@ -19,6 +18,7 @@ helm inspect readme [CHART] ``` --ca-file string chart repository url where to locate the requested chart --cert-file string verify certificates of HTTPS-enabled servers using this CA bundle + -h, --help help for readme --key-file string identify HTTPS client using this SSL key file --keyring string path to the keyring containing public verification keys (default "~/.gnupg/pubring.gpg") --repo string chart repository url where to locate the requested chart @@ -33,11 +33,13 @@ helm inspect readme [CHART] --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm inspect](helm_inspect.md) - inspect a chart -###### Auto generated by spf13/cobra on 14-Mar-2018 +###### Auto generated by spf13/cobra on 1-Aug-2018 diff --git a/docs/helm/helm_inspect_values.md b/docs/helm/helm_inspect_values.md index 6a907cc7d..9cca2fc32 100644 --- a/docs/helm/helm_inspect_values.md +++ b/docs/helm/helm_inspect_values.md @@ -5,13 +5,12 @@ shows inspect values ### Synopsis - This command inspects a chart (directory, file, or URL) and displays the contents of the values.yaml file ``` -helm inspect values [CHART] +helm inspect values [CHART] [flags] ``` ### Options @@ -19,6 +18,7 @@ helm inspect values [CHART] ``` --ca-file string chart repository url where to locate the requested chart --cert-file string verify certificates of HTTPS-enabled servers using this CA bundle + -h, --help help for values --key-file string identify HTTPS client using this SSL key file --keyring string path to the keyring containing public verification keys (default "~/.gnupg/pubring.gpg") --password string chart repository password where to locate the requested chart @@ -35,11 +35,13 @@ helm inspect values [CHART] --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm inspect](helm_inspect.md) - inspect a chart -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 1-Aug-2018 diff --git a/docs/helm/helm_install.md b/docs/helm/helm_install.md index 25ccea1bd..05cdf1e4a 100644 --- a/docs/helm/helm_install.md +++ b/docs/helm/helm_install.md @@ -5,15 +5,16 @@ install a chart archive ### Synopsis - This command installs a chart archive. The install argument must be a chart reference, a path to a packaged chart, a path to an unpacked chart directory or a URL. To override values in a chart, use either the '--values' flag and pass in a file -or use the '--set' flag and pass configuration from the command line, to force -a string value use '--set-string'. +or use the '--set' flag and pass configuration from the command line. To force string +values in '--set', use '--set-string' instead. In case a value is large and therefore +you want not to use neither '--values' nor '--set', use '--set-file' to read the +single large value from file. $ helm install -f myvalues.yaml ./redis @@ -25,6 +26,9 @@ or $ helm install --set-string long_int=1234567890 ./redis +or + $ helm install --set-file multiline_text=path/to/textfile + You can specify the '--values'/'-f' flag multiple times. The priority will be given to the last (right-most) file specified. For example, if both myvalues.yaml and override.yaml contained a key called 'Test', the value set in override.yaml would take precedence: @@ -68,7 +72,7 @@ charts in a repository, use 'helm search'. ``` -helm install [CHART] +helm install [CHART] [flags] ``` ### Options @@ -77,23 +81,28 @@ helm install [CHART] --ca-file string verify certificates of HTTPS-enabled servers using this CA bundle --cert-file string identify HTTPS client using this SSL certificate file --dep-up run helm dependency update before installing the chart + --description string specify a description for the release --devel use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored. --dry-run simulate an install + -h, --help help for install --key-file string identify HTTPS client using this SSL key file --keyring string location of public keys used for verification (default "~/.gnupg/pubring.gpg") -n, --name string release name. If unspecified, it will autogenerate one for you --name-template string specify template used to name the release --namespace string namespace to install the release into. Defaults to the current kube config namespace. + --no-crd-hook prevent CRD hooks from running, but run other hooks --no-hooks prevent hooks from running during install --password string chart repository password where to locate the requested chart --replace re-use the given name, even if that name is already used. This is unsafe in production --repo string chart repository url where to locate the requested chart --set stringArray set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) + --set-file stringArray set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2) --set-string stringArray set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) --timeout int time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks) (default 300) --tls enable TLS for request --tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem") --tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem") + --tls-hostname string the server name used to verify the hostname on the returned certificates from the server --tls-key string path to TLS key file (default "$HELM_HOME/key.pem") --tls-verify enable TLS for request and verify remote --username string chart repository username where to locate the requested chart @@ -110,11 +119,13 @@ helm install [CHART] --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 20-Mar-2018 +###### Auto generated by spf13/cobra on 10-Aug-2018 diff --git a/docs/helm/helm_lint.md b/docs/helm/helm_lint.md index 596edf2bb..bf168184e 100644 --- a/docs/helm/helm_lint.md +++ b/docs/helm/helm_lint.md @@ -5,7 +5,6 @@ examines a chart for possible issues ### Synopsis - This command takes a path to a chart and runs a series of tests to verify that the chart is well-formed. @@ -21,8 +20,10 @@ helm lint [flags] PATH ### Options ``` - --namespace string namespace to install the release into (only used if --install is set) (default "default") + -h, --help help for lint + --namespace string namespace to put the release into (default "default") --set stringArray set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) + --set-file stringArray set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2) --set-string stringArray set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) --strict fail on lint warnings -f, --values valueFiles specify values in a YAML file (can specify multiple) (default []) @@ -35,11 +36,13 @@ helm lint [flags] PATH --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 9-Mar-2018 +###### Auto generated by spf13/cobra on 1-Aug-2018 diff --git a/docs/helm/helm_list.md b/docs/helm/helm_list.md index 1d5bf7ea2..bf740239d 100755 --- a/docs/helm/helm_list.md +++ b/docs/helm/helm_list.md @@ -5,7 +5,6 @@ list releases ### Synopsis - This command lists all of the releases. By default, it lists only releases that are deployed or failed. Flags like @@ -39,24 +38,27 @@ helm list [flags] [FILTER] ### Options ``` - -a, --all show all releases, not just the ones marked DEPLOYED - --col-width uint specifies the max column width of output (default 60) - -d, --date sort by release date - --deleted show deleted releases - --deleting show releases that are currently being deleted - --deployed show deployed releases. If no other is specified, this will be automatically enabled - --failed show failed releases - -m, --max int maximum number of releases to fetch (default 256) - --namespace string show releases within a specific namespace - -o, --offset string next release name in the list, used to offset from start value - --pending show pending releases - -r, --reverse reverse the sort order - -q, --short output short (quiet) listing format - --tls enable TLS for request - --tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem") - --tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem") - --tls-key string path to TLS key file (default "$HELM_HOME/key.pem") - --tls-verify enable TLS for request and verify remote + -a, --all show all releases, not just the ones marked DEPLOYED + --col-width uint specifies the max column width of output (default 60) + -d, --date sort by release date + --deleted show deleted releases + --deleting show releases that are currently being deleted + --deployed show deployed releases. If no other is specified, this will be automatically enabled + --failed show failed releases + -h, --help help for list + -m, --max int maximum number of releases to fetch (default 256) + --namespace string show releases within a specific namespace + -o, --offset string next release name in the list, used to offset from start value + --output string output the specified format (json or yaml) + --pending show pending releases + -r, --reverse reverse the sort order + -q, --short output short (quiet) listing format + --tls enable TLS for request + --tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem") + --tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem") + --tls-hostname string the server name used to verify the hostname on the returned certificates from the server + --tls-key string path to TLS key file (default "$HELM_HOME/key.pem") + --tls-verify enable TLS for request and verify remote ``` ### Options inherited from parent commands @@ -66,11 +68,13 @@ helm list [flags] [FILTER] --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 10-Aug-2018 diff --git a/docs/helm/helm_package.md b/docs/helm/helm_package.md index c51aa7032..b772fa70c 100644 --- a/docs/helm/helm_package.md +++ b/docs/helm/helm_package.md @@ -5,7 +5,6 @@ package a chart directory into a chart archive ### Synopsis - This command packages a chart into a versioned chart archive file. If a path is given, this will look at that path for a chart (which must contain a Chart.yaml file) and then package that directory. @@ -26,6 +25,7 @@ helm package [flags] [CHART_PATH] [...] --app-version string set the appVersion on the chart to this version -u, --dependency-update update dependencies from "requirements.yaml" to dir "charts/" before packaging -d, --destination string location to write the chart. (default ".") + -h, --help help for package --key string name of the key to use when signing. Used if --sign is true --keyring string location of a public keyring (default "~/.gnupg/pubring.gpg") --save save packaged chart to local chart repository (default true) @@ -40,11 +40,13 @@ helm package [flags] [CHART_PATH] [...] --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 1-Aug-2018 diff --git a/docs/helm/helm_plugin.md b/docs/helm/helm_plugin.md index cc42aa4dc..5aa57b69c 100644 --- a/docs/helm/helm_plugin.md +++ b/docs/helm/helm_plugin.md @@ -5,10 +5,15 @@ add, list, or remove Helm plugins ### Synopsis - Manage client-side Helm plugins. +### Options + +``` + -h, --help help for plugin +``` + ### Options inherited from parent commands ``` @@ -16,15 +21,17 @@ Manage client-side Helm plugins. --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm](helm.md) - The Helm package manager for Kubernetes. * [helm plugin install](helm_plugin_install.md) - install one or more Helm plugins * [helm plugin list](helm_plugin_list.md) - list installed Helm plugins * [helm plugin remove](helm_plugin_remove.md) - remove one or more Helm plugins * [helm plugin update](helm_plugin_update.md) - update one or more Helm plugins -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 1-Aug-2018 diff --git a/docs/helm/helm_plugin_install.md b/docs/helm/helm_plugin_install.md index 196ca97dd..f30bfff55 100644 --- a/docs/helm/helm_plugin_install.md +++ b/docs/helm/helm_plugin_install.md @@ -5,7 +5,6 @@ install one or more Helm plugins ### Synopsis - This command allows you to install a plugin from a url to a VCS repo or a local path. Example usage: @@ -13,12 +12,13 @@ Example usage: ``` -helm plugin install [options] ... +helm plugin install [options] ... [flags] ``` ### Options ``` + -h, --help help for install --version string specify a version constraint. If this is not specified, the latest version is installed ``` @@ -29,11 +29,13 @@ helm plugin install [options] ... --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm plugin](helm_plugin.md) - add, list, or remove Helm plugins -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 1-Aug-2018 diff --git a/docs/helm/helm_plugin_list.md b/docs/helm/helm_plugin_list.md index ddfd04ee6..373462e2b 100644 --- a/docs/helm/helm_plugin_list.md +++ b/docs/helm/helm_plugin_list.md @@ -4,11 +4,16 @@ list installed Helm plugins ### Synopsis - list installed Helm plugins ``` -helm plugin list +helm plugin list [flags] +``` + +### Options + +``` + -h, --help help for list ``` ### Options inherited from parent commands @@ -18,11 +23,13 @@ helm plugin list --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm plugin](helm_plugin.md) - add, list, or remove Helm plugins -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 1-Aug-2018 diff --git a/docs/helm/helm_plugin_remove.md b/docs/helm/helm_plugin_remove.md index 8543a367a..30f222c9f 100644 --- a/docs/helm/helm_plugin_remove.md +++ b/docs/helm/helm_plugin_remove.md @@ -4,11 +4,16 @@ remove one or more Helm plugins ### Synopsis - remove one or more Helm plugins ``` -helm plugin remove ... +helm plugin remove ... [flags] +``` + +### Options + +``` + -h, --help help for remove ``` ### Options inherited from parent commands @@ -18,11 +23,13 @@ helm plugin remove ... --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm plugin](helm_plugin.md) - add, list, or remove Helm plugins -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 1-Aug-2018 diff --git a/docs/helm/helm_plugin_update.md b/docs/helm/helm_plugin_update.md index 9e5e205f0..65b16cd9d 100644 --- a/docs/helm/helm_plugin_update.md +++ b/docs/helm/helm_plugin_update.md @@ -4,11 +4,16 @@ update one or more Helm plugins ### Synopsis - update one or more Helm plugins ``` -helm plugin update ... +helm plugin update ... [flags] +``` + +### Options + +``` + -h, --help help for update ``` ### Options inherited from parent commands @@ -18,11 +23,13 @@ helm plugin update ... --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm plugin](helm_plugin.md) - add, list, or remove Helm plugins -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 1-Aug-2018 diff --git a/docs/helm/helm_repo.md b/docs/helm/helm_repo.md index 4109ceca4..0b73fbcd0 100644 --- a/docs/helm/helm_repo.md +++ b/docs/helm/helm_repo.md @@ -5,7 +5,6 @@ add, list, remove, update, and index chart repositories ### Synopsis - This command consists of multiple subcommands to interact with chart repositories. It can be used to add, remove, list, and index chart repositories. @@ -13,6 +12,12 @@ Example usage: $ helm repo add [NAME] [REPO_URL] +### Options + +``` + -h, --help help for repo +``` + ### Options inherited from parent commands ``` @@ -20,11 +25,13 @@ Example usage: --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm](helm.md) - The Helm package manager for Kubernetes. * [helm repo add](helm_repo_add.md) - add a chart repository * [helm repo index](helm_repo_index.md) - generate an index file given a directory containing packaged charts @@ -32,4 +39,4 @@ Example usage: * [helm repo remove](helm_repo_remove.md) - remove a chart repository * [helm repo update](helm_repo_update.md) - update information of available charts locally from chart repositories -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 1-Aug-2018 diff --git a/docs/helm/helm_repo_add.md b/docs/helm/helm_repo_add.md index 456ffa27e..29947147d 100644 --- a/docs/helm/helm_repo_add.md +++ b/docs/helm/helm_repo_add.md @@ -4,7 +4,6 @@ add a chart repository ### Synopsis - add a chart repository ``` @@ -16,6 +15,7 @@ helm repo add [flags] [NAME] [URL] ``` --ca-file string verify certificates of HTTPS-enabled servers using this CA bundle --cert-file string identify HTTPS client using this SSL certificate file + -h, --help help for add --key-file string identify HTTPS client using this SSL key file --no-update raise error if repo is already registered --password string chart repository password @@ -29,11 +29,13 @@ helm repo add [flags] [NAME] [URL] --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm repo](helm_repo.md) - add, list, remove, update, and index chart repositories -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 1-Aug-2018 diff --git a/docs/helm/helm_repo_index.md b/docs/helm/helm_repo_index.md index 14b412b29..4660489f9 100644 --- a/docs/helm/helm_repo_index.md +++ b/docs/helm/helm_repo_index.md @@ -5,7 +5,6 @@ generate an index file given a directory containing packaged charts ### Synopsis - Read the current directory and generate an index file based on the charts found. This tool is used for creating an 'index.yaml' file for a chart repository. To @@ -23,6 +22,7 @@ helm repo index [flags] [DIR] ### Options ``` + -h, --help help for index --merge string merge the generated index into the given index --url string url of chart repository ``` @@ -34,11 +34,13 @@ helm repo index [flags] [DIR] --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm repo](helm_repo.md) - add, list, remove, update, and index chart repositories -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 1-Aug-2018 diff --git a/docs/helm/helm_repo_list.md b/docs/helm/helm_repo_list.md index 858ef957f..bebaa6333 100644 --- a/docs/helm/helm_repo_list.md +++ b/docs/helm/helm_repo_list.md @@ -4,13 +4,18 @@ list chart repositories ### Synopsis - list chart repositories ``` helm repo list [flags] ``` +### Options + +``` + -h, --help help for list +``` + ### Options inherited from parent commands ``` @@ -18,11 +23,13 @@ helm repo list [flags] --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm repo](helm_repo.md) - add, list, remove, update, and index chart repositories -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 1-Aug-2018 diff --git a/docs/helm/helm_repo_remove.md b/docs/helm/helm_repo_remove.md index 801bc3c3f..89f43a130 100644 --- a/docs/helm/helm_repo_remove.md +++ b/docs/helm/helm_repo_remove.md @@ -4,13 +4,18 @@ remove a chart repository ### Synopsis - remove a chart repository ``` helm repo remove [flags] [NAME] ``` +### Options + +``` + -h, --help help for remove +``` + ### Options inherited from parent commands ``` @@ -18,11 +23,13 @@ helm repo remove [flags] [NAME] --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm repo](helm_repo.md) - add, list, remove, update, and index chart repositories -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 1-Aug-2018 diff --git a/docs/helm/helm_repo_update.md b/docs/helm/helm_repo_update.md index 897ed24b7..0d14f63ed 100644 --- a/docs/helm/helm_repo_update.md +++ b/docs/helm/helm_repo_update.md @@ -5,7 +5,6 @@ update information of available charts locally from chart repositories ### Synopsis - Update gets the latest information about charts from the respective chart repositories. Information is cached locally, where it is used by commands like 'helm search'. @@ -14,7 +13,13 @@ future releases. ``` -helm repo update +helm repo update [flags] +``` + +### Options + +``` + -h, --help help for update ``` ### Options inherited from parent commands @@ -24,11 +29,13 @@ helm repo update --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm repo](helm_repo.md) - add, list, remove, update, and index chart repositories -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 1-Aug-2018 diff --git a/docs/helm/helm_reset.md b/docs/helm/helm_reset.md index ed68b1b84..772ac42c3 100644 --- a/docs/helm/helm_reset.md +++ b/docs/helm/helm_reset.md @@ -5,26 +5,27 @@ uninstalls Tiller from a cluster ### Synopsis - This command uninstalls Tiller (the Helm server-side component) from your Kubernetes Cluster and optionally deletes local configuration in $HELM_HOME (default ~/.helm/) ``` -helm reset +helm reset [flags] ``` ### Options ``` - -f, --force forces Tiller uninstall even if there are releases installed, or if Tiller is not in ready state. Releases are not deleted.) - --remove-helm-home if set deletes $HELM_HOME - --tls enable TLS for request - --tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem") - --tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem") - --tls-key string path to TLS key file (default "$HELM_HOME/key.pem") - --tls-verify enable TLS for request and verify remote + -f, --force forces Tiller uninstall even if there are releases installed, or if Tiller is not in ready state. Releases are not deleted.) + -h, --help help for reset + --remove-helm-home if set deletes $HELM_HOME + --tls enable TLS for request + --tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem") + --tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem") + --tls-hostname string the server name used to verify the hostname on the returned certificates from the server + --tls-key string path to TLS key file (default "$HELM_HOME/key.pem") + --tls-verify enable TLS for request and verify remote ``` ### Options inherited from parent commands @@ -34,11 +35,13 @@ helm reset --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 10-Aug-2018 diff --git a/docs/helm/helm_rollback.md b/docs/helm/helm_rollback.md index 4b6dcbbb2..5862b180a 100644 --- a/docs/helm/helm_rollback.md +++ b/docs/helm/helm_rollback.md @@ -5,7 +5,6 @@ roll back a release to a previous revision ### Synopsis - This command rolls back a release to a previous revision. The first argument of the rollback command is the name of a release, and the @@ -20,17 +19,20 @@ helm rollback [flags] [RELEASE] [REVISION] ### Options ``` - --dry-run simulate a rollback - --force force resource update through delete/recreate if needed - --no-hooks prevent hooks from running during rollback - --recreate-pods performs pods restart for the resource if applicable - --timeout int time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks) (default 300) - --tls enable TLS for request - --tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem") - --tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem") - --tls-key string path to TLS key file (default "$HELM_HOME/key.pem") - --tls-verify enable TLS for request and verify remote - --wait if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment are in a ready state before marking the release as successful. It will wait for as long as --timeout + --description string specify a description for the release + --dry-run simulate a rollback + --force force resource update through delete/recreate if needed + -h, --help help for rollback + --no-hooks prevent hooks from running during rollback + --recreate-pods performs pods restart for the resource if applicable + --timeout int time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks) (default 300) + --tls enable TLS for request + --tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem") + --tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem") + --tls-hostname string the server name used to verify the hostname on the returned certificates from the server + --tls-key string path to TLS key file (default "$HELM_HOME/key.pem") + --tls-verify enable TLS for request and verify remote + --wait if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment are in a ready state before marking the release as successful. It will wait for as long as --timeout ``` ### Options inherited from parent commands @@ -40,11 +42,13 @@ helm rollback [flags] [RELEASE] [REVISION] --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 10-Aug-2018 diff --git a/docs/helm/helm_search.md b/docs/helm/helm_search.md index f59814b9a..c45a397e3 100644 --- a/docs/helm/helm_search.md +++ b/docs/helm/helm_search.md @@ -5,7 +5,6 @@ search for a keyword in charts ### Synopsis - Search reads through all of the repositories configured on the system, and looks for matches. @@ -13,12 +12,14 @@ Repositories are managed with 'helm repo' commands. ``` -helm search [keyword] +helm search [keyword] [flags] ``` ### Options ``` + --col-width uint specifies the max column width of output (default 60) + -h, --help help for search -r, --regexp use regular expressions for searching -v, --version string search using semantic versioning constraints -l, --versions show the long listing, with each version of each chart on its own line @@ -31,11 +32,13 @@ helm search [keyword] --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 1-Aug-2018 diff --git a/docs/helm/helm_serve.md b/docs/helm/helm_serve.md index 90ebb6da9..5e25f2a2f 100644 --- a/docs/helm/helm_serve.md +++ b/docs/helm/helm_serve.md @@ -5,7 +5,6 @@ start a local http web server ### Synopsis - This command starts a local chart repository server that serves charts from a local directory. The new server will provide HTTP access to a repository. By default, it will @@ -21,13 +20,14 @@ for more information on hosting chart repositories in a production setting. ``` -helm serve +helm serve [flags] ``` ### Options ``` --address string address to listen on (default "127.0.0.1:8879") + -h, --help help for serve --repo-path string local directory path from which to serve charts --url string external URL of chart repository ``` @@ -39,11 +39,13 @@ helm serve --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 1-Aug-2018 diff --git a/docs/helm/helm_status.md b/docs/helm/helm_status.md index 02ec0ad66..9dca005fd 100644 --- a/docs/helm/helm_status.md +++ b/docs/helm/helm_status.md @@ -5,7 +5,6 @@ displays the status of the named release ### Synopsis - This command shows the status of a named release. The status consists of: - last deployment time @@ -23,13 +22,15 @@ helm status [flags] RELEASE_NAME ### Options ``` - -o, --output string output the status in the specified format (json or yaml) - --revision int32 if set, display the status of the named release with revision - --tls enable TLS for request - --tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem") - --tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem") - --tls-key string path to TLS key file (default "$HELM_HOME/key.pem") - --tls-verify enable TLS for request and verify remote + -h, --help help for status + -o, --output string output the status in the specified format (json or yaml) + --revision int32 if set, display the status of the named release with revision + --tls enable TLS for request + --tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem") + --tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem") + --tls-hostname string the server name used to verify the hostname on the returned certificates from the server + --tls-key string path to TLS key file (default "$HELM_HOME/key.pem") + --tls-verify enable TLS for request and verify remote ``` ### Options inherited from parent commands @@ -39,11 +40,13 @@ helm status [flags] RELEASE_NAME --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 10-Aug-2018 diff --git a/docs/helm/helm_template.md b/docs/helm/helm_template.md index 3a4e9ce4a..d7770fb7f 100644 --- a/docs/helm/helm_template.md +++ b/docs/helm/helm_template.md @@ -5,7 +5,6 @@ locally render templates ### Synopsis - Render chart templates locally and display the output. This does not require Tiller. However, any values that would normally be @@ -26,6 +25,8 @@ helm template [flags] CHART ``` -x, --execute stringArray only execute the given templates + -h, --help help for template + --is-upgrade set .Release.IsUpgrade instead of .Release.IsInstall --kube-version string kubernetes version used as Capabilities.KubeVersion.Major/Minor (default "1.9") -n, --name string release name (default "RELEASE-NAME") --name-template string specify template used to name the release @@ -33,6 +34,7 @@ helm template [flags] CHART --notes show the computed NOTES.txt file as well --output-dir string writes the executed templates to files in output-dir instead of stdout --set stringArray set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) + --set-file stringArray set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2) --set-string stringArray set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) -f, --values valueFiles specify values in a YAML file (can specify multiple) (default []) ``` @@ -44,11 +46,13 @@ helm template [flags] CHART --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 9-Mar-2018 +###### Auto generated by spf13/cobra on 1-Aug-2018 diff --git a/docs/helm/helm_test.md b/docs/helm/helm_test.md index 062244e73..e55c5df68 100644 --- a/docs/helm/helm_test.md +++ b/docs/helm/helm_test.md @@ -5,7 +5,6 @@ test a release ### Synopsis - The test command runs the tests for a release. The argument this command takes is the name of a deployed release. @@ -13,19 +12,21 @@ The tests to be run are defined in the chart that was installed. ``` -helm test [RELEASE] +helm test [RELEASE] [flags] ``` ### Options ``` - --cleanup delete test pods upon completion - --timeout int time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks) (default 300) - --tls enable TLS for request - --tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem") - --tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem") - --tls-key string path to TLS key file (default "$HELM_HOME/key.pem") - --tls-verify enable TLS for request and verify remote + --cleanup delete test pods upon completion + -h, --help help for test + --timeout int time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks) (default 300) + --tls enable TLS for request + --tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem") + --tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem") + --tls-hostname string the server name used to verify the hostname on the returned certificates from the server + --tls-key string path to TLS key file (default "$HELM_HOME/key.pem") + --tls-verify enable TLS for request and verify remote ``` ### Options inherited from parent commands @@ -35,11 +36,13 @@ helm test [RELEASE] --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 10-Aug-2018 diff --git a/docs/helm/helm_upgrade.md b/docs/helm/helm_upgrade.md index 7ada6025f..f18bcf6a7 100644 --- a/docs/helm/helm_upgrade.md +++ b/docs/helm/helm_upgrade.md @@ -5,33 +5,61 @@ upgrade a release ### Synopsis +This command upgrades a release to a specified version of a chart and/or updates chart values. -This command upgrades a release to a new version of a chart. +Required arguments are release and chart. The chart argument can be one of: + - a chart reference('stable/mariadb'); use '--version' and '--devel' flags for versions other than latest, + - a path to a chart directory, + - a packaged chart, + - a fully qualified URL. -The upgrade arguments must be a release and chart. The chart -argument can be either: a chart reference('stable/mariadb'), a path to a chart directory, -a packaged chart, or a fully qualified URL. For chart references, the latest -version will be specified unless the '--version' flag is set. +To customize the chart values, use any of + - '--values'/'-f' to pass in a yaml file holding settings, + - '--set' to provide one or more key=val pairs directly, + - '--set-string' to provide key=val forcing val to be stored as a string, + - '--set-file' to provide key=path to read a single large value from a file at path. -To override values in a chart, use either the '--values' flag and pass in a file -or use the '--set' flag and pass configuration from the command line, to force string -values, use '--set-string'. +To edit or append to the existing customized values, add the + '--reuse-values' flag, otherwise any existing customized values are ignored. -You can specify the '--values'/'-f' flag multiple times. The priority will be given to the -last (right-most) file specified. For example, if both myvalues.yaml and override.yaml -contained a key called 'Test', the value set in override.yaml would take precedence: +If no chart value arguments are provided on the command line, any existing customized values are carried +forward. If you want to revert to just the values provided in the chart, use the '--reset-values' flag. + +You can specify any of the chart value flags multiple times. The priority will be given to the last +(right-most) value specified. For example, if both myvalues.yaml and override.yaml contained a key +called 'Test', the value set in override.yaml would take precedence: $ helm upgrade -f myvalues.yaml -f override.yaml redis ./redis -You can specify the '--set' flag multiple times. The priority will be given to the -last (right-most) set specified. For example, if both 'bar' and 'newbar' values are -set for a key called 'foo', the 'newbar' value would take precedence: +Note that the key name provided to the '--set', '--set-string' and '--set-file' flags can reference +structure elements. Examples: + - mybool=TRUE + - livenessProbe.timeoutSeconds=10 + - metrics.annotations[0]=hey,metrics.annotations[1]=ho + +which sets the top level key mybool to true, the nested timeoutSeconds to 10, and two array values, respectively. + +Note that the value side of the key=val provided to '--set' and '--set-string' flags will pass through +shell evaluation followed by yaml type parsing to produce the final value. This may alter inputs with +special characters in unexpected ways, for example + + $ helm upgrade --set pwd=3jk$o2,z=f\30.e redis ./redis + +results in "pwd: 3jk" and "z: f30.e". Use single quotes to avoid shell evaluation and argument delimiters, +and use backslash to escape yaml special characters: - $ helm upgrade --set foo=bar --set foo=newbar redis ./redis + $ helm upgrade --set pwd='3jk$o2z=f\\30.e' redis ./redis + +which results in the expected "pwd: 3jk$o2z=f\30.e". If a single quote occurs in your value then follow +your shell convention for escaping it; for example in bash: + + $ helm upgrade --set pwd='3jk$o2z=f\\30with'\''quote' + +which results in "pwd: 3jk$o2z=f\30with'quote". ``` -helm upgrade [RELEASE] [CHART] +helm upgrade [RELEASE] [CHART] [flags] ``` ### Options @@ -39,9 +67,11 @@ helm upgrade [RELEASE] [CHART] ``` --ca-file string verify certificates of HTTPS-enabled servers using this CA bundle --cert-file string identify HTTPS client using this SSL certificate file + --description string specify the description to use for the upgrade, rather than the default --devel use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored. --dry-run simulate an upgrade --force force resource update through delete/recreate if needed + -h, --help help for upgrade -i, --install if a release by this name doesn't already exist, run an install --key-file string identify HTTPS client using this SSL key file --keyring string path to the keyring that contains public signing keys (default "~/.gnupg/pubring.gpg") @@ -51,13 +81,15 @@ helm upgrade [RELEASE] [CHART] --recreate-pods performs pods restart for the resource if applicable --repo string chart repository url where to locate the requested chart --reset-values when upgrading, reset the values to the ones built into the chart - --reuse-values when upgrading, reuse the last release's values, and merge in any new values. If '--reset-values' is specified, this is ignored. + --reuse-values when upgrading, reuse the last release's values and merge in any overrides from the command line via --set and -f. If '--reset-values' is specified, this is ignored. --set stringArray set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) + --set-file stringArray set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2) --set-string stringArray set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) --timeout int time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks) (default 300) --tls enable TLS for request --tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem") --tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem") + --tls-hostname string the server name used to verify the hostname on the returned certificates from the server --tls-key string path to TLS key file (default "$HELM_HOME/key.pem") --tls-verify enable TLS for request and verify remote --username string chart repository username where to locate the requested chart @@ -74,11 +106,13 @@ helm upgrade [RELEASE] [CHART] --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 20-Mar-2018 +###### Auto generated by spf13/cobra on 24-Aug-2018 diff --git a/docs/helm/helm_verify.md b/docs/helm/helm_verify.md index bc5343937..30ed43679 100644 --- a/docs/helm/helm_verify.md +++ b/docs/helm/helm_verify.md @@ -5,7 +5,6 @@ verify that a chart at the given path has been signed and is valid ### Synopsis - Verify that the given chart has a valid provenance file. Provenance files provide crytographic verification that a chart has not been @@ -23,6 +22,7 @@ helm verify [flags] PATH ### Options ``` + -h, --help help for verify --keyring string keyring containing public keys (default "~/.gnupg/pubring.gpg") ``` @@ -33,11 +33,13 @@ helm verify [flags] PATH --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 1-Aug-2018 diff --git a/docs/helm/helm_version.md b/docs/helm/helm_version.md index 1f48cceba..33d33cf12 100644 --- a/docs/helm/helm_version.md +++ b/docs/helm/helm_version.md @@ -5,7 +5,6 @@ print the client/server version information ### Synopsis - Show the client and server versions for Helm and tiller. This will print a representation of the client and server versions of Helm and @@ -24,21 +23,23 @@ use '--server'. ``` -helm version +helm version [flags] ``` ### Options ``` - -c, --client client version only - -s, --server server version only - --short print the version number - --template string template for version string format - --tls enable TLS for request - --tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem") - --tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem") - --tls-key string path to TLS key file (default "$HELM_HOME/key.pem") - --tls-verify enable TLS for request and verify remote + -c, --client client version only + -h, --help help for version + -s, --server server version only + --short print the version number + --template string template for version string format + --tls enable TLS for request + --tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem") + --tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem") + --tls-hostname string the server name used to verify the hostname on the returned certificates from the server + --tls-key string path to TLS key file (default "$HELM_HOME/key.pem") + --tls-verify enable TLS for request and verify remote ``` ### Options inherited from parent commands @@ -48,11 +49,13 @@ helm version --home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --kubeconfig string absolute path to the kubeconfig file to use --tiller-connection-timeout int the duration (in seconds) Helm will wait to establish a connection to tiller (default 300) --tiller-namespace string namespace of Tiller (default "kube-system") ``` ### SEE ALSO + * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 10-Aug-2018 diff --git a/docs/install.md b/docs/install.md index 78b1a53b6..52b55baef 100755 --- a/docs/install.md +++ b/docs/install.md @@ -24,6 +24,15 @@ can be manually downloaded and installed. From there, you should be able to run the client: `helm help`. +### From Snap (Linux) + +The Snap package for Helm is maintained by +[Snapcrafters](https://github.com/snapcrafters/helm). + +``` +$ sudo snap install helm +``` + ### From Homebrew (macOS) Members of the Kubernetes community have contributed a Helm formula build to @@ -36,6 +45,15 @@ brew install kubernetes-helm (Note: There is also a formula for emacs-helm, which is a different project.) +### From Chocolatey (Windows) + +Members of the Kubernetes community have contributed a [Helm package](https://chocolatey.org/packages/kubernetes-helm) build to +[Chocolatey](https://chocolatey.org/). This package is generally up to date. + +``` +choco install kubernetes-helm +``` + ## From Script Helm now has an installer script that will automatically grab the latest version @@ -72,7 +90,7 @@ Building Helm from source is slightly more work, but is the best way to go if you want to test the latest (pre-release) Helm version. You must have a working Go environment with -[glide](https://github.com/Masterminds/glide) and Mercurial installed. +[glide](https://github.com/Masterminds/glide) installed. ```console $ cd $GOPATH @@ -113,6 +131,7 @@ You can explicitly tell `helm init` to... - Install a particular image (version) with `--tiller-image` - Install to a particular cluster with `--kube-context` - Install into a particular namespace with `--tiller-namespace` +- Install Tiller with a Service Account with `--service-account` (for [RBAC enabled clusters](securing_installation.md#rbac)) Once Tiller is installed, running `helm version` should show you both the client and server version. (If it shows only the client version, diff --git a/docs/install_faq.md b/docs/install_faq.md index ff9ee89e6..f2eae5b48 100644 --- a/docs/install_faq.md +++ b/docs/install_faq.md @@ -224,7 +224,7 @@ I am trying to remove stuff. **Q: When I delete the Tiller deployment, how come all the releases are still there?** Releases are stored in ConfigMaps inside of the `kube-system` namespace. You will -have to manually delete them to get rid of the record. +have to manually delete them to get rid of the record, or use ```helm delete --purge```. **Q: I want to delete my local Helm. Where are all its files?** diff --git a/docs/kubernetes_distros.md b/docs/kubernetes_distros.md index 04a86d0b4..bb14043da 100644 --- a/docs/kubernetes_distros.md +++ b/docs/kubernetes_distros.md @@ -18,8 +18,9 @@ Hyperkube you may need to do some manual configuration. ## GKE -Google's GKE hosted Kubernetes platform is known to work with Helm, and requires -no additional configuration. +Google's GKE hosted Kubernetes platform enables RBAC by default. You will need to create a service account for tiller, and use the --service-account flag when initializing the helm server. + +See [Tiller and role-based access control](https://docs.helm.sh/using_helm/#role-based-access-control) for more information. ## Ubuntu with 'kubeadm' @@ -43,3 +44,8 @@ Helm works straightforward on OpenShift Online, OpenShift Dedicated, OpenShift C ## Platform9 Helm Client and Helm Server (Tiller) are pre-installed with [Platform9 Managed Kubernetes](https://platform9.com/managed-kubernetes/?utm_source=helm_distro_notes). Platform9 provides access to all official Helm charts through the App Catalog UI and native Kubernetes CLI. Additional repositories can be manually added. Further details are available in this [Platform9 App Catalog article](https://platform9.com/support/deploying-kubernetes-apps-platform9-managed-kubernetes/?utm_source=helm_distro_notes). + +## DC/OS + +Helm (both client and server) has been tested and is working on Mesospheres DC/OS 1.11 Kubernetes platform, and requires +no additional configuration. diff --git a/docs/logos/helm-blue-vector.svg b/docs/logos/helm-blue-vector.svg new file mode 100644 index 000000000..45f2c2f86 --- /dev/null +++ b/docs/logos/helm-blue-vector.svg @@ -0,0 +1,43 @@ + + + + +logo +Created with Sketch. + + + + + + diff --git a/docs/logos/helm-white-vector.svg b/docs/logos/helm-white-vector.svg new file mode 100644 index 000000000..0f09be31e --- /dev/null +++ b/docs/logos/helm-white-vector.svg @@ -0,0 +1,43 @@ + + + + +logo white +Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/logos/helm.svg b/docs/logos/helm.svg new file mode 100644 index 000000000..2d8858e93 --- /dev/null +++ b/docs/logos/helm.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/man/man1/helm_upgrade.1 b/docs/man/man1/helm_upgrade.1 index 24bba7c85..602c3136f 100644 --- a/docs/man/man1/helm_upgrade.1 +++ b/docs/man/man1/helm_upgrade.1 @@ -1,6 +1,4 @@ -.TH "HELM" "1" "May 2017" "Auto generated by spf13/cobra" "" -.nh -.ad l +.TH "HELM" "1" "Aug 2018" "Auto generated by spf13/cobra" "" "" .SH NAME @@ -10,27 +8,39 @@ helm\-upgrade \- upgrade a release .SH SYNOPSIS .PP -\fBhelm upgrade [RELEASE] [CHART]\fP +\fBhelm upgrade [RELEASE] [CHART] [flags]\fP .SH DESCRIPTION .PP -This command upgrades a release to a new version of a chart. +This command upgrades a release to a specified version of a chart and/or updates chart values. .PP -The upgrade arguments must be a release and chart. The chart -argument can be either: a chart reference('stable/mariadb'), a path to a chart directory, -a packaged chart, or a fully qualified URL. For chart references, the latest -version will be specified unless the '\-\-version' flag is set. +Required arguments are release and chart. The chart argument can be one of: + \- a chart reference('stable/mariadb'); use '\-\-version' and '\-\-devel' flags for versions other than latest, + \- a path to a chart directory, + \- a packaged chart, + \- a fully qualified URL. .PP -To override values in a chart, use either the '\-\-values' flag and pass in a file -or use the '\-\-set' flag and pass configuration from the command line. +To customize the chart values, use any of + \- '\-\-values'/'\-f' to pass in a yaml file holding settings, + \- '\-\-set' to provide one or more key=val pairs directly, + \- '\-\-set\-string' to provide key=val forcing val to be stored as a string, + \- '\-\-set\-file' to provide key=path to read a single large value from a file at path. .PP -You can specify the '\-\-values'/'\-f' flag multiple times. The priority will be given to the -last (right\-most) file specified. For example, if both myvalues.yaml and override.yaml -contained a key called 'Test', the value set in override.yaml would take precedence: +To edit or append to the existing customized values, add the + '\-\-reuse\-values' flag, otherwise any existing customized values are ignored. + +.PP +If no chart value arguments are provided on the command line, any existing customized values are carried +forward. If you want to revert to just the values provided in the chart, use the '\-\-reset\-values' flag. + +.PP +You can specify any of the chart value flags multiple times. The priority will be given to the last +(right\-most) value specified. For example, if both myvalues.yaml and override.yaml contained a key +called 'Test', the value set in override.yaml would take precedence: .PP .RS @@ -42,19 +52,58 @@ $ helm upgrade \-f myvalues.yaml \-f override.yaml redis ./redis .RE .PP -You can specify the '\-\-set' flag multiple times. The priority will be given to the -last (right\-most) set specified. For example, if both 'bar' and 'newbar' values are -set for a key called 'foo', the 'newbar' value would take precedence: +Note that the key name provided to the '\-\-set', '\-\-set\-string' and '\-\-set\-file' flags can reference +structure elements. Examples: + \- mybool=TRUE + \- livenessProbe.timeoutSeconds=10 + \- metrics.annotations[0]=hey,metrics.annotations[1]=ho + +.PP +which sets the top level key mybool to true, the nested timeoutSeconds to 10, and two array values, respectively. + +.PP +Note that the value side of the key=val provided to '\-\-set' and '\-\-set\-string' flags will pass through +shell evaluation followed by yaml type parsing to produce the final value. This may alter inputs with +special characters in unexpected ways, for example + +.PP +.RS + +.nf +$ helm upgrade \-\-set pwd=3jk$o2,z=f\\30.e redis ./redis + +.fi +.RE + +.PP +results in "pwd: 3jk" and "z: f30.e". Use single quotes to avoid shell evaluation and argument delimiters, +and use backslash to escape yaml special characters: + +.PP +.RS + +.nf +$ helm upgrade \-\-set pwd='3jk$o2z=f\\\\30.e' redis ./redis + +.fi +.RE + +.PP +which results in the expected "pwd: 3jk$o2z=f\\30.e". If a single quote occurs in your value then follow +your shell convention for escaping it; for example in bash: .PP .RS .nf -$ helm upgrade \-\-set foo=bar \-\-set foo=newbar redis ./redis +$ helm upgrade \-\-set pwd='3jk$o2z=f\\\\30with'\\''quote' .fi .RE +.PP +which results in "pwd: 3jk$o2z=f\\30with'quote". + .SH OPTIONS .PP @@ -65,9 +114,13 @@ $ helm upgrade \-\-set foo=bar \-\-set foo=newbar redis ./redis \fB\-\-cert\-file\fP="" identify HTTPS client using this SSL certificate file +.PP +\fB\-\-description\fP="" + specify the description to use for the upgrade, rather than the default + .PP \fB\-\-devel\fP[=false] - use development versions, too. Equivalent to version '>0.0.0\-a'. If \-\-version is set, this is ignored. + use development versions, too. Equivalent to version '>0.0.0\-0'. If \-\-version is set, this is ignored. .PP \fB\-\-dry\-run\fP[=false] @@ -77,6 +130,10 @@ $ helm upgrade \-\-set foo=bar \-\-set foo=newbar redis ./redis \fB\-\-force\fP[=false] force resource update through delete/recreate if needed +.PP +\fB\-h\fP, \fB\-\-help\fP[=false] + help for upgrade + .PP \fB\-i\fP, \fB\-\-install\fP[=false] if a release by this name doesn't already exist, run an install @@ -86,17 +143,21 @@ $ helm upgrade \-\-set foo=bar \-\-set foo=newbar redis ./redis identify HTTPS client using this SSL key file .PP -\fB\-\-keyring\fP="~/.gnupg/pubring.gpg" +\fB\-\-keyring\fP="/Users/grapevine/.gnupg/pubring.gpg" path to the keyring that contains public signing keys .PP -\fB\-\-namespace\fP="default" - namespace to install the release into (only used if \-\-install is set) +\fB\-\-namespace\fP="" + namespace to install the release into (only used if \-\-install is set). Defaults to the current kube config namespace .PP \fB\-\-no\-hooks\fP[=false] disable pre/post upgrade hooks +.PP +\fB\-\-password\fP="" + chart repository password where to locate the requested chart + .PP \fB\-\-recreate\-pods\fP[=false] performs pods restart for the resource if applicable @@ -111,15 +172,23 @@ $ helm upgrade \-\-set foo=bar \-\-set foo=newbar redis ./redis .PP \fB\-\-reuse\-values\fP[=false] - when upgrading, reuse the last release's values, and merge in any new values. If '\-\-reset\-values' is specified, this is ignored. + when upgrading, reuse the last release's values and merge in any overrides from the command line via \-\-set and \-f. If '\-\-reset\-values' is specified, this is ignored. .PP \fB\-\-set\fP=[] set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) +.PP +\fB\-\-set\-file\fP=[] + set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2) + +.PP +\fB\-\-set\-string\fP=[] + set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) + .PP \fB\-\-timeout\fP=300 - time in seconds to wait for any individual kubernetes operation (like Jobs for hooks) + time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks) .PP \fB\-\-tls\fP[=false] @@ -133,6 +202,10 @@ $ helm upgrade \-\-set foo=bar \-\-set foo=newbar redis ./redis \fB\-\-tls\-cert\fP="$HELM\_HOME/cert.pem" path to TLS certificate file +.PP +\fB\-\-tls\-hostname\fP="" + the server name used to verify the hostname on the returned certificates from the server + .PP \fB\-\-tls\-key\fP="$HELM\_HOME/key.pem" path to TLS key file @@ -141,6 +214,10 @@ $ helm upgrade \-\-set foo=bar \-\-set foo=newbar redis ./redis \fB\-\-tls\-verify\fP[=false] enable TLS for request and verify remote +.PP +\fB\-\-username\fP="" + chart repository username where to locate the requested chart + .PP \fB\-f\fP, \fB\-\-values\fP=[] specify values in a YAML file or a URL(can specify multiple) @@ -164,20 +241,28 @@ $ helm upgrade \-\-set foo=bar \-\-set foo=newbar redis ./redis enable verbose output .PP -\fB\-\-home\fP="~/.helm" +\fB\-\-home\fP="/Users/grapevine/.helm" location of your Helm config. Overrides $HELM\_HOME .PP -\fB\-\-host\fP="localhost:44134" - address of tiller. Overrides $HELM\_HOST +\fB\-\-host\fP="" + address of Tiller. Overrides $HELM\_HOST .PP \fB\-\-kube\-context\fP="" name of the kubeconfig context to use +.PP +\fB\-\-kubeconfig\fP="" + absolute path to the kubeconfig file to use + +.PP +\fB\-\-tiller\-connection\-timeout\fP=300 + the duration (in seconds) Helm will wait to establish a connection to tiller + .PP \fB\-\-tiller\-namespace\fP="kube\-system" - namespace of tiller + namespace of Tiller .SH SEE ALSO @@ -187,4 +272,4 @@ $ helm upgrade \-\-set foo=bar \-\-set foo=newbar redis ./redis .SH HISTORY .PP -19\-May\-2017 Auto generated by spf13/cobra +24\-Aug\-2018 Auto generated by spf13/cobra diff --git a/docs/plugins.md b/docs/plugins.md index b2cc3c812..3087d1b39 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -134,7 +134,7 @@ downloaders: If such plugin is installed, Helm can interact with the repository using the specified protocol scheme by invoking the `command`. The special repository shall be added -similarily to the regular ones: `helm repo add favorite myprotocol://example.com/` +similarly to the regular ones: `helm repo add favorite myprotocol://example.com/` The rules for the special repos are the same to the regular ones: Helm must be able to download the `index.yaml` file in order to discover and cache the list of available Charts. @@ -183,7 +183,7 @@ If a plugin specifies `useTunnel: true`, Helm will do the following (in order): 5. Close the tunnel The tunnel is removed as soon as the `command` returns. So, for example, a -command cannot background a process and assume that that process will be able +command cannot background a process and assume that process will be able to use the tunnel. ## A Note on Flag Parsing diff --git a/docs/provenance.md b/docs/provenance.md index 1eb69f8f3..331074e8c 100644 --- a/docs/provenance.md +++ b/docs/provenance.md @@ -4,13 +4,6 @@ Helm has provenance tools which help chart users verify the integrity and origin of a package. Using industry-standard tools based on PKI, GnuPG, and well-respected package managers, Helm can generate and verify signature files. -**Note:** -Version 2.0.0-alpha.4 introduced a system for verifying the authenticity of charts. -While we do not anticipate that any major changes will be made to the file formats -or provenancing algorithms, this portion of Helm is not considered _frozen_ until -2.0.0-RC1 is released. The original plan for this feature can be found -[at issue 983](https://github.com/kubernetes/helm/issues/983). - ## Overview Integrity is established by comparing a chart to a provenance record. Provenance diff --git a/docs/quickstart.md b/docs/quickstart.md index 52a7c800f..8622137b2 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -65,7 +65,7 @@ This will install Tiller into the Kubernetes cluster you saw with **TIP:** When you want to upgrade Tiller, just run `helm init --upgrade`. -By default, when Tiller is installed,it does not have authentication enabled. +By default, when Tiller is installed, it does not have authentication enabled. To learn more about configuring strong TLS authentication for Tiller, consult [the Tiller TLS guide](tiller_ssl.md). diff --git a/docs/rbac.md b/docs/rbac.md index bc138ceee..4af36203c 100644 --- a/docs/rbac.md +++ b/docs/rbac.md @@ -4,21 +4,16 @@ In Kubernetes, granting a role to an application-specific service account is a b Bitnami also has a fantastic guide for [configuring RBAC in your cluster](https://docs.bitnami.com/kubernetes/how-to/configure-rbac-in-your-kubernetes-cluster/) that takes you through RBAC basics. -This guide is for users who want to restrict tiller's capabilities to install resources to certain namespaces, or to grant a helm client running access to a tiller instance. +This guide is for users who want to restrict Tiller's capabilities to install resources to certain namespaces, or to grant a Helm client running access to a Tiller instance. ## Tiller and Role-based Access Control -You can add a service account to Tiller using the `--service-account ` flag while you're configuring helm. As a prerequisite, you'll have to create a role binding which specifies a [role](https://kubernetes.io/docs/admin/authorization/rbac/#role-and-clusterrole) and a [service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) name that have been set up in advance. +You can add a service account to Tiller using the `--service-account ` flag while you're configuring Helm. As a prerequisite, you'll have to create a role binding which specifies a [role](https://kubernetes.io/docs/admin/authorization/rbac/#role-and-clusterrole) and a [service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) name that have been set up in advance. Once you have satisfied the pre-requisite and have a service account with the correct permissions, you'll run a command like this: `helm init --service-account ` ### Example: Service account with cluster-admin role -```console -$ kubectl create serviceaccount tiller --namespace kube-system -serviceaccount "tiller" created -``` - In `rbac-config.yaml`: ```yaml @@ -51,7 +46,7 @@ clusterrolebinding "tiller" created $ helm init --service-account tiller ``` -### Example: Deploy tiller in a namespace, restricted to deploying resources only in that namespace +### Example: Deploy Tiller in a namespace, restricted to deploying resources only in that namespace In the example above, we gave Tiller admin access to the entire cluster. You are not at all required to give Tiller cluster-admin access for it to work. Instead of specifying a ClusterRole or a ClusterRoleBinding, you can specify a Role and RoleBinding to limit Tiller's scope to a particular namespace. @@ -62,7 +57,7 @@ $ kubectl create serviceaccount tiller --namespace tiller-world serviceaccount "tiller" created ``` -Define a Role that allows tiller to manage all resources in `tiller-world` like in `role-tiller.yaml`: +Define a Role that allows Tiller to manage all resources in `tiller-world` like in `role-tiller.yaml`: ```yaml kind: Role @@ -71,7 +66,7 @@ metadata: name: tiller-manager namespace: tiller-world rules: -- apiGroups: ["", "extensions", "apps"] +- apiGroups: ["", "batch", "extensions", "apps"] resources: ["*"] verbs: ["*"] ``` @@ -104,13 +99,13 @@ $ kubectl create -f rolebinding-tiller.yaml rolebinding "tiller-binding" created ``` -Afterwards you can run `helm init` to install tiller in the `tiller-world` namespace. +Afterwards you can run `helm init` to install Tiller in the `tiller-world` namespace. ```console $ helm init --service-account tiller --tiller-namespace tiller-world $HELM_HOME has been configured at /Users/awesome-user/.helm. -Tiller (the helm server side component) has been installed into your Kubernetes Cluster. +Tiller (the Helm server side component) has been installed into your Kubernetes Cluster. Happy Helming! $ helm install nginx --tiller-namespace tiller-world --namespace tiller-world @@ -125,11 +120,11 @@ NAME READY STATUS RESTARTS AGE wayfaring-yak-alpine 0/1 ContainerCreating 0 0s ``` -### Example: Deploy tiller in a namespace, restricted to deploying resources in another namespace +### Example: Deploy Tiller in a namespace, restricted to deploying resources in another namespace In the example above, we gave Tiller admin access to the namespace it was deployed inside. Now, let's limit Tiller's scope to deploy resources in a different namespace! -For example, let's install tiller in the namespace `myorg-system` and allow tiller to deploy resources in the namespace `myorg-users`. +For example, let's install Tiller in the namespace `myorg-system` and allow Tiller to deploy resources in the namespace `myorg-users`. ```console $ kubectl create namespace myorg-system @@ -138,7 +133,7 @@ $ kubectl create serviceaccount tiller --namespace myorg-system serviceaccount "tiller" created ``` -Define a Role that allows tiller to manage all resources in `myorg-users` like in `role-tiller.yaml`: +Define a Role that allows Tiller to manage all resources in `myorg-users` like in `role-tiller.yaml`: ```yaml kind: Role @@ -180,7 +175,7 @@ $ kubectl create -f rolebinding-tiller.yaml rolebinding "tiller-binding" created ``` -We'll also need to grant tiller access to read configmaps in myorg-system so it can store release information. In `role-tiller-myorg-system.yaml`: +We'll also need to grant Tiller access to read configmaps in myorg-system so it can store release information. In `role-tiller-myorg-system.yaml`: ```yaml kind: Role @@ -224,11 +219,11 @@ rolebinding "tiller-binding" created ## Helm and Role-based Access Control -When running a helm client in a pod, in order for the helm client to talk to a tiller instance, it will need certain privileges to be granted. Specifically, the helm client will need to be able to create pods, forward ports and be able to list pods in the namespace where tiller is running (so it can find tiller). +When running a Helm client in a pod, in order for the Helm client to talk to a Tiller instance, it will need certain privileges to be granted. Specifically, the Helm client will need to be able to create pods, forward ports and be able to list pods in the namespace where Tiller is running (so it can find Tiller). ### Example: Deploy Helm in a namespace, talking to Tiller in another namespace -In this example, we will assume tiller is running in a namespace called `tiller-world` and that the helm client is running in a namespace called `helm-world`. By default, tiller is running in the `kube-system` namespace. +In this example, we will assume Tiller is running in a namespace called `tiller-world` and that the Helm client is running in a namespace called `helm-world`. By default, Tiller is running in the `kube-system` namespace. In `helm-user.yaml`: diff --git a/docs/related.md b/docs/related.md index c14eb3880..082684d9c 100644 --- a/docs/related.md +++ b/docs/related.md @@ -6,43 +6,50 @@ add to this list, please open an [issue](https://github.com/kubernetes/helm/issu or [pull request](https://github.com/kubernetes/helm/pulls). ## Article, Blogs, How-Tos, and Extra Documentation -- [Using Helm to Deploy to Kubernetes](https://daemonza.github.io/2017/02/20/using-helm-to-deploy-to-kubernetes/) -- [Honestbee's Helm Chart Conventions](https://gist.github.com/so0k/f927a4b60003cedd101a0911757c605a) + +- [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) +- [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/) +- [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) -- [CI/CD with Kubernetes, Helm & Wercker ](http://www.slideshare.net/Diacode/cicd-with-kubernetes-helm-wercker-madscalability) -- [The missing CI/CD Kubernetes component: Helm package manager](https://hackernoon.com/the-missing-ci-cd-kubernetes-component-helm-package-manager-1fe002aac680#.691sk2zhu) +- [The Missing CI/CD Kubernetes Component: Helm package manager](https://hackernoon.com/the-missing-ci-cd-kubernetes-component-helm-package-manager-1fe002aac680#.691sk2zhu) - [The Workflow "Umbrella" Helm Chart](https://deis.com/blog/2017/workflow-chart-assembly) -- [GitLab, Consumer Driven Contracts, Helm and Kubernetes](https://medium.com/@enxebre/gitlab-consumer-driven-contracts-helm-and-kubernetes-b7235a60a1cb#.xwp1y4tgi) +- [Using Helm to Deploy to Kubernetes](https://daemonza.github.io/2017/02/20/using-helm-to-deploy-to-kubernetes/) - [Writing a Helm Chart](https://www.influxdata.com/packaged-kubernetes-deployments-writing-helm-chart/) -- [Creating a Helm Plugin in 3 Steps](http://technosophos.com/2017/03/21/creating-a-helm-plugin.html) +- [A basic walk through Kubernetes Helm](https://github.com/muffin87/helm-tutorial) +- [Tillerless Helm v2](https://rimusz.net/tillerless-helm/) ## Video, Audio, and Podcast - [CI/CD with Jenkins, Kubernetes, and Helm](https://www.youtube.com/watch?v=NVoln4HdZOY): AKA "The Infamous Croc Hunter Video". -- [KubeCon2016: Delivering Kubernetes-Native Applications by Michelle Noorali](https://www.youtube.com/watch?v=zBc1goRfk3k&index=49&list=PLj6h78yzYM2PqgIGU1Qmi8nY7dqn9PCr4) - [Helm with Michelle Noorali and Matthew Butcher](https://gcppodcast.com/post/episode-50-helm-with-michelle-noorali-and-matthew-butcher/): The official Google CloudPlatform Podcast interviews Michelle and Matt about Helm. +- [KubeCon2016: Delivering Kubernetes-Native Applications by Michelle Noorali](https://www.youtube.com/watch?v=zBc1goRfk3k&index=49&list=PLj6h78yzYM2PqgIGU1Qmi8nY7dqn9PCr4) ## Helm Plugins -- [helm-tiller](https://github.com/adamreese/helm-tiller) - Additional commands to work with Tiller -- [Technosophos's Helm Plugins](https://github.com/technosophos/helm-plugins) - Plugins for GitHub, Keybase, and GPG -- [helm-template](https://github.com/technosophos/helm-template) - Debug/render templates client-side -- [Helm Value Store](https://github.com/skuid/helm-value-store) - Plugin for working with Helm deployment values -- [Helm Diff](https://github.com/databus23/helm-diff) - Preview `helm upgrade` as a coloured diff -- [helm-env](https://github.com/adamreese/helm-env) - Plugin to show current environment -- [helm-last](https://github.com/adamreese/helm-last) - Plugin to show the latest release -- [helm-nuke](https://github.com/adamreese/helm-nuke) - Plugin to destroy all releases -- [helm-local](https://github.com/adamreese/helm-local) - Plugin to run Tiller as a local daemon - [App Registry](https://github.com/app-registry/helm-plugin) - Plugin to manage charts via the [App Registry specification](https://github.com/app-registry/spec) -- [helm-secrets](https://github.com/futuresimple/helm-secrets) - Plugin to manage and store secrets safely +- [Helm Diff](https://github.com/databus23/helm-diff) - Preview `helm upgrade` as a coloured diff +- [Helm Value Store](https://github.com/skuid/helm-value-store) - Plugin for working with Helm deployment values +- [Technosophos's Helm Plugins](https://github.com/technosophos/helm-plugins) - Plugins for GitHub, Keybase, and GPG +- [helm-cos](https://github.com/imroc/helm-cos) - Plugin to manage repositories on Tencent Cloud Object Storage - [helm-edit](https://github.com/mstrzele/helm-edit) - Plugin for editing release's values +- [helm-env](https://github.com/adamreese/helm-env) - Plugin to show current environment - [helm-gcs](https://github.com/nouney/helm-gcs) - Plugin to manage repositories on Google Cloud Storage - [helm-github](https://github.com/sagansystems/helm-github) - Plugin to install Helm Charts from Github repositories -- [helm-monitor](https://github.com/ContainerSolutions/helm-monitor) - Plugin to monitor a release and rollback based on Prometheus/ElasticSearch query -- [helm-k8comp](https://github.com/cststack/k8comp) - Plugin to create Helm Charts from hiera using k8comp - [helm-hashtag](https://github.com/balboah/helm-hashtag) - Plugin for tracking docker tag hash digests as values +- [helm-k8comp](https://github.com/cststack/k8comp) - Plugin to create Helm Charts from hiera using k8comp +- [helm-last](https://github.com/adamreese/helm-last) - Plugin to show the latest release +- [helm-local](https://github.com/adamreese/helm-local) - Plugin to run Tiller as a local daemon +- [helm-monitor](https://github.com/ContainerSolutions/helm-monitor) - Plugin to monitor a release and rollback based on Prometheus/ElasticSearch query +- [helm-nuke](https://github.com/adamreese/helm-nuke) - Plugin to destroy all releases +- [helm-secrets](https://github.com/futuresimple/helm-secrets) - Plugin to manage and store secrets safely +- [helm-stop](https://github.com/IBM/helm-stop) - Plugin for stopping a release pods +- [helm-template](https://github.com/technosophos/helm-template) - Debug/render templates client-side +- [helm-tiller](https://github.com/adamreese/helm-tiller) - Additional commands to work with Tiller - [helm-unittest](https://github.com/lrills/helm-unittest) - Plugin for unit testing chart locally with YAML +- [Tillerless Helm v2](https://github.com/rimusz/helm-tiller) - Helm plugin for using Tiller locally and in CI/CD pipelines We also encourage GitHub authors to use the [helm-plugin](https://github.com/search?q=topic%3Ahelm-plugin&type=Repositories) tag on their plugin repositories. @@ -52,32 +59,33 @@ tag on their plugin repositories. Tools layered on top of Helm or Tiller. - [AppsCode Swift](https://github.com/appscode/swift) - Ajax friendly Helm Tiller Proxy using [grpc-gateway](https://github.com/grpc-ecosystem/grpc-gateway) -- [Quay App Registry](https://coreos.com/blog/quay-application-registry-for-kubernetes.html) - Open Kubernetes application registry, including a Helm access client -- [Chartify](https://github.com/appscode/chartify) - Generate Helm charts from existing Kubernetes resources. -- [VIM-Kubernetes](https://github.com/andrewstuart/vim-kubernetes) - VIM plugin for Kubernetes and Helm -- [Landscaper](https://github.com/Eneco/landscaper/) - "Landscaper takes a set of Helm Chart references with values (a desired state), and realizes this in a Kubernetes cluster." -- [Rudder](https://github.com/AcalephStorage/rudder) - RESTful (JSON) proxy for Tiller's API -- [Helmfile](https://github.com/roboll/helmfile) - Helmfile is a declarative spec for deploying helm charts +- [Armada](https://github.com/att-comdev/armada) - Manage prefixed releases throughout various Kubernetes namespaces, and removes completed jobs for complex deployments. Used by the [Openstack-Helm](https://github.com/openstack/openstack-helm) team. - [Autohelm](https://github.com/reactiveops/autohelm) - Autohelm is _another_ simple declarative spec for deploying helm charts. Written in python and supports git urls as a source for helm charts. -- [Helmsman](https://github.com/Praqma/helmsman) - Helmsman is a helm-charts-as-code tool which enables installing/upgrading/protecting/moving/deleting releases from version controlled desired state files (described in a simple TOML format). -- [Schelm](https://github.com/databus23/schelm) - Render a Helm manifest to a directory -- [Drone.io Helm Plugin](http://plugins.drone.io/ipedrazas/drone-helm/) - Run Helm inside of the Drone CI/CD system +- [ChartMuseum](https://github.com/chartmuseum/chartmuseum) - Helm Chart Repository with support for Amazon S3 and Google Cloud Storage +- [Chartify](https://github.com/appscode/chartify) - Generate Helm charts from existing Kubernetes resources. +- [Codefresh](https://codefresh.io) - Kubernetes native CI/CD and management platform with UI dashboards for managing Helm charts and releases - [Cog](https://github.com/ohaiwalt/cog-helm) - Helm chart to deploy Cog on Kubernetes -- [Monocular](https://github.com/helm/monocular) - Web UI for Helm Chart repositories +- [Drone.io Helm Plugin](http://plugins.drone.io/ipedrazas/drone-helm/) - Run Helm inside of the Drone CI/CD system - [Helm Chart Publisher](https://github.com/luizbafilho/helm-chart-publisher) - HTTP API for publishing Helm Charts in an easy way -- [Armada](https://github.com/att-comdev/armada) - Manage prefixed releases throughout various Kubernetes namespaces, and removes completed jobs for complex deployments. Used by the [Openstack-Helm](https://github.com/openstack/openstack-helm) team. -- [ChartMuseum](https://github.com/chartmuseum/chartmuseum) - Helm Chart Repository with support for Amazon S3 and Google Cloud Storage - [Helm.NET](https://github.com/qmfrederik/helm) - A .NET client for Tiller's API -- [Codefresh](https://codefresh.io) - Kubernetes native CI/CD and management platform with UI dashboards for managing Helm charts and releases +- [Helmfile](https://github.com/roboll/helmfile) - Helmfile is a declarative spec for deploying helm charts +- [Helmsman](https://github.com/Praqma/helmsman) - Helmsman is a helm-charts-as-code tool which enables installing/upgrading/protecting/moving/deleting releases from version controlled desired state files (described in a simple TOML format). +- [Landscaper](https://github.com/Eneco/landscaper/) - "Landscaper takes a set of Helm Chart references with values (a desired state), and realizes this in a Kubernetes cluster." +- [Monocular](https://github.com/helm/monocular) - Web UI for Helm Chart repositories +- [Quay App Registry](https://coreos.com/blog/quay-application-registry-for-kubernetes.html) - Open Kubernetes application registry, including a Helm access client +- [Rudder](https://github.com/AcalephStorage/rudder) - RESTful (JSON) proxy for Tiller's API +- [Schelm](https://github.com/databus23/schelm) - Render a Helm manifest to a directory +- [VIM-Kubernetes](https://github.com/andrewstuart/vim-kubernetes) - VIM plugin for Kubernetes and Helm ## Helm Included Platforms, distributions, and services that include Helm support. -- [Kubernetic](https://kubernetic.com/) - Kubernetes Desktop Client - [Cabin](http://www.skippbox.com/cabin/) - Mobile App for Managing Kubernetes -- [Qstack](https://qstack.com) - [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) +- [Kubernetic](https://kubernetic.com/) - Kubernetes Desktop Client +- [Qstack](https://qstack.com) ## Misc diff --git a/docs/release_checklist.md b/docs/release_checklist.md index 9bb3ae00c..96d7e5625 100644 --- a/docs/release_checklist.md +++ b/docs/release_checklist.md @@ -2,9 +2,36 @@ **IMPORTANT**: If your experience deviates from this document, please document the changes to keep it up-to-date. +## Release Meetings +As part of the release process, two of the weekly developer calls will be co-opted +as "release meetings." + +### Start of the Release Cycle +The first developer call after a release will be used as the release meeting to +start the next release cycle. During this meeting, the following items must be +identified: + +- Release date +- Goals/Objectives for this release +- The release manager (basically whoever is going to cut the release) +- Any other important details for the community + +All of this information should be added to the GitHub milestone for the given +release. This should give the community and maintainers a clear set of guidelines +to follow when choosing whether or not to add issues and PRs to a given release. + +### End (almost) of the Release Cycle +The developer call closest to two weeks before the scheduled release date will +be used to review any remaining PRs that should be pulled into the release. This +is the place to debate whether or not we should wait before cutting a release and +any other concerns. At the end of this meeting, if the release date has not been +pushed out, the first RC should be cut. Subsequent developer calls in between this +meeting and the release date should have some time set aside to see if any bugs +were found. Once the release date is reached, the final release can be cut + ## A Maintainer's Guide to Releasing Helm -So you're in charge of a new release for helm? Cool. Here's what to do... +So you're in charge of a new release for Helm? Cool. Here's what to do... ![TODO: Nothing](images/nothing.png) @@ -24,8 +51,8 @@ In this doc, we are going to reference a few environment variables as well, whic ```shell export RELEASE_NAME=vX.Y.0 -export RELEASE_BRANCH_NAME="release-$RELEASE_NAME" -export RELEASE_CANDIDATE_NAME="$RELEASE_NAME-rc1" +export RELEASE_BRANCH_NAME="release-X.Y" +export RELEASE_CANDIDATE_NAME="$RELEASE_NAME-rc.1" ``` If you are creating a patch release, you may want to use the following instead: @@ -34,7 +61,7 @@ If you are creating a patch release, you may want to use the following instead: export PREVIOUS_PATCH_RELEASE=vX.Y.Z export RELEASE_NAME=vX.Y.Z+1 export RELEASE_BRANCH_NAME="release-X.Y" -export RELEASE_CANDIDATE_NAME="$RELEASE_NAME-rc1" +export RELEASE_CANDIDATE_NAME="$RELEASE_NAME-rc.1" ``` ## 1. Create the Release Branch @@ -94,33 +121,6 @@ index 2109a0a..6f5a1a4 100644 BuildMetadata = "unreleased" ``` -The README stores links to the latest release for helm. We want to change the version to the first release candidate which we are releasing (more on that in step 5). - -```shell -$ git diff README.md -diff --git a/README.md b/README.md -index 022afd79..547839e2 100644 ---- a/README.md -+++ b/README.md -@@ -34,10 +34,10 @@ Think of it like apt/yum/homebrew for Kubernetes. - - Binary downloads of the Helm client can be found at the following links: - --- [OSX](https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-darwin-amd64.tar.gz) --- [Linux](https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-linux-amd64.tar.gz) --- [Linux 32-bit](https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-linux-386.tar.gz) --- [Windows](https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-windows-amd64.tar.gz) -+- [OSX](https://kubernetes-helm.storage.googleapis.com/helm-v2.8.0-darwin-amd64.tar.gz) -+- [Linux](https://kubernetes-helm.storage.googleapis.com/helm-v2.8.0-linux-amd64.tar.gz) -+- [Linux 32-bit](https://kubernetes-helm.storage.googleapis.com/helm-v2.8.0-linux-386.tar.gz) -+- [Windows](https://kubernetes-helm.storage.googleapis.com/helm-v2.8.0-windows-amd64.tar.gz) - - Unpack the `helm` binary and add it to your PATH and you are good to go! - macOS/[homebrew](https://brew.sh/) users can also use `brew install kubernetes-helm`. -``` - -For patch releases, the old version number will be the latest patch release, so just bump the patch number, incrementing Z by one. - ```shell git add . git commit -m "bump version to $RELEASE_CANDIDATE_NAME" @@ -166,7 +166,7 @@ wget https://kubernetes-helm.storage.googleapis.com/helm-$RELEASE_CANDIDATE_NAME windows/amd64, using PowerShell: ```shell -PS C:\> Invoke-WebRequest -Uri "https://kubernetes-helm.storage.googleapis.com/helm-$RELEASE_CANDIDATE_NAME-windows-amd64.tar.gz" -OutFile "helm-$ReleaseCandidateName-windows-amd64.tar.gz" +PS C:\> Invoke-WebRequest -Uri "https://kubernetes-helm.storage.googleapis.com/helm-$RELEASE_CANDIDATE_NAME-windows-amd64.zip" -OutFile "helm-$ReleaseCandidateName-windows-amd64.zip" ``` Then, unpack and move the binary to somewhere on your $PATH, or move it somewhere and add it to your $PATH (e.g. /usr/local/bin/helm for linux/macOS, C:\Program Files\helm\helm.exe for Windows). @@ -188,7 +188,7 @@ You will also want to update the release version number and the CHANGELOG as we After that, tag it and notify users of the new release candidate: ```shell -export RELEASE_CANDIDATE_NAME="$RELEASE_NAME-rc2" +export RELEASE_CANDIDATE_NAME="$RELEASE_NAME-rc.2" git tag --sign --annotate "${RELEASE_CANDIDATE_NAME}" --message "Helm release ${RELEASE_CANDIDATE_NAME}" git push upstream $RELEASE_CANDIDATE_NAME ``` @@ -197,7 +197,7 @@ From here on just repeat this process, continuously testing until you're happy w ## 6. Finalize the Release -When you're finally happy with the quality of a release candidate, you can move on and create the real thing. Double-check one last time to make sure eveything is in order, then finally push the release tag. +When you're finally happy with the quality of a release candidate, you can move on and create the real thing. Double-check one last time to make sure everything is in order, then finally push the release tag. ```shell git checkout $RELEASE_BRANCH_NAME @@ -218,21 +218,25 @@ An example release note for a minor release would look like this: Helm vX.Y.Z is a feature release. This release, we focused on . Users are encouraged to upgrade for the best experience. -The community keeps growing, and we'd love to see you there. +The community keeps growing, and we'd love to see you there! - Join the discussion in [Kubernetes Slack](https://slack.k8s.io/): - `#helm-users` for questions and just to hang out - `#helm-dev` for discussing PRs, code, and bugs -- Hang out at the Public Developer Call: Thursday, 9:30 Pacific via [Zoom](https://zoom.us/j/4526666954) +- Hang out at the Public Developer Call: Thursday, 9:30 Pacific via [Zoom](https://zoom.us/j/696660622) - Test, debug, and contribute charts: [GitHub/kubernetes/charts](https://github.com/kubernetes/charts) ## Installation and Upgrading Download Helm X.Y. The common platform binaries are here: -- [OSX](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-darwin-amd64.tar.gz) -- [Linux](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-amd64.tar.gz) -- [Windows](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-windows-amd64.tar.gz) +- [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)) +- [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)) Once you have the client installed, upgrade Tiller with `helm init --upgrade`. @@ -258,7 +262,7 @@ git log --no-merges --pretty=format:'- %s %H (%aN)' $RELEASE_NAME $PREVIOUS_RELE Once finished, go into GitHub and edit the release notes for the tagged release with the notes written here. -## 9. Evangelize +## 8. Evangelize Congratulations! You're done. Go grab yourself a $DRINK_OF_CHOICE. You've earned it. diff --git a/docs/securing_installation.md b/docs/securing_installation.md index ffce5df75..454e0cc12 100644 --- a/docs/securing_installation.md +++ b/docs/securing_installation.md @@ -34,7 +34,7 @@ There are four main areas to consider when securing a tiller installation: ### RBAC -Recent versions of Kubernetes employ a [role-based access control (or RBAC)](https://en.wikipedia.org/wiki/Role-based_access_control) system (as do modern operating systems) to help mitigate the damage that can done if credentials are misused or bugs exist. Even where an identity is hijacked, the identity has only so many permissions to a controlled space. This effectively adds a layer of security to limit the scope of any attack with that identity. +Recent versions of Kubernetes employ a [role-based access control (or RBAC)](https://en.wikipedia.org/wiki/Role-based_access_control) system (as do modern operating systems) to help mitigate the damage that can be done if credentials are misused or bugs exist. Even where an identity is hijacked, the identity has only so many permissions to a controlled space. This effectively adds a layer of security to limit the scope of any attack with that identity. Helm and Tiller are designed to install, remove, and modify logical applications that can contain many services interacting together. As a result, often its usefulness involves cluster-wide operations, which in a multitenant cluster means that great care must be taken with access to a cluster-wide Tiller installation to prevent improper activity. @@ -53,11 +53,11 @@ This situation may change in the future. While the community has several methods In the default installation the gRPC endpoint that Tiller offers is available inside the cluster (not external to the cluster) without authentication configuration applied. Without applying authentication, any process in the cluster can use the gRPC endpoint to perform operations inside the cluster. In a local or secured private cluster, this enables rapid usage and is normal. (When running outside the cluster, Helm authenticates through the Kubernetes API server to reach Tiller, leveraging existing Kubernetes authentication support.) -Shared and production clusters -- for the most part -- should use Helm 2.7.2 at a minimum and configure TLS for each Tiller gRPC endpoint to ensure that within the cluster usage of gRPC endpoints is only for the properly authenticated identity for that endpoint. Doing so enables any number of Tiller instances to be deployed in any number of namespaces and yet no unauthenticated usage of any gRPC endpoint is possible. Finally, usa Helm `init` with the `--tiller-tls-verify` option to install Tiller with TLS enabled and to verify remote certificates, and all other Helm commands should use the `--tls` option. +Shared and production clusters -- for the most part -- should use Helm 2.7.2 at a minimum and configure TLS for each Tiller gRPC endpoint to ensure that within the cluster usage of gRPC endpoints is only for the properly authenticated identity for that endpoint. Doing so enables any number of Tiller instances to be deployed in any number of namespaces and yet no unauthenticated usage of any gRPC endpoint is possible. Finally, use Helm `init` with the `--tiller-tls-verify` option to install Tiller with TLS enabled and to verify remote certificates, and all other Helm commands should use the `--tls` option. For more information about the proper steps to configure Tiller and use Helm properly with TLS configured, see [Using SSL between Helm and Tiller](tiller_ssl.md). -When Helm clients are connecting from outside of the cluster, the security between the Helm client and the API server is managed by Kubernetes itself. You may want to ensure that this link is secure. Note that if you are using the TLS configuration recommended above, not even the Kubernetes API server has access to the unencrypted messages between the client and Tiller. +When Helm clients are connecting from outside of the cluster, the security between the Helm client and the API server is managed by Kubernetes itself. You may want to ensure that this link is secure. Note that if you are using the TLS configuration recommended above, not even the Kubernetes API server has access to the encrypted messages between the client and Tiller. ### Tiller's Release Information @@ -65,13 +65,13 @@ For historical reasons, Tiller stores its release information in ConfigMaps. We Secrets are the Kubernetes accepted mechanism for saving configuration data that is considered sensitive. While secrets don't themselves offer many protections, Kubernetes cluster management software often treats them differently than other objects. Thus, we suggest using secrets to store releases. -Enabling this feature currently requires setting the `--storage=secret` flag in the tiller-deploy deployment. This entails directly modifying the deployment or using `helm init --override=...`, as no helm init flag is currently available to do this for you. For more information, see [Using --override](install.md#using---override). +Enabling this feature currently requires setting the `--storage=secret` flag in the tiller-deploy deployment. This entails directly modifying the deployment or using `helm init --override 'spec.template.spec.containers[0].command'='{/tiller,--storage=secret}'`, as no helm init flag is currently available to do this for you. ### Thinking about Charts Because of the relative longevity of Helm, the Helm chart ecosystem evolved without the immediate concern for cluster-wide control, and especially in the developer space this makes complete sense. However, charts are a kind of package that not only installs containers you may or may not have validated yourself, but it may also install into more than one namespace. -As with all shared software, in a controlled or shared environment you must validate all software you install yourself _before_ you install it. If you have secured Tiller with TLS and have installed it with permissions to only one or a subset of namespaces, some charts may fail to install -- but in these environments, that is exactly what you want. If you need to use the chart, you may have to work with the creator or modify it yourself in order to use it securely in a mulitenant cluster with proper RBAC rules applied. The `helm template` command renders the chart locally and displays the output. +As with all shared software, in a controlled or shared environment you must validate all software you install yourself _before_ you install it. If you have secured Tiller with TLS and have installed it with permissions to only one or a subset of namespaces, some charts may fail to install -- but in these environments, that is exactly what you want. If you need to use the chart, you may have to work with the creator or modify it yourself in order to use it securely in a multitenant cluster with proper RBAC rules applied. The `helm template` command renders the chart locally and displays the output. Once vetted, you can use Helm's provenance tools to [ensure the provenance and integrity of charts](provenance.md) that you use. @@ -93,15 +93,16 @@ If these steps are followed, an example `helm init` command might look something ```bash $ helm init \ +--override 'spec.template.spec.containers[0].command'='{/tiller,--storage=secret}' \ --tiller-tls \ --tiller-tls-verify \ ---tiller-tls-ca-cert=ca.pem \ --tiller-tls-cert=cert.pem \ --tiller-tls-key=key.pem \ ---service-account=accountname +--tls-ca-cert=ca.pem \ +--service-account=accountname ``` -This command will start Tiller with both strong authentication over gRPC, and a service account to which RBAC policies have been applied. +This command will start Tiller with strong authentication over gRPC, release information stored in a Kubernetes Secret, and a service account to which RBAC policies have been applied. diff --git a/docs/tiller_ssl.md b/docs/tiller_ssl.md index db1603068..41e704653 100644 --- a/docs/tiller_ssl.md +++ b/docs/tiller_ssl.md @@ -148,10 +148,10 @@ $ openssl req -key helm.key.pem -new -sha256 -out helm.csr.pem (In rare cases, we've had to add the `-nodes` flag when generating the request.) -Now we sign each of these CSRs with the CA certificate we created: +Now we sign each of these CSRs with the CA certificate we created (adjust the days parameter to suit your requirements): ```console -$ openssl x509 -req -CA ca.cert.pem -CAkey ca.key.pem -CAcreateserial -in tiller.csr.pem -out tiller.cert.pem +$ openssl x509 -req -CA ca.cert.pem -CAkey ca.key.pem -CAcreateserial -in tiller.csr.pem -out tiller.cert.pem -days 365 Signature ok subject=/C=US/ST=CO/L=Boulder/O=Tiller Server/CN=tiller-server Getting CA Private Key @@ -161,7 +161,7 @@ Enter pass phrase for ca.key.pem: And again for the client certificate: ```console -$ openssl x509 -req -CA ca.cert.pem -CAkey ca.key.pem -CAcreateserial -in helm.csr.pem -out helm.cert.pem +$ openssl x509 -req -CA ca.cert.pem -CAkey ca.key.pem -CAcreateserial -in helm.csr.pem -out helm.cert.pem -days 365 ``` At this point, the important files for us are these: @@ -251,7 +251,7 @@ This configuration sends our client-side certificate to establish identity, uses the client key for encryption, and uses the CA certificate to validate the remote Tiller's identity. -Typing a line that that is cumbersome, though. The shortcut is to move the key, +Typing a line that is cumbersome, though. The shortcut is to move the key, cert, and CA into `$HELM_HOME`: ```console @@ -284,6 +284,30 @@ the host name that Helm connects to matches the host name on the certificate. In some cases this is awkward, since Helm will connect over localhost, or the FQDN is not available for public resolution. +*If I use `--tls-verify` on the client, I get `Error: x509: cannot validate certificate for 127.0.0.1 because it doesn't contain any IP SANs`* + +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. +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. + +For example, to list 127.0.0.1 as an IP SAN when generating the Tiller certificate: + +```console +$ echo subjectAltName=IP:127.0.0.1 > extfile.cnf +$ openssl x509 -req -CA ca.cert.pem -CAkey ca.key.pem -CAcreateserial -in tiller.csr.pem -out tiller.cert.pem -days 365 -extfile extfile.cnf +``` + +Alternatively, you can override the expected hostname of the tiller certificate using the `--tls-hostname` flag. + +*If I use `--tls-verify` on the client, I get `Error: x509: certificate has expired or is not yet valid`* + +Your helm certificate has expired, you need to sign a new certificate using your private key and the CA (and consider increasing the number of days) + +If your tiller certificate has expired, you'll need to sign a new certificate, base64 encode it and update the Tiller Secret: +`kubectl edit secret tiller-secret` + ## References https://github.com/denji/golang-tls diff --git a/docs/using_helm.md b/docs/using_helm.md index 6bf7bc40a..b7fec60ed 100755 --- a/docs/using_helm.md +++ b/docs/using_helm.md @@ -43,7 +43,7 @@ carefully curated and maintained charts. This chart repository is named You can see which charts are available by running `helm search`: -``` +```console $ helm search NAME VERSION DESCRIPTION stable/drupal 0.3.2 One of the most versatile open source content m... @@ -56,7 +56,7 @@ stable/mysql 0.1.0 Chart for MySQL With no filter, `helm search` shows you all of the available charts. You can narrow down your results by searching with a filter: -``` +```console $ helm search mysql NAME VERSION DESCRIPTION stable/mysql 0.1.0 Chart for MySQL @@ -69,7 +69,7 @@ Why is `mariadb` in the list? Because its package description relates it to MySQL. We can use `helm inspect chart` to see this: -``` +```console $ helm inspect stable/mariadb Fetched stable/mariadb to mariadb-0.5.1.tgz description: Chart for MariaDB @@ -91,7 +91,7 @@ package you want to install, you can use `helm install` to install it. To install a new package, use the `helm install` command. At its simplest, it takes only one argument: The name of the chart. -``` +```console $ helm install stable/mariadb Fetched stable/mariadb-0.3.0 to /Users/mattbutcher/Code/Go/src/k8s.io/helm/mariadb-0.3.0.tgz happy-panda @@ -139,7 +139,7 @@ may take a long time to install into the cluster. To keep track of a release's state, or to re-read configuration information, you can use `helm status`: -``` +```console $ helm status happy-panda Last Deployed: Wed Sep 28 12:32:28 2016 Namespace: default @@ -227,7 +227,7 @@ There are two ways to pass configuration data during install: - `--values` (or `-f`): Specify a YAML file with overrides. This can be specified multiple times and the rightmost file will take precedence -- `--set`: Specify overrides on the command line. +- `--set` (and its variants `--set-string` and `--set-file`): Specify overrides on the command line. If both are used, `--set` values are merged into `--values` with higher precedence. Overrides specified with `--set` are persisted in a configmap. Values that have been @@ -285,7 +285,7 @@ servers: ``` Sometimes you need to use special characters in your `--set` lines. You can use -a backslash to escape the characters; `--set name=value1\,value2` will become: +a backslash to escape the characters; `--set name="value1\,value2"` will become: ```yaml name: "value1,value2" @@ -304,6 +304,35 @@ Deeply nested data structures can be difficult to express using `--set`. Chart designers are encouraged to consider the `--set` usage when designing the format of a `values.yaml` file. +Helm will cast certain values specified with `--set` to integers. +For example, `--set foo=true` results Helm to cast `true` into an int64 value. +In case you want a string, use a `--set`'s variant named `--set-string`. `--set-string foo=true` results in a string value of `"true"`. + +`--set-file key=filepath` is another variant of `--set`. +It reads the file and use its content as a value. +An example use case of it is to inject a multi-line text into values without dealing with indentation in YAML. +Say you want to create a [brigade](https://github.com/Azure/brigade) project with certain value containing 5 lines JavaScript code, you might write a `values.yaml` like: + +```yaml +defaultScript: | + const { events, Job } = require("brigadier") + function run(e, project) { + console.log("hello default script") + } + events.on("run", run) +``` + +Being embedded in a YAML, this makes it harder for you to use IDE features and testing framework and so on that supports writing code. +Instead, you can use `--set-file defaultScript=brigade.js` with `brigade.js` containing: + +```javascript +const { events, Job } = require("brigadier") +function run(e, project) { + console.log("hello default script") +} +events.on("run", run) +``` + ### More Installation Methods The `helm install` command can install from several sources: @@ -392,14 +421,14 @@ is not a full list of cli flags. To see a description of all flags, just run When it is time to uninstall or delete a release from the cluster, use the `helm delete` command: -``` +```console $ helm delete happy-panda ``` This will remove the release from the cluster. You can see all of your currently deployed releases with the `helm list` command: -``` +```console $ helm list NAME VERSION UPDATED STATUS CHART inky-cat 1 Wed Sep 28 12:59:46 2016 DEPLOYED alpine-0.1.0 diff --git a/glide.lock b/glide.lock index 1ccdae61c..9a89616ef 100644 --- a/glide.lock +++ b/glide.lock @@ -1,58 +1,21 @@ -hash: d93f565214b112cf8560e9cd2da2f3ab7852a1f19544569fc112bd4fb2d1d506 -updated: 2018-03-08T14:06:06.497394911-08:00 +hash: 9d3eee153a34027ed93ccbcbfb4778baead73ed3f5bd4c665114e02aef747606 +updated: 2018-08-01T07:48:30.2009451Z imports: - name: cloud.google.com/go version: 3b1ae45394a234c385be014e9a488f2bb6eef821 - repo: https://github.com/GoogleCloudPlatform/google-cloud-go.git subpackages: - - compute - compute/metadata - internal - name: github.com/aokoli/goutils version: 9c37978a95bd5c709a15883b6242714ea6709e64 - name: github.com/asaskevich/govalidator version: 7664702784775e51966f0885f5cd27435916517b -- name: github.com/aws/aws-sdk-go - version: 760741802ad40f49ae9fc4a69ef6706d2527d62e - subpackages: - - aws - - aws/awserr - - aws/awsutil - - aws/client - - aws/client/metadata - - aws/corehandlers - - aws/credentials - - aws/credentials/ec2rolecreds - - aws/credentials/endpointcreds - - aws/credentials/stscreds - - aws/defaults - - aws/ec2metadata - - aws/endpoints - - aws/request - - aws/session - - aws/signer/v4 - - internal/shareddefaults - - private/protocol - - private/protocol/ec2query - - private/protocol/json/jsonutil - - private/protocol/jsonrpc - - private/protocol/query - - private/protocol/query/queryutil - - private/protocol/rest - - private/protocol/xml/xmlutil - - service/autoscaling - - service/ec2 - - service/ecr - - service/elb - - service/elbv2 - - service/kms - - service/sts - name: github.com/Azure/go-ansiterm version: 19f72df4d05d31cbe1c56bfc8045c96babff6c7e subpackages: - winterm - name: github.com/Azure/go-autorest - version: e14a70c556c8e0db173358d1a903dca345a8e75e + version: 1ff28809256a84bb6966640ff3d0371af82ccba4 subpackages: - autorest - autorest/adal @@ -65,11 +28,18 @@ imports: - name: github.com/BurntSushi/toml version: b26d9c308763d68093482582cea63d69be07a0f0 - name: github.com/chai2010/gettext-go - version: bf70f2a70fb1b1f36d90d671a72795984eab0fcb + version: c6fed771bfd517099caf0f7a961671fa8ed08723 + subpackages: + - gettext + - gettext/mo + - gettext/plural + - gettext/po - name: github.com/cpuguy83/go-md2man version: 71acacd42f85e5e82f70a55327789582a5200a90 subpackages: - md2man +- name: github.com/cyphar/filepath-securejoin + version: 06bda8370f45268db985f7af15732444d94ed51c - name: github.com/davecgh/go-spew version: 782f4967f2dc4564575ca782fe2d04090b5faca8 subpackages: @@ -106,8 +76,10 @@ imports: - pkg/jsonmessage - pkg/longpath - pkg/mount + - pkg/parsers + - pkg/parsers/operatingsystem - pkg/stdcopy - - pkg/symlink + - pkg/sysinfo - pkg/system - pkg/term - pkg/term/windows @@ -124,26 +96,20 @@ imports: version: 449fdfce4d962303d702fec724ef0ad181c92528 subpackages: - spdy -- name: github.com/emicklei/go-restful - version: ff4f55a206334ef123e4f79bbf348980da81ca46 - subpackages: - - log - name: github.com/evanphx/json-patch - version: 944e07253867aacae43c04b2e6a239005443f33a + version: 94e38aa1586e8a6c8a75770bddf5ff84c48a106b - name: github.com/exponent-io/jsonpath version: d6023ce2651d8eafb5c75bb0c7167536102ec9f5 - name: github.com/fatih/camelcase version: f6a740d52f961c60348ebb109adde9f4635d7540 - name: github.com/ghodss/yaml version: 73d445a93680fa1a78ae23a5839bad48f32ba1ee -- name: github.com/go-ini/ini - version: 300e940a926eb277d3901b20bdfcc54928ad3642 - name: github.com/go-openapi/jsonpointer version: 46af16f9f7b149af66e5d1bd010e3574dc06de98 - name: github.com/go-openapi/jsonreference version: 13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272 - name: github.com/go-openapi/spec - version: 7abd5745472fff5eb3685386d5fb8bf38683154d + version: 1de3e0542de65ad8d75452a595886fdd0befb363 - name: github.com/go-openapi/swag version: f3f9494671f93fcff853e3c6e9e948b3eb71e590 - name: github.com/gobwas/glob @@ -179,6 +145,8 @@ imports: version: 7d79101e329e5a3adf994758c578dab82b90c017 - name: github.com/google/gofuzz version: 44d81051d367757e1c7c6a5a86423ece9afcf63c +- name: github.com/google/uuid + version: 064e2069ce9c359c118179501254f67d7d37ba24 - name: github.com/googleapis/gnostic version: 0c5108395e2debce0d731cf0287ddf7242066aba subpackages: @@ -186,7 +154,7 @@ imports: - compiler - extensions - name: github.com/gophercloud/gophercloud - version: 8183543f90d1aef267a5ecc209f2e0715b355acb + version: 781450b3c4fcb4f5182bcc5133adb4b2e4a09d1d subpackages: - openstack - openstack/identity/v2/tenants @@ -209,20 +177,14 @@ imports: version: a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4 subpackages: - simplelru -- name: github.com/howeyc/gopass - version: bf9dde6d0d2c004a008c27aaee91170c786f6db8 - name: github.com/huandu/xstrings version: 3959339b333561bf62a38b424fd41517c2c90f40 - name: github.com/imdario/mergo version: 6633656539c1639d9d78127b7d47c622b5d7b6dc - name: github.com/inconshreveable/mousetrap version: 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 -- name: github.com/jmespath/go-jmespath - version: 0b12d6b521d83fc7f755e7cfc1b1fbdd35a01a74 - name: github.com/json-iterator/go - version: 36b14963da70d11297d313183d7e6388c8510e1e -- name: github.com/juju/ratelimit - version: 5b9ff866471762aa2ab2dced63c9fb6f53921342 + version: f2b4162afba35581b6d4a50d3b8f34e33c144682 - name: github.com/mailru/easyjson version: 2f5df55504ebc322e4d52d34df6a1f5b503bf26d subpackages: @@ -234,7 +196,7 @@ imports: - name: github.com/Masterminds/semver version: 517734cc7d6470c0d07130e40fd40bdeb9bcd3fd - name: github.com/Masterminds/sprig - version: b217b9c388de2cacde4354c536e520c52c055563 + version: 6b2a58267f6a8b1dc8e2eb5519b984008fa85e8c - name: github.com/Masterminds/vcs version: 3084677c2c188840777bff30054f2b553729d329 - name: github.com/mattn/go-runewidth @@ -245,8 +207,10 @@ imports: - pbutil - name: github.com/mitchellh/go-wordwrap version: ad45545899c7b13c020ea92b2072220eefad42b8 -- name: github.com/naoina/go-stringutil - version: 6b638e95a32d0c1131db0e7fe83775cbea4a0d0b +- name: github.com/modern-go/concurrent + version: bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94 +- name: github.com/modern-go/reflect2 + version: 05fbef0ca5da472bbf96c9322b84a53edc03c9fd - name: github.com/opencontainers/go-digest version: a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb - name: github.com/opencontainers/image-spec @@ -254,10 +218,10 @@ imports: subpackages: - specs-go - specs-go/v1 -- name: github.com/pborman/uuid - version: ca53cad383cad2479bbba7f7a1a05797ec1386e4 - name: github.com/peterbourgon/diskv version: 5f041e8faa004a95c88a202771f4cc3e991971e6 +- name: github.com/pkg/errors + version: 645ef00459ed84a119197bfb8d8205042c6df63d - name: github.com/prometheus/client_golang version: c5b7fccd204277076155f10851dad72b76a49317 subpackages: @@ -283,24 +247,24 @@ imports: version: 5bd2802263f21d8788851d5305584c82a5c75d7e - name: github.com/russross/blackfriday version: 300106c228d52c8941d4b3de6054a6062a86dda3 -- name: github.com/satori/go.uuid - version: f58768cc1a7a7e77a3bd49e98cdd21419399b6a3 - name: github.com/shurcooL/sanitized_anchor_name version: 10ef21a441db47d8b13ebcc5fd2310f636973c77 - name: github.com/sirupsen/logrus version: 89742aefa4b206dcf400792f3bd35b542998eb3b - name: github.com/spf13/cobra - version: f62e98d28ab7ad31d707ba837a966378465c7b57 + version: c439c4fa093711d42e1b01acb1235b52004753c1 subpackages: - doc - name: github.com/spf13/pflag - version: 9ff6c6923cfffbcd502984b8e0c80539a94968b7 + version: 583c0c0531f06d5278b7d917446061adc344b5cd - name: github.com/technosophos/moniker - version: ab470f5e105a44d0c87ea21bacd6a335c4816d83 + version: a5dbd03a2245d554160e3ae6bfdcf969fe58b431 - name: golang.org/x/crypto - version: 81e90905daefcd6fd217b62423c0908922eadb30 + version: 49796115aa4b964c318aad4f3084fdb41e9aa067 subpackages: - cast5 + - ed25519 + - ed25519/internal/edwards25519 - openpgp - openpgp/armor - openpgp/clearsign @@ -353,6 +317,10 @@ imports: - unicode/bidi - unicode/norm - width +- name: golang.org/x/time + version: f51c12702a4d776e4c1fa9b0fabab841babae631 + subpackages: + - rate - name: google.golang.org/appengine version: 12d5545dc1cfa6047a286d5e853841b6471f4c19 subpackages: @@ -390,20 +358,18 @@ imports: - status - tap - transport -- name: gopkg.in/gcfg.v1 - version: 27e4946190b4a327b539185f2b5b1f7c84730728 - subpackages: - - scanner - - token - - types - name: gopkg.in/inf.v0 version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4 -- name: gopkg.in/warnings.v0 - version: 8a331561fe74dadba6edfc59f3be66c22c3b065d +- name: gopkg.in/square/go-jose.v2 + version: f8f38de21b4dcd69d0413faf231983f5fd6634b1 + subpackages: + - cipher + - json + - jwt - name: gopkg.in/yaml.v2 - version: 53feefa2559fb8dfa8d81baad31be332c97d6c77 + version: 670d4cfef0544295bc27a114dbac37980d83185a - name: k8s.io/api - version: 006a217681ae70cbacdd66a5e2fca1a61a8ff28e + version: 2d6f90ab1293a1fb871cf149423ebb72aa7423aa subpackages: - admission/v1beta1 - admissionregistration/v1alpha1 @@ -431,30 +397,31 @@ imports: - rbac/v1alpha1 - rbac/v1beta1 - scheduling/v1alpha1 + - scheduling/v1beta1 - settings/v1alpha1 - storage/v1 - storage/v1alpha1 - storage/v1beta1 - name: k8s.io/apiextensions-apiserver - version: a5bbfd114a9b122acd741c61d88c84812375d9e1 + version: 898b0eda132e1aeac43a459785144ee4bf9b0a2e subpackages: - pkg/features - name: k8s.io/apimachinery - version: 68f9c3a1feb3140df59c67ced62d3a5df8e6c9c2 + version: 103fd098999dc9c0c88536f5c9ad2e5da39373ae subpackages: - pkg/api/equality - pkg/api/errors - pkg/api/meta + - pkg/api/meta/testrestmapper - pkg/api/resource - pkg/api/validation - - pkg/apimachinery - - pkg/apimachinery/announced - - pkg/apimachinery/registered + - pkg/api/validation/path - pkg/apis/meta/internalversion - pkg/apis/meta/v1 - pkg/apis/meta/v1/unstructured + - pkg/apis/meta/v1/unstructured/unstructuredscheme - pkg/apis/meta/v1/validation - - pkg/apis/meta/v1alpha1 + - pkg/apis/meta/v1beta1 - pkg/conversion - pkg/conversion/queryparams - pkg/fields @@ -472,6 +439,7 @@ imports: - pkg/util/cache - pkg/util/clock - pkg/util/diff + - pkg/util/duration - pkg/util/errors - pkg/util/framer - pkg/util/httpstream @@ -485,7 +453,6 @@ imports: - pkg/util/runtime - pkg/util/sets - pkg/util/strategicpatch - - pkg/util/uuid - pkg/util/validation - pkg/util/validation/field - pkg/util/wait @@ -496,7 +463,7 @@ imports: - third_party/forked/golang/netutil - third_party/forked/golang/reflect - name: k8s.io/apiserver - version: 2a1092aaa7202e8f9b188281ff9424a014ce61c2 + version: 8b122ec9e3bbab91a262d17a39325e69349dc44d subpackages: - pkg/apis/audit - pkg/authentication/authenticator @@ -505,53 +472,13 @@ imports: - pkg/endpoints/request - pkg/features - pkg/util/feature - - pkg/util/flag - name: k8s.io/client-go - version: 78700dec6369ba22221b72770783300f143df150 + version: 59698c7d9724b0f95f9dc9e7f7dfdcc3dfeceb82 subpackages: - discovery - discovery/fake - dynamic - - informers - - informers/admissionregistration - - informers/admissionregistration/v1alpha1 - - informers/admissionregistration/v1beta1 - - informers/apps - - informers/apps/v1 - - informers/apps/v1beta1 - - informers/apps/v1beta2 - - informers/autoscaling - - informers/autoscaling/v1 - - informers/autoscaling/v2beta1 - - informers/batch - - informers/batch/v1 - - informers/batch/v1beta1 - - informers/batch/v2alpha1 - - informers/certificates - - informers/certificates/v1beta1 - - informers/core - - informers/core/v1 - - informers/events - - informers/events/v1beta1 - - informers/extensions - - informers/extensions/v1beta1 - - informers/internalinterfaces - - informers/networking - - informers/networking/v1 - - informers/policy - - informers/policy/v1beta1 - - informers/rbac - - informers/rbac/v1 - - informers/rbac/v1alpha1 - - informers/rbac/v1beta1 - - informers/scheduling - - informers/scheduling/v1alpha1 - - informers/settings - - informers/settings/v1alpha1 - - informers/storage - - informers/storage/v1 - - informers/storage/v1alpha1 - - informers/storage/v1beta1 + - dynamic/fake - kubernetes - kubernetes/fake - kubernetes/scheme @@ -603,6 +530,8 @@ imports: - kubernetes/typed/rbac/v1beta1/fake - kubernetes/typed/scheduling/v1alpha1 - kubernetes/typed/scheduling/v1alpha1/fake + - kubernetes/typed/scheduling/v1beta1 + - kubernetes/typed/scheduling/v1beta1/fake - kubernetes/typed/settings/v1alpha1 - kubernetes/typed/settings/v1alpha1/fake - kubernetes/typed/storage/v1 @@ -611,39 +540,30 @@ imports: - kubernetes/typed/storage/v1alpha1/fake - kubernetes/typed/storage/v1beta1 - kubernetes/typed/storage/v1beta1/fake - - listers/admissionregistration/v1alpha1 - - listers/admissionregistration/v1beta1 - listers/apps/v1 - - listers/apps/v1beta1 - - listers/apps/v1beta2 - - listers/autoscaling/v1 - - listers/autoscaling/v2beta1 - - listers/batch/v1 - - listers/batch/v1beta1 - - listers/batch/v2alpha1 - - listers/certificates/v1beta1 - listers/core/v1 - - listers/events/v1beta1 - - listers/extensions/v1beta1 - - listers/networking/v1 - - listers/policy/v1beta1 - - listers/rbac/v1 - - listers/rbac/v1alpha1 - - listers/rbac/v1beta1 - - listers/scheduling/v1alpha1 - - listers/settings/v1alpha1 - - listers/storage/v1 - - listers/storage/v1alpha1 - - listers/storage/v1beta1 + - pkg/apis/clientauthentication + - pkg/apis/clientauthentication/v1alpha1 + - pkg/apis/clientauthentication/v1beta1 - pkg/version - plugin/pkg/client/auth - plugin/pkg/client/auth/azure + - plugin/pkg/client/auth/exec - plugin/pkg/client/auth/gcp - plugin/pkg/client/auth/oidc - plugin/pkg/client/auth/openstack - rest - rest/fake - rest/watch + - restmapper + - scale + - scale/scheme + - scale/scheme/appsint + - scale/scheme/appsv1beta1 + - scale/scheme/appsv1beta2 + - scale/scheme/autoscalingv1 + - scale/scheme/extensionsint + - scale/scheme/extensionsv1beta1 - testing - third_party/forked/golang/template - tools/auth @@ -662,21 +582,21 @@ imports: - transport/spdy - util/buffer - util/cert + - util/connrotation - util/exec - util/flowcontrol - util/homedir - util/integer - util/jsonpath - util/retry - - util/workqueue - name: k8s.io/kube-openapi - version: 39a7bf85c140f972372c2a0d1ee40adbf0c8bfe1 + version: 91cfa479c814065e420cee7ed227db0f63a5854e subpackages: - - pkg/common - pkg/util/proto + - pkg/util/proto/testing - pkg/util/proto/validation - name: k8s.io/kubernetes - version: 5fa2db2bd46ac79e5e00a4e6ed24191080aa463b + version: 8b3d76091fd500b7c59c83e113c9048ee612b205 subpackages: - pkg/api/events - pkg/api/legacyscheme @@ -686,7 +606,6 @@ imports: - pkg/api/service - pkg/api/testapi - pkg/api/v1/pod - - pkg/api/v1/service - pkg/apis/admission - pkg/apis/admission/install - pkg/apis/admission/v1beta1 @@ -729,7 +648,6 @@ imports: - pkg/apis/core/pods - pkg/apis/core/v1 - pkg/apis/core/v1/helper - - pkg/apis/core/v1/helper/qos - pkg/apis/core/validation - pkg/apis/events - pkg/apis/events/install @@ -754,6 +672,7 @@ imports: - pkg/apis/scheduling - pkg/apis/scheduling/install - pkg/apis/scheduling/v1alpha1 + - pkg/apis/scheduling/v1beta1 - pkg/apis/settings - pkg/apis/settings/install - pkg/apis/settings/v1alpha1 @@ -799,35 +718,28 @@ imports: - pkg/client/clientset_generated/internalclientset/typed/settings/internalversion/fake - pkg/client/clientset_generated/internalclientset/typed/storage/internalversion - pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/fake - - pkg/client/unversioned - - pkg/cloudprovider - - pkg/cloudprovider/providers/aws - pkg/controller - - pkg/controller/daemon - - pkg/controller/daemon/util - pkg/controller/deployment/util - - pkg/controller/history - - pkg/controller/statefulset - - pkg/controller/volume/events - - pkg/controller/volume/persistentvolume - pkg/credentialprovider - - pkg/credentialprovider/aws - pkg/features - pkg/fieldpath + - pkg/generated - pkg/kubectl - pkg/kubectl/apps - - pkg/kubectl/categories + - pkg/kubectl/cmd/get - pkg/kubectl/cmd/templates - pkg/kubectl/cmd/testing - pkg/kubectl/cmd/util - pkg/kubectl/cmd/util/openapi - pkg/kubectl/cmd/util/openapi/testing - pkg/kubectl/cmd/util/openapi/validation - - pkg/kubectl/plugins - - pkg/kubectl/resource + - pkg/kubectl/genericclioptions + - pkg/kubectl/genericclioptions/printers + - pkg/kubectl/genericclioptions/resource - pkg/kubectl/scheme - pkg/kubectl/util - pkg/kubectl/util/hash + - pkg/kubectl/util/i18n - pkg/kubectl/util/slice - pkg/kubectl/util/term - pkg/kubectl/validation @@ -837,45 +749,32 @@ imports: - pkg/printers - pkg/printers/internalversion - pkg/registry/rbac/validation + - pkg/scheduler/algorithm + - pkg/scheduler/algorithm/priorities/util + - pkg/scheduler/api + - pkg/scheduler/cache + - pkg/scheduler/util - pkg/security/apparmor - pkg/serviceaccount - pkg/util/file - - pkg/util/goroutinemap - - pkg/util/goroutinemap/exponentialbackoff - pkg/util/hash - pkg/util/interrupt - - pkg/util/io - pkg/util/labels - - pkg/util/metrics - - pkg/util/mount - pkg/util/net/sets - pkg/util/node - - pkg/util/nsenter - pkg/util/parsers - pkg/util/pointer - pkg/util/slice - pkg/util/taints - pkg/version - - pkg/volume - - pkg/volume/util - - pkg/watch/json - - plugin/pkg/scheduler/algorithm - - plugin/pkg/scheduler/algorithm/predicates - - plugin/pkg/scheduler/algorithm/priorities/util - - plugin/pkg/scheduler/api - - plugin/pkg/scheduler/schedulercache - - plugin/pkg/scheduler/util - - plugin/pkg/scheduler/volumebinder - name: k8s.io/utils - version: aedf551cdb8b0119df3a19c65fde413a13b34997 + version: 258e2a2fa64568210fbd6267cf1d8fd87c3cb86e subpackages: - clock - exec - exec/testing - name: vbom.ml/util version: db5cfe13f5cc80a4990d98e2e1b0707a4d1a5394 - repo: https://github.com/fvbommel/util.git - vcs: git subpackages: - sortorder testImports: diff --git a/glide.yaml b/glide.yaml index 7d0fce978..68a5d91ad 100644 --- a/glide.yaml +++ b/glide.yaml @@ -4,20 +4,21 @@ import: subpackages: - context - package: github.com/spf13/cobra - version: f62e98d28ab7ad31d707ba837a966378465c7b57 + version: c439c4fa093711d42e1b01acb1235b52004753c1 - package: github.com/spf13/pflag - version: 9ff6c6923cfffbcd502984b8e0c80539a94968b7 + version: 583c0c0531f06d5278b7d917446061adc344b5cd - package: github.com/Masterminds/vcs version: ~1.11.0 # Pin version of mergo that is compatible with both sprig and Kubernetes - package: github.com/imdario/mergo version: 6633656539c1639d9d78127b7d47c622b5d7b6dc - package: github.com/Masterminds/sprig - version: ^2.14.1 + version: ^2.15.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 subpackages: @@ -32,6 +33,7 @@ import: - package: golang.org/x/crypto subpackages: - openpgp + - ssh/terminal # pin version of golang.org/x/sys that is compatible with golang.org/x/crypto - package: golang.org/x/sys version: 43eea11 @@ -43,28 +45,22 @@ import: - package: github.com/evanphx/json-patch - package: github.com/BurntSushi/toml version: ~0.3.0 -- package: github.com/naoina/go-stringutil - version: ~0.1.0 -- package: github.com/chai2010/gettext-go - package: github.com/prometheus/client_golang version: 0.8.0 -- package: vbom.ml/util - repo: https://github.com/fvbommel/util.git - vcs: git +- package: github.com/grpc-ecosystem/go-grpc-prometheus - package: k8s.io/kubernetes - version: 1.9.2 + version: release-1.11 - package: k8s.io/client-go - version: ~6.0.0 + version: kubernetes-1.11.1 - package: k8s.io/api - version: kubernetes-1.9.2 + version: kubernetes-1.11.1 - package: k8s.io/apimachinery - version: kubernetes-1.9.2 + version: kubernetes-1.11.1 - package: k8s.io/apiserver - version: kubernetes-1.9.2 - -- package: cloud.google.com/go/compute - repo: https://github.com/GoogleCloudPlatform/google-cloud-go.git + version: kubernetes-1.11.1 +- package: github.com/cyphar/filepath-securejoin + version: ^0.2.1 testImports: - package: github.com/stretchr/testify diff --git a/pkg/chartutil/capabilities.go b/pkg/chartutil/capabilities.go index c87c0368e..d7e660b8a 100644 --- a/pkg/chartutil/capabilities.go +++ b/pkg/chartutil/capabilities.go @@ -1,5 +1,5 @@ /* -Copyright 2017 The Kubernetes Authors All rights reserved. +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 @@ -42,7 +42,7 @@ var ( type Capabilities struct { // List of all supported API versions APIVersions VersionSet - // KubeVerison is the Kubernetes version + // KubeVersion is the Kubernetes version KubeVersion *version.Info // TillerVersion is the Tiller version // diff --git a/pkg/chartutil/capabilities_test.go b/pkg/chartutil/capabilities_test.go index ac20f0038..1f7020a39 100644 --- a/pkg/chartutil/capabilities_test.go +++ b/pkg/chartutil/capabilities_test.go @@ -1,5 +1,5 @@ /* -Copyright 2017 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/chartutil/chartfile.go b/pkg/chartutil/chartfile.go index 9897d66ff..f997d15fe 100644 --- a/pkg/chartutil/chartfile.go +++ b/pkg/chartutil/chartfile.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -31,7 +31,7 @@ import ( // ApiVersionV1 is the API version number for version 1. // // This is ApiVersionV1 instead of APIVersionV1 to match the protobuf-generated name. -const ApiVersionV1 = "v1" +const ApiVersionV1 = "v1" // nolint // UnmarshalChartfile takes raw Chart.yaml data and unmarshals it. func UnmarshalChartfile(data []byte) (*chart.Metadata, error) { diff --git a/pkg/chartutil/chartfile_test.go b/pkg/chartutil/chartfile_test.go index 5b36dc955..e55fbbd48 100755 --- a/pkg/chartutil/chartfile_test.go +++ b/pkg/chartutil/chartfile_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/chartutil/create.go b/pkg/chartutil/create.go index 319a75e2f..cff3b89eb 100644 --- a/pkg/chartutil/create.go +++ b/pkg/chartutil/create.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -59,6 +59,9 @@ image: tag: stable pullPolicy: IfNotPresent +nameOverride: "" +fullnameOverride: "" + service: type: ClusterIP port: 80 @@ -120,17 +123,16 @@ const defaultIgnore = `# Patterns to ignore when building packages. const defaultIngress = `{{- if .Values.ingress.enabled -}} {{- $fullName := include ".fullname" . -}} -{{- $servicePort := .Values.service.port -}} {{- $ingressPath := .Values.ingress.path -}} apiVersion: extensions/v1beta1 kind: Ingress metadata: name: {{ $fullName }} labels: - app: {{ template ".name" . }} - chart: {{ template ".chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} + app.kubernetes.io/name: {{ include ".name" . }} + helm.sh/chart: {{ include ".chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} {{- with .Values.ingress.annotations }} annotations: {{ toYaml . | indent 4 }} @@ -141,14 +143,14 @@ spec: {{- range .Values.ingress.tls }} - hosts: {{- range .hosts }} - - {{ . }} + - {{ . | quote }} {{- end }} secretName: {{ .secretName }} {{- end }} {{- end }} rules: {{- range .Values.ingress.hosts }} - - host: {{ . }} + - host: {{ . | quote }} http: paths: - path: {{ $ingressPath }} @@ -162,23 +164,23 @@ spec: const defaultDeployment = `apiVersion: apps/v1beta2 kind: Deployment metadata: - name: {{ template ".fullname" . }} + name: {{ include ".fullname" . }} labels: - app: {{ template ".name" . }} - chart: {{ template ".chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} + app.kubernetes.io/name: {{ include ".name" . }} + helm.sh/chart: {{ include ".chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} spec: replicas: {{ .Values.replicaCount }} selector: matchLabels: - app: {{ template ".name" . }} - release: {{ .Release.Name }} + app.kubernetes.io/name: {{ include ".name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} template: metadata: labels: - app: {{ template ".name" . }} - release: {{ .Release.Name }} + app.kubernetes.io/name: {{ include ".name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} spec: containers: - name: {{ .Chart.Name }} @@ -215,12 +217,12 @@ spec: const defaultService = `apiVersion: v1 kind: Service metadata: - name: {{ template ".fullname" . }} + name: {{ include ".fullname" . }} labels: - app: {{ template ".name" . }} - chart: {{ template ".chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} + app.kubernetes.io/name: {{ include ".name" . }} + helm.sh/chart: {{ include ".chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} spec: type: {{ .Values.service.type }} ports: @@ -229,8 +231,8 @@ spec: protocol: TCP name: http selector: - app: {{ template ".name" . }} - release: {{ .Release.Name }} + app.kubernetes.io/name: {{ include ".name" . }} + app.kubernetes.io/instancelease: {{ .Release.Name }} ` const defaultNotes = `1. Get the application URL by running these commands: @@ -239,16 +241,16 @@ const defaultNotes = `1. Get the application URL by running these commands: http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }} {{- end }} {{- else if contains "NodePort" .Values.service.type }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template ".fullname" . }}) + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include ".fullname" . }}) export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") echo http://$NODE_IP:$NODE_PORT {{- else if contains "LoadBalancer" .Values.service.type }} NOTE: It may take a few minutes for the LoadBalancer IP to be available. - You can watch the status of by running 'kubectl get svc -w {{ template ".fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template ".fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + You can watch the status of by running 'kubectl get svc -w {{ include ".fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include ".fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') echo http://$SERVICE_IP:{{ .Values.service.port }} {{- else if contains "ClusterIP" .Values.service.type }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template ".name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include ".name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") echo "Visit http://127.0.0.1:8080 to use your application" kubectl port-forward $POD_NAME 8080:80 {{- end }} @@ -305,8 +307,9 @@ func CreateFrom(chartfile *chart.Metadata, dest string, src string) error { } schart.Templates = updatedTemplates - schart.Values = &chart.Config{Raw: string(Transform(schart.Values.Raw, "", schart.Metadata.Name))} - + if schart.Values != nil { + schart.Values = &chart.Config{Raw: string(Transform(schart.Values.Raw, "", schart.Metadata.Name))} + } return SaveDir(schart, dest) } diff --git a/pkg/chartutil/create_test.go b/pkg/chartutil/create_test.go index e9af83ad2..96c467e7e 100644 --- a/pkg/chartutil/create_test.go +++ b/pkg/chartutil/create_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/chartutil/doc.go b/pkg/chartutil/doc.go index 1190d968d..cb3f5d1f1 100644 --- a/pkg/chartutil/doc.go +++ b/pkg/chartutil/doc.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/chartutil/expand.go b/pkg/chartutil/expand.go index 126e14e80..1d49b159f 100644 --- a/pkg/chartutil/expand.go +++ b/pkg/chartutil/expand.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/chartutil/files.go b/pkg/chartutil/files.go index a711a3366..c5496a8b0 100644 --- a/pkg/chartutil/files.go +++ b/pkg/chartutil/files.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 @@ -211,7 +211,8 @@ func ToToml(v interface{}) string { // always return a string, even on marshal error (empty string). // // This is designed to be called from a template. -func ToJson(v interface{}) string { +// TODO: change the function signature in Helm 3 +func ToJson(v interface{}) string { // nolint data, err := json.Marshal(v) if err != nil { // Swallow errors inside of a template. @@ -226,7 +227,8 @@ func ToJson(v interface{}) string { // JSON documents. Additionally, because its intended use is within templates // it tolerates errors. It will insert the returned error message string into // m["Error"] in the returned map. -func FromJson(str string) map[string]interface{} { +// TODO: change the function signature in Helm 3 +func FromJson(str string) map[string]interface{} { // nolint m := map[string]interface{}{} if err := json.Unmarshal([]byte(str), &m); err != nil { diff --git a/pkg/chartutil/files_test.go b/pkg/chartutil/files_test.go index 731c82e6f..1488b7986 100644 --- a/pkg/chartutil/files_test.go +++ b/pkg/chartutil/files_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/chartutil/load.go b/pkg/chartutil/load.go index c5246b8d7..b3daefac7 100644 --- a/pkg/chartutil/load.go +++ b/pkg/chartutil/load.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/chartutil/load_test.go b/pkg/chartutil/load_test.go index 454500489..5cb15fbdc 100644 --- a/pkg/chartutil/load_test.go +++ b/pkg/chartutil/load_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/chartutil/requirements.go b/pkg/chartutil/requirements.go index ce761a6fc..566123122 100644 --- a/pkg/chartutil/requirements.go +++ b/pkg/chartutil/requirements.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 @@ -45,7 +45,7 @@ var ( type Dependency struct { // Name is the name of the dependency. // - // This must mach the name in the dependency's Chart.yaml. + // This must match the name in the dependency's Chart.yaml. Name string `json:"name"` // Version is the version (range) of this chart. // @@ -394,6 +394,21 @@ func processImportValues(c *chart.Chart) error { b := make(map[string]interface{}, 0) // import values from each dependency if specified in import-values for _, r := range reqs.Dependencies { + // only process raw requirement that is found in chart's dependencies (enabled) + found := false + name := r.Name + for _, v := range c.Dependencies { + if v.Metadata.Name == r.Name { + found = true + } + if v.Metadata.Name == r.Alias { + found = true + name = r.Alias + } + } + if !found { + continue + } if len(r.ImportValues) > 0 { var outiv []interface{} for _, riv := range r.ImportValues { @@ -404,7 +419,7 @@ func processImportValues(c *chart.Chart) error { "parent": iv["parent"].(string), } outiv = append(outiv, nm) - s := r.Name + "." + nm["child"] + s := name + "." + nm["child"] // get child table vv, err := cvals.Table(s) if err != nil { @@ -420,7 +435,7 @@ func processImportValues(c *chart.Chart) error { "parent": ".", } outiv = append(outiv, nm) - s := r.Name + "." + nm["child"] + s := name + "." + nm["child"] vm, err := cvals.Table(s) if err != nil { log.Printf("Warning: ImportValues missing table: %v", err) diff --git a/pkg/chartutil/requirements_test.go b/pkg/chartutil/requirements_test.go index 24388f86c..0afde17e1 100644 --- a/pkg/chartutil/requirements_test.go +++ b/pkg/chartutil/requirements_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/chartutil/save.go b/pkg/chartutil/save.go index bff32dde5..9b85d0714 100644 --- a/pkg/chartutil/save.go +++ b/pkg/chartutil/save.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -24,6 +24,7 @@ import ( "io/ioutil" "os" "path/filepath" + "time" "github.com/ghodss/yaml" @@ -205,9 +206,10 @@ func writeTarContents(out *tar.Writer, c *chart.Chart, prefix string) error { func writeToTar(out *tar.Writer, name string, body []byte) error { // TODO: Do we need to create dummy parent directory names if none exist? h := &tar.Header{ - Name: name, - Mode: 0755, - Size: int64(len(body)), + Name: filepath.ToSlash(name), + Mode: 0755, + Size: int64(len(body)), + ModTime: time.Now(), } if err := out.WriteHeader(h); err != nil { return err diff --git a/pkg/chartutil/save_test.go b/pkg/chartutil/save_test.go index 5e1564299..0ec305e78 100644 --- a/pkg/chartutil/save_test.go +++ b/pkg/chartutil/save_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -17,10 +17,14 @@ limitations under the License. package chartutil import ( + "archive/tar" + "compress/gzip" + "io" "io/ioutil" "os" "strings" "testing" + "time" "github.com/golang/protobuf/ptypes/any" "k8s.io/helm/pkg/proto/hapi/chart" @@ -73,6 +77,82 @@ func TestSave(t *testing.T) { } } +func TestSavePreservesTimestamps(t *testing.T) { + // Test executes so quickly that if we don't subtract a second, the + // check will fail because `initialCreateTime` will be identical to the + // written timestamp for the files. + initialCreateTime := time.Now().Add(-1 * time.Second) + + tmp, err := ioutil.TempDir("", "helm-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmp) + + c := &chart.Chart{ + Metadata: &chart.Metadata{ + Name: "ahab", + Version: "1.2.3.4", + }, + Values: &chart.Config{ + Raw: "ship: Pequod", + }, + Files: []*any.Any{ + {TypeUrl: "scheherazade/shahryar.txt", Value: []byte("1,001 Nights")}, + }, + } + + where, err := Save(c, tmp) + if err != nil { + t.Fatalf("Failed to save: %s", err) + } + + allHeaders, err := retrieveAllHeadersFromTar(where) + if err != nil { + t.Fatalf("Failed to parse tar: %v", err) + } + + for _, header := range allHeaders { + if header.ModTime.Before(initialCreateTime) { + t.Fatalf("File timestamp not preserved: %v", header.ModTime) + } + } +} + +// We could refactor `load.go` to use this `retrieveAllHeadersFromTar` function +// as well, so we are not duplicating components of the code which iterate +// through the tar. +func retrieveAllHeadersFromTar(path string) ([]*tar.Header, error) { + raw, err := os.Open(path) + if err != nil { + return nil, err + } + defer raw.Close() + + unzipped, err := gzip.NewReader(raw) + if err != nil { + return nil, err + } + defer unzipped.Close() + + tr := tar.NewReader(unzipped) + headers := []*tar.Header{} + for { + hd, err := tr.Next() + if err == io.EOF { + break + } + + if err != nil { + return nil, err + } + + headers = append(headers, hd) + } + + return headers, nil +} + func TestSaveDir(t *testing.T) { tmp, err := ioutil.TempDir("", "helm-") if err != nil { diff --git a/pkg/chartutil/testdata/dependent-chart-alias/charts/alpine/templates/alpine-pod.yaml b/pkg/chartutil/testdata/dependent-chart-alias/charts/alpine/templates/alpine-pod.yaml index 08cf3c2c1..c34fa8c47 100644 --- a/pkg/chartutil/testdata/dependent-chart-alias/charts/alpine/templates/alpine-pod.yaml +++ b/pkg/chartutil/testdata/dependent-chart-alias/charts/alpine/templates/alpine-pod.yaml @@ -3,7 +3,7 @@ kind: Pod metadata: name: {{.Release.Name}}-{{.Chart.Name}} labels: - heritage: {{.Release.Service}} + app.kubernetes.io/managed-by: {{.Release.Service}} chartName: {{.Chart.Name}} chartVersion: {{.Chart.Version | quote}} annotations: diff --git a/pkg/chartutil/testdata/dependent-chart-helmignore/charts/alpine/templates/alpine-pod.yaml b/pkg/chartutil/testdata/dependent-chart-helmignore/charts/alpine/templates/alpine-pod.yaml index 08cf3c2c1..c34fa8c47 100644 --- a/pkg/chartutil/testdata/dependent-chart-helmignore/charts/alpine/templates/alpine-pod.yaml +++ b/pkg/chartutil/testdata/dependent-chart-helmignore/charts/alpine/templates/alpine-pod.yaml @@ -3,7 +3,7 @@ kind: Pod metadata: name: {{.Release.Name}}-{{.Chart.Name}} labels: - heritage: {{.Release.Service}} + app.kubernetes.io/managed-by: {{.Release.Service}} chartName: {{.Chart.Name}} chartVersion: {{.Chart.Version | quote}} annotations: diff --git a/pkg/chartutil/testdata/dependent-chart-no-requirements-yaml/charts/alpine/templates/alpine-pod.yaml b/pkg/chartutil/testdata/dependent-chart-no-requirements-yaml/charts/alpine/templates/alpine-pod.yaml index 08cf3c2c1..c34fa8c47 100644 --- a/pkg/chartutil/testdata/dependent-chart-no-requirements-yaml/charts/alpine/templates/alpine-pod.yaml +++ b/pkg/chartutil/testdata/dependent-chart-no-requirements-yaml/charts/alpine/templates/alpine-pod.yaml @@ -3,7 +3,7 @@ kind: Pod metadata: name: {{.Release.Name}}-{{.Chart.Name}} labels: - heritage: {{.Release.Service}} + app.kubernetes.io/managed-by: {{.Release.Service}} chartName: {{.Chart.Name}} chartVersion: {{.Chart.Version | quote}} annotations: diff --git a/pkg/chartutil/testdata/dependent-chart-with-all-in-requirements-yaml/charts/alpine/templates/alpine-pod.yaml b/pkg/chartutil/testdata/dependent-chart-with-all-in-requirements-yaml/charts/alpine/templates/alpine-pod.yaml index 08cf3c2c1..c34fa8c47 100644 --- a/pkg/chartutil/testdata/dependent-chart-with-all-in-requirements-yaml/charts/alpine/templates/alpine-pod.yaml +++ b/pkg/chartutil/testdata/dependent-chart-with-all-in-requirements-yaml/charts/alpine/templates/alpine-pod.yaml @@ -3,7 +3,7 @@ kind: Pod metadata: name: {{.Release.Name}}-{{.Chart.Name}} labels: - heritage: {{.Release.Service}} + app.kubernetes.io/managed-by: {{.Release.Service}} chartName: {{.Chart.Name}} chartVersion: {{.Chart.Version | quote}} annotations: diff --git a/pkg/chartutil/testdata/dependent-chart-with-mixed-requirements-yaml/charts/alpine/templates/alpine-pod.yaml b/pkg/chartutil/testdata/dependent-chart-with-mixed-requirements-yaml/charts/alpine/templates/alpine-pod.yaml index 08cf3c2c1..c34fa8c47 100644 --- a/pkg/chartutil/testdata/dependent-chart-with-mixed-requirements-yaml/charts/alpine/templates/alpine-pod.yaml +++ b/pkg/chartutil/testdata/dependent-chart-with-mixed-requirements-yaml/charts/alpine/templates/alpine-pod.yaml @@ -3,7 +3,7 @@ kind: Pod metadata: name: {{.Release.Name}}-{{.Chart.Name}} labels: - heritage: {{.Release.Service}} + app.kubernetes.io/managed-by: {{.Release.Service}} chartName: {{.Chart.Name}} chartVersion: {{.Chart.Version | quote}} annotations: diff --git a/pkg/chartutil/testdata/frobnitz-1.2.3.tgz b/pkg/chartutil/testdata/frobnitz-1.2.3.tgz index fb21cd08f..cd12d2c1e 100644 Binary files a/pkg/chartutil/testdata/frobnitz-1.2.3.tgz and b/pkg/chartutil/testdata/frobnitz-1.2.3.tgz differ diff --git a/pkg/chartutil/testdata/frobnitz/charts/alpine/templates/alpine-pod.yaml b/pkg/chartutil/testdata/frobnitz/charts/alpine/templates/alpine-pod.yaml index 08cf3c2c1..c34fa8c47 100644 --- a/pkg/chartutil/testdata/frobnitz/charts/alpine/templates/alpine-pod.yaml +++ b/pkg/chartutil/testdata/frobnitz/charts/alpine/templates/alpine-pod.yaml @@ -3,7 +3,7 @@ kind: Pod metadata: name: {{.Release.Name}}-{{.Chart.Name}} labels: - heritage: {{.Release.Service}} + app.kubernetes.io/managed-by: {{.Release.Service}} chartName: {{.Chart.Name}} chartVersion: {{.Chart.Version | quote}} annotations: diff --git a/pkg/chartutil/testdata/frobnitz/charts/mariner-4.3.2.tgz b/pkg/chartutil/testdata/frobnitz/charts/mariner-4.3.2.tgz index 3af333e76..78fabe241 100644 Binary files a/pkg/chartutil/testdata/frobnitz/charts/mariner-4.3.2.tgz and b/pkg/chartutil/testdata/frobnitz/charts/mariner-4.3.2.tgz differ diff --git a/pkg/chartutil/testdata/frobnitz_backslash/charts/alpine/templates/alpine-pod.yaml b/pkg/chartutil/testdata/frobnitz_backslash/charts/alpine/templates/alpine-pod.yaml index 08cf3c2c1..c34fa8c47 100755 --- a/pkg/chartutil/testdata/frobnitz_backslash/charts/alpine/templates/alpine-pod.yaml +++ b/pkg/chartutil/testdata/frobnitz_backslash/charts/alpine/templates/alpine-pod.yaml @@ -3,7 +3,7 @@ kind: Pod metadata: name: {{.Release.Name}}-{{.Chart.Name}} labels: - heritage: {{.Release.Service}} + app.kubernetes.io/managed-by: {{.Release.Service}} chartName: {{.Chart.Name}} chartVersion: {{.Chart.Version | quote}} annotations: diff --git a/pkg/chartutil/testdata/mariner/charts/albatross-0.1.0.tgz b/pkg/chartutil/testdata/mariner/charts/albatross-0.1.0.tgz index 0b66d27fe..cd2ac4e46 100644 Binary files a/pkg/chartutil/testdata/mariner/charts/albatross-0.1.0.tgz and b/pkg/chartutil/testdata/mariner/charts/albatross-0.1.0.tgz differ diff --git a/pkg/chartutil/testdata/mariner/templates/placeholder.tpl b/pkg/chartutil/testdata/mariner/templates/placeholder.tpl index 29c11843a..9804717d1 100644 --- a/pkg/chartutil/testdata/mariner/templates/placeholder.tpl +++ b/pkg/chartutil/testdata/mariner/templates/placeholder.tpl @@ -1 +1,3 @@ # This is a placeholder. + +Goodbye {{.Values.name | default "world"}} diff --git a/pkg/chartutil/testdata/subpop/charts/subchart1/templates/service.yaml b/pkg/chartutil/testdata/subpop/charts/subchart1/templates/service.yaml index 3835a3d0b..e06d19b90 100644 --- a/pkg/chartutil/testdata/subpop/charts/subchart1/templates/service.yaml +++ b/pkg/chartutil/testdata/subpop/charts/subchart1/templates/service.yaml @@ -6,6 +6,8 @@ metadata: chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" namespace: "{{ .Release.Namespace }}" release-name: "{{ .Release.Name }}" + release-is-upgrade: "{{ .Release.IsUpgrade }}" + release-is-install: "{{ .Release.IsInstall }}" kube-version/major: "{{ .Capabilities.KubeVersion.Major }}" kube-version/minor: "{{ .Capabilities.KubeVersion.Minor }}" kube-version/gitversion: "v{{ .Capabilities.KubeVersion.Major }}.{{ .Capabilities.KubeVersion.Minor }}.0" diff --git a/pkg/chartutil/transform.go b/pkg/chartutil/transform.go index 7cbb754fb..fbee8e690 100644 --- a/pkg/chartutil/transform.go +++ b/pkg/chartutil/transform.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/chartutil/values.go b/pkg/chartutil/values.go index 66a2658d5..1ea7edd8c 100644 --- a/pkg/chartutil/values.go +++ b/pkg/chartutil/values.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/chartutil/values_test.go b/pkg/chartutil/values_test.go index d9b03c21a..f54b25827 100644 --- a/pkg/chartutil/values_test.go +++ b/pkg/chartutil/values_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/downloader/chart_downloader.go b/pkg/downloader/chart_downloader.go index 9fe89820e..92c8f9165 100644 --- a/pkg/downloader/chart_downloader.go +++ b/pkg/downloader/chart_downloader.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 @@ -85,7 +85,7 @@ type ChartDownloader struct { // Returns a string path to the location where the file was downloaded and a verification // (if provenance was verified), or an error if something bad happened. func (c *ChartDownloader) DownloadTo(ref, version, dest string) (string, *provenance.Verification, error) { - u, r, g, err := c.ResolveChartVersionAndGetRepo(ref, version) + u, g, err := c.ResolveChartVersion(ref, version) if err != nil { return "", nil, err } @@ -104,7 +104,7 @@ func (c *ChartDownloader) DownloadTo(ref, version, dest string) (string, *proven // If provenance is requested, verify it. ver := &provenance.Verification{} if c.Verify > VerifyNever { - body, err := r.Client.Get(u.String() + ".prov") + body, err := g.Get(u.String() + ".prov") if err != nil { if c.Verify == VerifyAlways { return destfile, ver, fmt.Errorf("Failed to fetch provenance %q", u.String()+".prov") @@ -144,31 +144,16 @@ func (c *ChartDownloader) DownloadTo(ref, version, dest string) (string, *proven // * If version is empty, this will return the URL for the latest version // * If no version can be found, an error is returned func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, getter.Getter, error) { - u, r, _, err := c.ResolveChartVersionAndGetRepo(ref, version) - if r != nil { - return u, r.Client, err - } - return u, nil, err -} - -// Same as the ResolveChartVersion method, but returns the chart repositoryy. -func (c *ChartDownloader) ResolveChartVersionAndGetRepo(ref, version string) (*url.URL, *repo.ChartRepository, *getter.HttpGetter, error) { u, err := url.Parse(ref) if err != nil { - return nil, nil, nil, fmt.Errorf("invalid chart URL format: %s", ref) + return nil, nil, fmt.Errorf("invalid chart URL format: %s", ref) } rf, err := repo.LoadRepositoriesFile(c.HelmHome.RepositoryFile()) if err != nil { - return u, nil, nil, err + return u, nil, err } - g, err := getter.NewHTTPGetter(ref, "", "", "") - if err != nil { - return u, nil, nil, err - } - g.SetCredentials(c.getRepoCredentials(nil)) - if u.IsAbs() && len(u.Host) > 0 && len(u.Path) > 0 { // In this case, we have to find the parent repo that contains this chart // URL. And this is an unfortunate problem, as it requires actually going @@ -181,78 +166,85 @@ func (c *ChartDownloader) ResolveChartVersionAndGetRepo(ref, version string) (*u // If there is no special config, return the default HTTP client and // swallow the error. if err == ErrNoOwnerRepo { - r := &repo.ChartRepository{} - r.Client = g - g.SetCredentials(c.getRepoCredentials(r)) - return u, r, g, err + getterConstructor, err := c.Getters.ByScheme(u.Scheme) + if err != nil { + return u, nil, err + } + getter, err := getterConstructor(ref, "", "", "") + return u, getter, err } - return u, nil, nil, err + return u, nil, err } r, err := repo.NewChartRepository(rc, c.Getters) + c.setCredentials(r) // If we get here, we don't need to go through the next phase of looking // up the URL. We have it already. So we just return. - return u, r, g, err + return u, r.Client, err } // See if it's of the form: repo/path_to_chart p := strings.SplitN(u.Path, "/", 2) if len(p) < 2 { - return u, nil, nil, fmt.Errorf("Non-absolute URLs should be in form of repo_name/path_to_chart, got: %s", u) + return u, nil, fmt.Errorf("Non-absolute URLs should be in form of repo_name/path_to_chart, got: %s", u) } repoName := p[0] chartName := p[1] rc, err := pickChartRepositoryConfigByName(repoName, rf.Repositories) + if err != nil { - return u, nil, nil, err + return u, nil, err } r, err := repo.NewChartRepository(rc, c.Getters) if err != nil { - return u, nil, nil, err + return u, nil, err } + c.setCredentials(r) // Next, we need to load the index, and actually look up the chart. i, err := repo.LoadIndexFile(c.HelmHome.CacheIndex(r.Config.Name)) if err != nil { - return u, r, g, fmt.Errorf("no cached repo found. (try 'helm repo update'). %s", err) + return u, r.Client, fmt.Errorf("no cached repo found. (try 'helm repo update'). %s", err) } cv, err := i.Get(chartName, version) if err != nil { - return u, r, g, 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 %s not found in %s index. (try 'helm repo update'). %s", chartName, version, r.Config.Name, err) } if len(cv.URLs) == 0 { - return u, r, g, fmt.Errorf("chart %q has no downloadable URLs", ref) + return u, r.Client, fmt.Errorf("chart %q has no downloadable URLs", ref) } // TODO: Seems that picking first URL is not fully correct u, err = url.Parse(cv.URLs[0]) if err != nil { - return u, r, g, fmt.Errorf("invalid chart URL format: %s", ref) + return u, r.Client, fmt.Errorf("invalid chart URL format: %s", ref) } // If the URL is relative (no scheme), prepend the chart repo's base URL if !u.IsAbs() { repoURL, err := url.Parse(rc.URL) if err != nil { - return repoURL, r, nil, err + return repoURL, r.Client, err } q := repoURL.Query() // We need a trailing slash for ResolveReference to work, but make sure there isn't already one repoURL.Path = strings.TrimSuffix(repoURL.Path, "/") + "/" u = repoURL.ResolveReference(u) u.RawQuery = q.Encode() - g, err := getter.NewHTTPGetter(rc.URL, "", "", "") - if err != nil { - return repoURL, r, nil, err - } - g.SetCredentials(c.getRepoCredentials(r)) - return u, r, g, err + return u, r.Client, err } - return u, r, g, nil + return u, r.Client, nil +} + +// 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, diff --git a/pkg/downloader/chart_downloader_test.go b/pkg/downloader/chart_downloader_test.go index 80efa77e8..5967eee70 100644 --- a/pkg/downloader/chart_downloader_test.go +++ b/pkg/downloader/chart_downloader_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/downloader/doc.go b/pkg/downloader/doc.go index fb54936b8..c70b2f695 100644 --- a/pkg/downloader/doc.go +++ b/pkg/downloader/doc.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index 89a839b54..67f9dc7bf 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 @@ -99,11 +99,7 @@ func (m *Manager) Build() error { } // Now we need to fetch every package here into charts/ - if err := m.downloadAll(lock.Dependencies); err != nil { - return err - } - - return nil + return m.downloadAll(lock.Dependencies) } // Update updates a local charts directory. diff --git a/pkg/downloader/manager_test.go b/pkg/downloader/manager_test.go index 1ff2a9c17..8c2377e47 100644 --- a/pkg/downloader/manager_test.go +++ b/pkg/downloader/manager_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/downloader/testdata/signtest/alpine/templates/alpine-pod.yaml b/pkg/downloader/testdata/signtest/alpine/templates/alpine-pod.yaml index 08cf3c2c1..c34fa8c47 100644 --- a/pkg/downloader/testdata/signtest/alpine/templates/alpine-pod.yaml +++ b/pkg/downloader/testdata/signtest/alpine/templates/alpine-pod.yaml @@ -3,7 +3,7 @@ kind: Pod metadata: name: {{.Release.Name}}-{{.Chart.Name}} labels: - heritage: {{.Release.Service}} + app.kubernetes.io/managed-by: {{.Release.Service}} chartName: {{.Chart.Name}} chartVersion: {{.Chart.Version | quote}} annotations: diff --git a/pkg/engine/doc.go b/pkg/engine/doc.go index 53c4084b0..63c036605 100644 --- a/pkg/engine/doc.go +++ b/pkg/engine/doc.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index 7a940fc84..e29e044f9 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/engine/engine_test.go b/pkg/engine/engine_test.go index 8ffb3d87c..91a3fd795 100644 --- a/pkg/engine/engine_test.go +++ b/pkg/engine/engine_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/getter/doc.go b/pkg/getter/doc.go index fe51e4967..c53ef1ae0 100644 --- a/pkg/getter/doc.go +++ b/pkg/getter/doc.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/getter/getter.go b/pkg/getter/getter.go index ca018884a..c595fec69 100644 --- a/pkg/getter/getter.go +++ b/pkg/getter/getter.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/getter/getter_test.go b/pkg/getter/getter_test.go index 6d38a0d28..d03c82686 100644 --- a/pkg/getter/getter_test.go +++ b/pkg/getter/getter_test.go @@ -1,5 +1,5 @@ /* -Copyright 2017 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/getter/httpgetter.go b/pkg/getter/httpgetter.go index dd462ce5f..4987e951a 100644 --- a/pkg/getter/httpgetter.go +++ b/pkg/getter/httpgetter.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 @@ -23,17 +23,18 @@ import ( "strings" "k8s.io/helm/pkg/tlsutil" - "k8s.io/helm/pkg/urlutil" "k8s.io/helm/pkg/version" ) -//httpGetter is the efault HTTP(/S) backend handler -type HttpGetter struct { +//HttpGetter is the efault HTTP(/S) backend handler +// TODO: change the name to HTTPGetter in Helm 3 +type HttpGetter struct { //nolint client *http.Client username string password string } +//SetCredentials sets the credentials for the getter func (g *HttpGetter) SetCredentials(username, password string) { g.username = username g.password = password @@ -80,27 +81,17 @@ func newHTTPGetter(URL, CertFile, KeyFile, CAFile string) (Getter, error) { // NewHTTPGetter constructs a valid http/https client as HttpGetter func NewHTTPGetter(URL, CertFile, KeyFile, CAFile string) (*HttpGetter, error) { var client HttpGetter - if CertFile != "" && KeyFile != "" { - tlsConf, err := tlsutil.NewClientTLS(CertFile, KeyFile, CAFile) - if err != nil { - return &client, fmt.Errorf("can't create TLS config for client: %s", err.Error()) - } - tlsConf.BuildNameToCertificate() - - sni, err := urlutil.ExtractHostname(URL) + tr := &http.Transport{ + DisableCompression: true, + } + if (CertFile != "" && KeyFile != "") || CAFile != "" { + tlsConf, err := tlsutil.NewTLSConfig(URL, CertFile, KeyFile, CAFile) if err != nil { - return &client, err - } - tlsConf.ServerName = sni - - client.client = &http.Client{ - Transport: &http.Transport{ - TLSClientConfig: tlsConf, - Proxy: http.ProxyFromEnvironment, - }, + return &client, fmt.Errorf("can't create TLS config: %s", err.Error()) } - } else { - client.client = http.DefaultClient + tr.TLSClientConfig = tlsConf + tr.Proxy = http.ProxyFromEnvironment } + client.client = &http.Client{Transport: tr} return &client, nil } diff --git a/pkg/getter/httpgetter_test.go b/pkg/getter/httpgetter_test.go index fe3fde22a..fbe330390 100644 --- a/pkg/getter/httpgetter_test.go +++ b/pkg/getter/httpgetter_test.go @@ -1,5 +1,5 @@ /* -Copyright 2017 The Kubernetes Authors All rights reserved. +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 @@ -16,33 +16,92 @@ limitations under the License. package getter import ( + "io" "net/http" + "net/http/httptest" + "os" "path/filepath" + "strconv" "testing" ) +type TestFileHandler struct{} + +func (h *TestFileHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + HandleClient(w, r) +} + func TestHTTPGetter(t *testing.T) { g, err := newHTTPGetter("http://example.com", "", "", "") if err != nil { t.Fatal(err) } - if hg, ok := g.(*HttpGetter); !ok { - t.Fatal("Expected newHTTPGetter to produce an httpGetter") - } else if hg.client != http.DefaultClient { - t.Fatal("Expected newHTTPGetter to return a default HTTP client.") + if _, ok := g.(*HttpGetter); !ok { + t.Fatal("Expected newHTTPGetter to produce an HttpGetter") } // Test with SSL: cd := "../../testdata" join := filepath.Join ca, pub, priv := join(cd, "ca.pem"), join(cd, "crt.pem"), join(cd, "key.pem") - g, err = newHTTPGetter("http://example.com/", pub, priv, ca) + g, err = newHTTPGetter("https://example.com/", pub, priv, ca) if err != nil { t.Fatal(err) } + if hg, ok := g.(*HttpGetter); !ok { + t.Fatal("Expected newHTTPGetter to produce an HttpGetter") + } else if hg.client == http.DefaultClient { + t.Fatal("Expected newHTTPGetter to return a non-default HTTP client") + } - if _, ok := g.(*HttpGetter); !ok { - t.Fatal("Expected newHTTPGetter to produce an httpGetter") + // Test with SSL, caFile only + g, err = newHTTPGetter("https://example.com/", "", "", ca) + if err != nil { + t.Fatal(err) + } + if hg, ok := g.(*HttpGetter); !ok { + t.Fatal("Expected newHTTPGetter to produce an HttpGetter") + } else if hg.client == http.DefaultClient { + t.Fatal("Expected newHTTPGetter to return a non-default HTTP client") + } +} + +func HandleClient(writer http.ResponseWriter, request *http.Request) { + f, _ := os.Open("testdata/sssd-0.1.0.tgz") + defer f.Close() + + b := make([]byte, 512) + f.Read(b) + //Get the file size + FileStat, _ := f.Stat() + FileSize := strconv.FormatInt(FileStat.Size(), 10) + + //Simulating improper header values from bitbucket + writer.Header().Set("Content-Type", "application/x-tar") + writer.Header().Set("Content-Encoding", "gzip") + writer.Header().Set("Content-Length", FileSize) + + f.Seek(0, 0) + io.Copy(writer, f) + return +} + +func TestHTTPGetterTarDownload(t *testing.T) { + h := &TestFileHandler{} + server := httptest.NewServer(h) + defer server.Close() + + g, err := newHTTPGetter(server.URL, "", "", "") + if err != nil { + t.Fatal(err) + } + + data, _ := g.Get(server.URL) + mimeType := http.DetectContentType(data.Bytes()) + + expectedMimeType := "application/x-gzip" + if mimeType != expectedMimeType { + t.Fatalf("Expected response with MIME type %s, but got %s", expectedMimeType, mimeType) } } diff --git a/pkg/getter/plugingetter.go b/pkg/getter/plugingetter.go index c747eef7f..8f2099de0 100644 --- a/pkg/getter/plugingetter.go +++ b/pkg/getter/plugingetter.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 @@ -69,6 +69,7 @@ func (p *pluginGetter) Get(href string) (*bytes.Buffer, error) { buf := bytes.NewBuffer(nil) prog.Stdout = buf prog.Stderr = os.Stderr + prog.Stdin = os.Stdin if err := prog.Run(); err != nil { if eerr, ok := err.(*exec.ExitError); ok { os.Stderr.Write(eerr.Stderr) diff --git a/pkg/getter/plugingetter_test.go b/pkg/getter/plugingetter_test.go index f1fe9bf29..9bfe6144d 100644 --- a/pkg/getter/plugingetter_test.go +++ b/pkg/getter/plugingetter_test.go @@ -1,5 +1,5 @@ /* -Copyright 2017 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/getter/testdata/sssd-0.1.0.tgz b/pkg/getter/testdata/sssd-0.1.0.tgz new file mode 100644 index 000000000..2f34fece6 Binary files /dev/null and b/pkg/getter/testdata/sssd-0.1.0.tgz differ diff --git a/pkg/helm/client.go b/pkg/helm/client.go index 372613b2a..771c7f3d1 100644 --- a/pkg/helm/client.go +++ b/pkg/helm/client.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -44,6 +44,8 @@ type Client struct { // NewClient creates a new client. func NewClient(opts ...Option) *Client { var c Client + // set some sane defaults + c.Option(ConnectTimeout(5)) return c.Option(opts...) } @@ -95,6 +97,7 @@ func (h *Client) InstallReleaseFromChart(chart *chart.Chart, ns string, opts ... req.Namespace = ns req.DryRun = reqOpts.dryRun req.DisableHooks = reqOpts.disableHooks + req.DisableCrdHook = reqOpts.disableCRDHook req.ReuseName = reqOpts.reuseName ctx := NewContext() @@ -344,8 +347,22 @@ func (h *Client) list(ctx context.Context, req *rls.ListReleasesRequest) (*rls.L if err != nil { return nil, err } - - return s.Recv() + var resp *rls.ListReleasesResponse + for { + r, err := s.Recv() + if err == io.EOF { + break + } + if err != nil { + return nil, err + } + if resp == nil { + resp = r + continue + } + resp.Releases = append(resp.Releases, r.GetReleases()...) + } + return resp, nil } // Executes tiller.InstallRelease RPC. diff --git a/pkg/helm/client_test.go b/pkg/helm/client_test.go new file mode 100644 index 000000000..30d8e2002 --- /dev/null +++ b/pkg/helm/client_test.go @@ -0,0 +1,34 @@ +/* +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 helm + +import ( + "testing" + "time" +) + +func TestNewClient(t *testing.T) { + helmClient := NewClient() + if helmClient.opts.connectTimeout != 5*time.Second { + t.Errorf("expected default timeout duration to be 5 seconds, got %v", helmClient.opts.connectTimeout) + } + + helmClient = NewClient(ConnectTimeout(60)) + if helmClient.opts.connectTimeout != time.Minute { + t.Errorf("expected timeout duration to be 1 minute, got %v", helmClient.opts.connectTimeout) + } +} diff --git a/pkg/helm/environment/environment.go b/pkg/helm/environment/environment.go index 2980e6dc9..4241bbb8a 100644 --- a/pkg/helm/environment/environment.go +++ b/pkg/helm/environment/environment.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -49,6 +49,8 @@ type EnvSettings struct { Debug bool // KubeContext is the name of the kubeconfig context. KubeContext string + // KubeConfig is the path to an explicit kubeconfig file. This overwrites the value in $KUBECONFIG + KubeConfig string } // AddFlags binds flags to the given flagset. @@ -56,6 +58,7 @@ func (s *EnvSettings) AddFlags(fs *pflag.FlagSet) { fs.StringVar((*string)(&s.Home), "home", DefaultHelmHome, "location of your Helm config. Overrides $HELM_HOME") fs.StringVar(&s.TillerHost, "host", "", "address of Tiller. Overrides $HELM_HOST") fs.StringVar(&s.KubeContext, "kube-context", "", "name of the kubeconfig context to use") + fs.StringVar(&s.KubeConfig, "kubeconfig", "", "absolute path to the kubeconfig file to use") fs.BoolVar(&s.Debug, "debug", false, "enable verbose output") fs.StringVar(&s.TillerNamespace, "tiller-namespace", "kube-system", "namespace of Tiller") fs.Int64Var(&s.TillerConnectionTimeout, "tiller-connection-timeout", int64(300), "the duration (in seconds) Helm will wait to establish a connection to tiller") diff --git a/pkg/helm/environment/environment_test.go b/pkg/helm/environment/environment_test.go index 8f0caa388..35958e791 100644 --- a/pkg/helm/environment/environment_test.go +++ b/pkg/helm/environment/environment_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -35,8 +35,8 @@ func TestEnvSettings(t *testing.T) { envars map[string]string // expected values - home, host, ns, kcontext, plugins string - debug bool + home, host, ns, kcontext, kconfig, plugins string + debug bool }{ { name: "defaults", @@ -47,11 +47,12 @@ func TestEnvSettings(t *testing.T) { }, { name: "with flags set", - args: []string{"--home", "/foo", "--host=here", "--debug", "--tiller-namespace=myns"}, + args: []string{"--home", "/foo", "--host=here", "--debug", "--tiller-namespace=myns", "--kubeconfig", "/bar"}, home: "/foo", plugins: helmpath.Home("/foo").Plugins(), host: "here", ns: "myns", + kconfig: "/bar", debug: true, }, { @@ -111,6 +112,9 @@ func TestEnvSettings(t *testing.T) { if settings.KubeContext != tt.kcontext { t.Errorf("expected kube-context %q, got %q", tt.kcontext, settings.KubeContext) } + if settings.KubeConfig != tt.kconfig { + t.Errorf("expected kubeconfig %q, got %q", tt.kconfig, settings.KubeConfig) + } cleanup() }) diff --git a/pkg/helm/fake.go b/pkg/helm/fake.go index 0a9e77c44..a3b0ebc84 100644 --- a/pkg/helm/fake.go +++ b/pkg/helm/fake.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -18,7 +18,6 @@ package helm // import "k8s.io/helm/pkg/helm" import ( "errors" - "fmt" "math/rand" "sync" @@ -27,6 +26,7 @@ import ( "k8s.io/helm/pkg/proto/hapi/release" rls "k8s.io/helm/pkg/proto/hapi/services" "k8s.io/helm/pkg/proto/hapi/version" + storage "k8s.io/helm/pkg/storage/driver" ) // FakeClient implements Interface @@ -49,9 +49,28 @@ var _ Interface = (*FakeClient)(nil) // ListReleases lists the current releases func (c *FakeClient) ListReleases(opts ...ReleaseListOption) (*rls.ListReleasesResponse, error) { + reqOpts := c.Opts + for _, opt := range opts { + opt(&reqOpts) + } + req := &reqOpts.listReq + rels := c.Rels + count := int64(len(c.Rels)) + var next string + limit := req.GetLimit() + // TODO: Handle all other options. + if limit != 0 && limit < count { + rels = rels[:limit] + count = limit + next = c.Rels[limit].GetName() + } + resp := &rls.ListReleasesResponse{ - Count: int64(len(c.Rels)), - Releases: c.Rels, + Count: count, + Releases: rels, + } + if next != "" { + resp.Next = next } return resp, nil } @@ -69,6 +88,7 @@ func (c *FakeClient) InstallReleaseFromChart(chart *chart.Chart, ns string, opts } releaseName := c.Opts.instReq.Name + releaseDescription := c.Opts.instReq.Description // Check to see if the release already exists. rel, err := c.ReleaseStatus(releaseName, nil) @@ -76,8 +96,10 @@ func (c *FakeClient) InstallReleaseFromChart(chart *chart.Chart, ns string, opts return nil, errors.New("cannot re-use a name that is still in use") } - release := ReleaseMock(&MockReleaseOptions{Name: releaseName, Namespace: ns}) - c.Rels = append(c.Rels, release) + release := ReleaseMock(&MockReleaseOptions{Name: releaseName, Namespace: ns, Description: releaseDescription}) + if !c.Opts.dryRun { + c.Rels = append(c.Rels, release) + } return &rls.InstallReleaseResponse{ Release: release, @@ -95,7 +117,7 @@ func (c *FakeClient) DeleteRelease(rlsName string, opts ...DeleteOption) (*rls.U } } - return nil, fmt.Errorf("No such release: %s", rlsName) + return nil, storage.ErrReleaseNotFound(rlsName) } // GetVersion returns a fake version @@ -139,7 +161,7 @@ func (c *FakeClient) ReleaseStatus(rlsName string, opts ...StatusOption) (*rls.G }, nil } } - return nil, fmt.Errorf("No such release: %s", rlsName) + return nil, storage.ErrReleaseNotFound(rlsName) } // ReleaseContent returns the configuration for the matching release name in the fake release client. @@ -151,7 +173,7 @@ func (c *FakeClient) ReleaseContent(rlsName string, opts ...ContentOption) (resp }, nil } } - return resp, fmt.Errorf("No such release: %s", rlsName) + return resp, storage.ErrReleaseNotFound(rlsName) } // ReleaseHistory returns a release's revision history. @@ -206,11 +228,12 @@ metadata: // MockReleaseOptions allows for user-configurable options on mock release objects. type MockReleaseOptions struct { - Name string - Version int32 - Chart *chart.Chart - StatusCode release.Status_Code - Namespace string + Name string + Version int32 + Chart *chart.Chart + StatusCode release.Status_Code + Namespace string + Description string } // ReleaseMock creates a mock release object based on options set by MockReleaseOptions. This function should typically not be used outside of testing. @@ -232,6 +255,11 @@ func ReleaseMock(opts *MockReleaseOptions) *release.Release { namespace = "default" } + description := opts.Description + if description == "" { + description = "Release mock" + } + ch := opts.Chart if opts.Chart == nil { ch = &chart.Chart{ @@ -256,7 +284,7 @@ func ReleaseMock(opts *MockReleaseOptions) *release.Release { FirstDeployed: &date, LastDeployed: &date, Status: &release.Status{Code: scode}, - Description: "Release mock", + Description: description, }, Chart: ch, Config: &chart.Config{Raw: `name: "value"`}, diff --git a/pkg/helm/fake_test.go b/pkg/helm/fake_test.go index 9c0a53759..f16fbaf4c 100644 --- a/pkg/helm/fake_test.go +++ b/pkg/helm/fake_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -150,6 +150,23 @@ func TestFakeClient_InstallReleaseFromChart(t *testing.T) { }, wantErr: false, }, + { + name: "Add release with description.", + fields: fields{ + Rels: []*release.Release{}, + }, + args: args{ + ns: "default", + opts: []InstallOption{ReleaseName("new-release"), InstallDescription("foo-bar")}, + }, + want: &rls.InstallReleaseResponse{ + Release: ReleaseMock(&MockReleaseOptions{Name: "new-release", Description: "foo-bar"}), + }, + relsAfter: []*release.Release{ + ReleaseMock(&MockReleaseOptions{Name: "new-release", Description: "foo-bar"}), + }, + wantErr: false, + }, { name: "Try to add a release where the name already exists.", fields: fields{ diff --git a/pkg/helm/helm_test.go b/pkg/helm/helm_test.go index 2b0436581..fe7150cc0 100644 --- a/pkg/helm/helm_test.go +++ b/pkg/helm/helm_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/helm/helmpath/helmhome.go b/pkg/helm/helmpath/helmhome.go index b5ec4909e..9608ea6dd 100644 --- a/pkg/helm/helmpath/helmhome.go +++ b/pkg/helm/helmpath/helmhome.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/helm/helmpath/helmhome_unix_test.go b/pkg/helm/helmpath/helmhome_unix_test.go index 494d0f6b4..ca9035554 100644 --- a/pkg/helm/helmpath/helmhome_unix_test.go +++ b/pkg/helm/helmpath/helmhome_unix_test.go @@ -1,4 +1,4 @@ -// Copyright 2016 The Kubernetes Authors All rights reserved. +// 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 diff --git a/pkg/helm/helmpath/helmhome_windows_test.go b/pkg/helm/helmpath/helmhome_windows_test.go index e416bfd58..db1341421 100644 --- a/pkg/helm/helmpath/helmhome_windows_test.go +++ b/pkg/helm/helmpath/helmhome_windows_test.go @@ -1,4 +1,4 @@ -// Copyright 2016 The Kubernetes Authors All rights reserved. +// 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 diff --git a/pkg/helm/interface.go b/pkg/helm/interface.go index 10c04c710..d09b6cf8f 100644 --- a/pkg/helm/interface.go +++ b/pkg/helm/interface.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/helm/option.go b/pkg/helm/option.go index 3381e3f80..5579ae76d 100644 --- a/pkg/helm/option.go +++ b/pkg/helm/option.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -51,6 +51,8 @@ type options struct { force bool // if set, skip running hooks disableHooks bool + // if set, skip CRD hook only + disableCRDHook bool // name of release releaseName string // tls.Config to use for rpc if tls enabled @@ -260,6 +262,34 @@ func UpdateValueOverrides(raw []byte) UpdateOption { } } +// InstallDescription specifies the description for the release +func InstallDescription(description string) InstallOption { + return func(opts *options) { + opts.instReq.Description = description + } +} + +// UpgradeDescription specifies the description for the update +func UpgradeDescription(description string) UpdateOption { + return func(opts *options) { + opts.updateReq.Description = description + } +} + +// RollbackDescription specifies the description for the release +func RollbackDescription(description string) RollbackOption { + return func(opts *options) { + opts.rollbackReq.Description = description + } +} + +// DeleteDescription specifies the description for the release +func DeleteDescription(description string) DeleteOption { + return func(opts *options) { + opts.uninstallReq.Description = description + } +} + // DeleteDisableHooks will disable hooks for a deletion operation. func DeleteDisableHooks(disable bool) DeleteOption { return func(opts *options) { @@ -295,6 +325,13 @@ func InstallDisableHooks(disable bool) InstallOption { } } +// InstallDisableCRDHook disables CRD hook during installation. +func InstallDisableCRDHook(disable bool) InstallOption { + return func(opts *options) { + opts.disableCRDHook = disable + } +} + // InstallReuseName will (if true) instruct Tiller to re-use an existing name. func InstallReuseName(reuse bool) InstallOption { return func(opts *options) { diff --git a/pkg/helm/portforwarder/pod.go b/pkg/helm/portforwarder/pod.go index 7c2355204..239eb2730 100644 --- a/pkg/helm/portforwarder/pod.go +++ b/pkg/helm/portforwarder/pod.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -32,7 +32,7 @@ func isPodReady(pod *v1.Pod) bool { return isPodReadyConditionTrue(pod.Status) } -// isPodReady retruns true if a pod is ready; false otherwise. +// isPodReadyConditionTrue returns true if a pod is ready; false otherwise. func isPodReadyConditionTrue(status v1.PodStatus) bool { condition := getPodReadyCondition(status) return condition != nil && condition.Status == v1.ConditionTrue diff --git a/pkg/helm/portforwarder/portforwarder.go b/pkg/helm/portforwarder/portforwarder.go index 878610d5f..cc3261d1c 100644 --- a/pkg/helm/portforwarder/portforwarder.go +++ b/pkg/helm/portforwarder/portforwarder.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/helm/portforwarder/portforwarder_test.go b/pkg/helm/portforwarder/portforwarder_test.go index e4c148991..ad5a23bc8 100644 --- a/pkg/helm/portforwarder/portforwarder_test.go +++ b/pkg/helm/portforwarder/portforwarder_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/hooks/hooks.go b/pkg/hooks/hooks.go index ed2d946a4..5083672cd 100644 --- a/pkg/hooks/hooks.go +++ b/pkg/hooks/hooks.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -41,12 +41,14 @@ const ( PostRollback = "post-rollback" ReleaseTestSuccess = "test-success" ReleaseTestFailure = "test-failure" + CRDInstall = "crd-install" ) // Type of policy for deleting the hook const ( - HookSucceeded = "hook-succeeded" - HookFailed = "hook-failed" + HookSucceeded = "hook-succeeded" + HookFailed = "hook-failed" + BeforeHookCreation = "before-hook-creation" ) // FilterTestHooks filters the list of hooks are returns only testing hooks. diff --git a/pkg/ignore/doc.go b/pkg/ignore/doc.go index 7281c33a9..85cc91060 100644 --- a/pkg/ignore/doc.go +++ b/pkg/ignore/doc.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/ignore/rules.go b/pkg/ignore/rules.go index 76f45fc7a..9a8e08327 100644 --- a/pkg/ignore/rules.go +++ b/pkg/ignore/rules.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -77,7 +77,7 @@ func (r *Rules) Len() int { return len(r.patterns) } -// Ignore evalutes the file at the given path, and returns true if it should be ignored. +// Ignore evaluates the file at the given path, and returns true if it should be ignored. // // Ignore evaluates path against the rules in order. Evaluation stops when a match // is found. Matching a negative rule will stop evaluation. diff --git a/pkg/ignore/rules_test.go b/pkg/ignore/rules_test.go index 17b8bf403..a2f709097 100644 --- a/pkg/ignore/rules_test.go +++ b/pkg/ignore/rules_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/kube/client.go b/pkg/kube/client.go index cd5227dd7..167da9eef 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -35,28 +35,25 @@ import ( extv1beta1 "k8s.io/api/extensions/v1beta1" apiequality "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/strategicpatch" "k8s.io/apimachinery/pkg/watch" - "k8s.io/client-go/tools/clientcmd" + "k8s.io/kubernetes/pkg/api/legacyscheme" batchinternal "k8s.io/kubernetes/pkg/apis/batch" "k8s.io/kubernetes/pkg/apis/core" - conditions "k8s.io/kubernetes/pkg/client/unversioned" - "k8s.io/kubernetes/pkg/kubectl" + "k8s.io/kubernetes/pkg/kubectl/cmd/get" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" - "k8s.io/kubernetes/pkg/kubectl/resource" + "k8s.io/kubernetes/pkg/kubectl/genericclioptions" + "k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource" "k8s.io/kubernetes/pkg/kubectl/validation" - "k8s.io/kubernetes/pkg/printers" ) const ( - // MissingGetHeader is added to Get's outout when a resource is not found. + // MissingGetHeader is added to Get's output when a resource is not found. MissingGetHeader = "==> MISSING\nKIND\t\tNAME\n" ) @@ -66,21 +63,22 @@ var ErrNoObjectsVisited = goerrors.New("no objects visited") // Client represents a client capable of communicating with the Kubernetes API. type Client struct { cmdutil.Factory - // SchemaCacheDir is the path for loading cached schema. - SchemaCacheDir string - Log func(string, ...interface{}) } // New creates a new Client. -func New(config clientcmd.ClientConfig) *Client { +func New(getter genericclioptions.RESTClientGetter) *Client { + if getter == nil { + getter = genericclioptions.NewConfigFlags() + } return &Client{ - Factory: cmdutil.NewFactory(config), - SchemaCacheDir: clientcmd.RecommendedSchemaFile, - Log: func(_ string, _ ...interface{}) {}, + Factory: cmdutil.NewFactory(getter), + Log: nopLogger, } } +var nopLogger = func(_ string, _ ...interface{}) {} + // ResourceActorFunc performs an action on a single resource. type ResourceActorFunc func(*resource.Info) error @@ -112,8 +110,8 @@ func (c *Client) Create(namespace string, reader io.Reader, timeout int64, shoul func (c *Client) newBuilder(namespace string, reader io.Reader) *resource.Result { return c.NewBuilder(). - Internal(). ContinueOnError(). + WithScheme(legacyscheme.Scheme). Schema(c.validator()). NamespaceParam(namespace). DefaultNamespace(). @@ -140,6 +138,7 @@ func (c *Client) BuildUnstructured(namespace string, reader io.Reader) (Result, NamespaceParam(namespace). DefaultNamespace(). Stream(reader, ""). + Schema(c.validator()). Flatten(). Do().Infos() return result, scrubValidationError(err) @@ -179,7 +178,7 @@ 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 - objs[vk] = append(objs[vk], info.Object) + objs[vk] = append(objs[vk], asVersioned(info)) //Get the relation pods objPods, err = c.getSelectRelationPod(info, objPods) @@ -205,7 +204,7 @@ func (c *Client) Get(namespace string, reader io.Reader) (string, error) { // an object type changes, so we can just rely on that. Problem is it doesn't seem to keep // track of tab widths. buf := new(bytes.Buffer) - p, _ := c.Printer(nil, printers.PrintOptions{}) + p, _ := get.NewHumanPrintFlags().ToPrinter("") for t, ot := range objs { if _, err = buf.WriteString("==> " + t + "\n"); err != nil { return "", err @@ -294,7 +293,7 @@ func (c *Client) Update(namespace string, originalReader, targetReader io.Reader for _, info := range original.Difference(target) { c.Log("Deleting %q in %s...", info.Name, info.Namespace) - if err := deleteResource(c, info); err != nil { + if err := deleteResource(info); err != nil { c.Log("Failed to delete %q, err: %s", info.Name, err) } } @@ -314,7 +313,7 @@ func (c *Client) Delete(namespace string, reader io.Reader) error { } return perform(infos, func(info *resource.Info) error { c.Log("Starting delete for %q %s", info.Name, info.Mapping.GroupVersionKind.Kind) - err := deleteResource(c, info) + err := deleteResource(info) return c.skipIfNotFound(err) }) } @@ -376,39 +375,33 @@ func createResource(info *resource.Info) error { return info.Refresh(obj, true) } -func deleteResource(c *Client, info *resource.Info) error { - reaper, err := c.Reaper(info.Mapping) - if err != nil { - // If there is no reaper for this resources, delete it. - if kubectl.IsNoSuchReaperError(err) { - return resource.NewHelper(info.Client, info.Mapping).Delete(info.Namespace, info.Name) - } - return err - } - c.Log("Using reaper for deleting %q", info.Name) - return reaper.Stop(info.Namespace, info.Name, 0, nil) +func deleteResource(info *resource.Info) error { + policy := metav1.DeletePropagationBackground + opts := &metav1.DeleteOptions{PropagationPolicy: &policy} + _, err := resource.NewHelper(info.Client, info.Mapping).DeleteWithOptions(info.Namespace, info.Name, opts) + return err } -func createPatch(mapping *meta.RESTMapping, target, current runtime.Object) ([]byte, types.PatchType, error) { +func createPatch(target *resource.Info, current runtime.Object) ([]byte, types.PatchType, error) { oldData, err := json.Marshal(current) if err != nil { return nil, types.StrategicMergePatchType, fmt.Errorf("serializing current configuration: %s", err) } - newData, err := json.Marshal(target) + newData, err := json.Marshal(target.Object) if err != nil { return nil, types.StrategicMergePatchType, fmt.Errorf("serializing target configuration: %s", err) } // While different objects need different merge types, the parent function // that calls this does not try to create a patch when the data (first - // returned object) is nil. We can skip calculating the the merge type as + // returned object) is nil. We can skip calculating the merge type as // the returned merge type is ignored. if apiequality.Semantic.DeepEqual(oldData, newData) { return nil, types.StrategicMergePatchType, nil } // Get a versioned object - versionedObject, err := mapping.ConvertToVersion(target, mapping.GroupVersionKind.GroupVersion()) + versionedObject := asVersioned(target) // Unstructured objects, such as CRDs, may not have an not registered error // returned from ConvertToVersion. Anything that's unstructured should @@ -430,7 +423,7 @@ func createPatch(mapping *meta.RESTMapping, target, current runtime.Object) ([]b } func updateResource(c *Client, target *resource.Info, currentObj runtime.Object, force bool, recreate bool) error { - patch, patchType, err := createPatch(target.Mapping, target.Object, currentObj) + patch, patchType, err := createPatch(target, currentObj) if err != nil { return fmt.Errorf("failed to create patch: %s", err) } @@ -452,7 +445,7 @@ func updateResource(c *Client, target *resource.Info, currentObj runtime.Object, if force { // Attempt to delete... - if err := deleteResource(c, target); err != nil { + if err := deleteResource(target); err != nil { return err } log.Printf("Deleted %s: %q", kind, target.Name) @@ -480,16 +473,9 @@ func updateResource(c *Client, target *resource.Info, currentObj runtime.Object, return nil } - versioned, err := c.AsVersionedObject(target.Object) - if runtime.IsNotRegisteredError(err) { - return nil - } - if err != nil { - return err - } - - selector, err := getSelectorFromObject(versioned) - if err != nil { + versioned := asVersioned(target) + selector, ok := getSelectorFromObject(versioned) + if !ok { return nil } @@ -518,45 +504,45 @@ func updateResource(c *Client, target *resource.Info, currentObj runtime.Object, return nil } -func getSelectorFromObject(obj runtime.Object) (map[string]string, error) { +func getSelectorFromObject(obj runtime.Object) (map[string]string, bool) { switch typed := obj.(type) { case *v1.ReplicationController: - return typed.Spec.Selector, nil + return typed.Spec.Selector, true case *extv1beta1.ReplicaSet: - return typed.Spec.Selector.MatchLabels, nil + return typed.Spec.Selector.MatchLabels, true case *appsv1.ReplicaSet: - return typed.Spec.Selector.MatchLabels, nil + return typed.Spec.Selector.MatchLabels, true case *extv1beta1.Deployment: - return typed.Spec.Selector.MatchLabels, nil + return typed.Spec.Selector.MatchLabels, true case *appsv1beta1.Deployment: - return typed.Spec.Selector.MatchLabels, nil + return typed.Spec.Selector.MatchLabels, true case *appsv1beta2.Deployment: - return typed.Spec.Selector.MatchLabels, nil + return typed.Spec.Selector.MatchLabels, true case *appsv1.Deployment: - return typed.Spec.Selector.MatchLabels, nil + return typed.Spec.Selector.MatchLabels, true case *extv1beta1.DaemonSet: - return typed.Spec.Selector.MatchLabels, nil + return typed.Spec.Selector.MatchLabels, true case *appsv1beta2.DaemonSet: - return typed.Spec.Selector.MatchLabels, nil + return typed.Spec.Selector.MatchLabels, true case *appsv1.DaemonSet: - return typed.Spec.Selector.MatchLabels, nil + return typed.Spec.Selector.MatchLabels, true case *batch.Job: - return typed.Spec.Selector.MatchLabels, nil + return typed.Spec.Selector.MatchLabels, true case *appsv1beta1.StatefulSet: - return typed.Spec.Selector.MatchLabels, nil + return typed.Spec.Selector.MatchLabels, true case *appsv1beta2.StatefulSet: - return typed.Spec.Selector.MatchLabels, nil + return typed.Spec.Selector.MatchLabels, true case *appsv1.StatefulSet: - return typed.Spec.Selector.MatchLabels, nil + return typed.Spec.Selector.MatchLabels, true default: - return nil, fmt.Errorf("Unsupported kind when getting selector: %v", obj) + return nil, false } } @@ -601,17 +587,6 @@ func (c *Client) watchUntilReady(timeout time.Duration, info *resource.Info) err return err } -// AsVersionedObject converts a runtime.object to a versioned object. -func (c *Client) AsVersionedObject(obj runtime.Object) (runtime.Object, error) { - json, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj) - if err != nil { - return nil, err - } - versions := &runtime.VersionedObjects{} - err = runtime.DecodeInto(c.Decoder(true), json, versions) - return versions.First(), err -} - // waitForJob is a helper that waits for a job to complete. // // This operates on an event returned from a watcher. @@ -680,13 +655,28 @@ func (c *Client) watchPodUntilComplete(timeout time.Duration, info *resource.Inf c.Log("Watching pod %s for completion with timeout of %v", info.Name, timeout) _, err = watch.Until(timeout, w, func(e watch.Event) (bool, error) { - return conditions.PodCompleted(e) + return isPodComplete(e) }) return err } -//get an kubernetes resources's relation pods +func isPodComplete(event watch.Event) (bool, error) { + o, ok := event.Object.(*core.Pod) + if !ok { + return true, fmt.Errorf("expected a *core.Pod, got %T", event.Object) + } + if event.Type == watch.Deleted { + return false, fmt.Errorf("pod not found") + } + switch o.Status.Phase { + case core.PodFailed, core.PodSucceeded: + return true, nil + } + return false, nil +} + +//get a kubernetes resources' relation pods // kubernetes resource used select labels to relate pods func (c *Client) getSelectRelationPod(info *resource.Info, objPods map[string][]core.Pod) (map[string][]core.Pod, error) { if info == nil { @@ -695,22 +685,9 @@ func (c *Client) getSelectRelationPod(info *resource.Info, objPods map[string][] c.Log("get relation pod of object: %s/%s/%s", info.Namespace, info.Mapping.GroupVersionKind.Kind, info.Name) - versioned, err := c.AsVersionedObject(info.Object) - if runtime.IsNotRegisteredError(err) { - return objPods, nil - } - if err != nil { - return objPods, err - } - - // We can ignore this error because it will only error if it isn't a type that doesn't - // have pods. In that case, we don't care - selector, _ := getSelectorFromObject(versioned) - - selectorString := labels.Set(selector).AsSelector().String() - - // If we have an empty selector, this likely is a service or config map, so bail out now - if selectorString == "" { + versioned := asVersioned(info) + selector, ok := getSelectorFromObject(versioned) + if !ok { return objPods, nil } @@ -749,3 +726,7 @@ func isFoundPod(podItem []core.Pod, pod core.Pod) bool { } return false } + +func asVersioned(info *resource.Info) runtime.Object { + return cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping) +} diff --git a/pkg/kube/client_test.go b/pkg/kube/client_test.go index a81b2c949..617fce352 100644 --- a/pkg/kube/client_test.go +++ b/pkg/kube/client_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -18,32 +18,26 @@ package kube import ( "bytes" - "encoding/json" - "fmt" "io" "io/ioutil" "net/http" "strings" "testing" - "time" - "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/watch" - "k8s.io/client-go/dynamic" "k8s.io/client-go/rest/fake" + "k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/apis/core" - "k8s.io/kubernetes/pkg/kubectl" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" - cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" - "k8s.io/kubernetes/pkg/kubectl/resource" - "k8s.io/kubernetes/pkg/printers" - watchjson "k8s.io/kubernetes/pkg/watch/json" + "k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource" + "k8s.io/kubernetes/pkg/kubectl/scheme" ) +var unstructuredSerializer = resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer + func objBody(codec runtime.Codec, obj runtime.Object) io.ReadCloser { return ioutil.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(codec, obj)))) } @@ -99,49 +93,21 @@ func newResponse(code int, obj runtime.Object) (*http.Response, error) { return &http.Response{StatusCode: code, Header: header, Body: body}, nil } -type fakeReaper struct { - name string -} - -func (r *fakeReaper) Stop(namespace, name string, timeout time.Duration, gracePeriod *metav1.DeleteOptions) error { - r.name = name - return nil -} - -type fakeReaperFactory struct { - cmdutil.Factory - reaper kubectl.Reaper +type testClient struct { + *Client + *cmdtesting.TestFactory } -func (f *fakeReaperFactory) Reaper(mapping *meta.RESTMapping) (kubectl.Reaper, error) { - return f.reaper, nil -} - -func newEventResponse(code int, e *watch.Event) (*http.Response, error) { - dispatchedEvent, err := encodeAndMarshalEvent(e) - if err != nil { - return nil, err +func newTestClient() *testClient { + tf := cmdtesting.NewTestFactory() + c := &Client{ + Factory: tf, + Log: nopLogger, } - - header := http.Header{} - header.Set("Content-Type", runtime.ContentTypeJSON) - body := ioutil.NopCloser(bytes.NewReader(dispatchedEvent)) - return &http.Response{StatusCode: code, Header: header, Body: body}, nil -} - -func encodeAndMarshalEvent(e *watch.Event) ([]byte, error) { - encodedEvent, err := watchjson.Object(testapi.Default.Codec(), e) - if err != nil { - return nil, err + return &testClient{ + Client: c, + TestFactory: tf, } - - return json.Marshal(encodedEvent) -} - -func newTestClient(f cmdutil.Factory) *Client { - c := New(nil) - c.Factory = f - return c } func TestUpdate(t *testing.T) { @@ -153,10 +119,11 @@ func TestUpdate(t *testing.T) { var actions []string - f, tf, codec, _ := cmdtesting.NewAPIFactory() + tf := cmdtesting.NewTestFactory() + defer tf.Cleanup() + tf.UnstructuredClient = &fake.RESTClient{ - GroupVersion: schema.GroupVersion{Version: "v1"}, - NegotiatedSerializer: dynamic.ContentConfig().NegotiatedSerializer, + NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { p, m := req.URL.Path, req.Method actions = append(actions, p+":"+m) @@ -190,9 +157,12 @@ func TestUpdate(t *testing.T) { }), } - reaper := &fakeReaper{} - rf := &fakeReaperFactory{Factory: f, reaper: reaper} - c := newTestClient(rf) + c := &Client{ + Factory: tf, + Log: nopLogger, + } + codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...) + if err := c.Update(core.NamespaceDefault, objBody(codec, &listA), objBody(codec, &listB), false, false, 0, false); err != nil { t.Fatal(err) } @@ -213,6 +183,7 @@ func TestUpdate(t *testing.T) { "/namespaces/default/pods/otter:GET", "/namespaces/default/pods/dolphin:GET", "/namespaces/default/pods:POST", + "/namespaces/default/pods/squid:DELETE", } if len(expectedActions) != len(actions) { t.Errorf("unexpected number of requests, expected %d, got %d", len(expectedActions), len(actions)) @@ -223,11 +194,6 @@ func TestUpdate(t *testing.T) { t.Errorf("expected %s request got %s", v, actions[k]) } } - - if reaper.name != "squid" { - t.Errorf("unexpected reaper: %#v", reaper) - } - } func TestBuild(t *testing.T) { @@ -251,54 +217,35 @@ func TestBuild(t *testing.T) { }, } + c := newTestClient() for _, tt := range tests { - f, _, _, _ := cmdtesting.NewAPIFactory() - c := newTestClient(f) - - // Test for an invalid manifest - infos, err := c.Build(tt.namespace, tt.reader) - if err != nil && !tt.err { - t.Errorf("%q. Got error message when no error should have occurred: %v", tt.name, err) - } else if err != nil && strings.Contains(err.Error(), "--validate=false") { - t.Errorf("%q. error message was not scrubbed", tt.name) - } + t.Run(tt.name, func(t *testing.T) { + c.Cleanup() + + // Test for an invalid manifest + infos, err := c.Build(tt.namespace, tt.reader) + if err != nil && !tt.err { + t.Errorf("Got error message when no error should have occurred: %v", err) + } else if err != nil && strings.Contains(err.Error(), "--validate=false") { + t.Error("error message was not scrubbed") + } - if len(infos) != tt.count { - t.Errorf("%q. expected %d result objects, got %d", tt.name, tt.count, len(infos)) - } + if len(infos) != tt.count { + t.Errorf("expected %d result objects, got %d", tt.count, len(infos)) + } + }) } } -type testPrinter struct { - Objects []runtime.Object - Err error - printers.ResourcePrinter -} - -func (t *testPrinter) PrintObj(obj runtime.Object, out io.Writer) error { - t.Objects = append(t.Objects, obj) - fmt.Fprintf(out, "%#v", obj) - return t.Err -} - -func (t *testPrinter) HandledResources() []string { - return []string{} -} - -func (t *testPrinter) AfterPrint(io.Writer, string) error { - return t.Err -} - func TestGet(t *testing.T) { list := newPodList("starfish", "otter") - f, tf, _, _ := cmdtesting.NewAPIFactory() - tf.Printer = &testPrinter{} - tf.UnstructuredClient = &fake.RESTClient{ + c := newTestClient() + defer c.Cleanup() + c.TestFactory.UnstructuredClient = &fake.RESTClient{ GroupVersion: schema.GroupVersion{Version: "v1"}, - NegotiatedSerializer: dynamic.ContentConfig().NegotiatedSerializer, + NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { p, m := req.URL.Path, req.Method - //actions = append(actions, p+":"+m) t.Logf("got request %s %s", p, m) switch { case p == "/namespaces/default/pods/starfish" && m == "GET": @@ -311,7 +258,6 @@ func TestGet(t *testing.T) { } }), } - c := newTestClient(f) // Test Success data := strings.NewReader("kind: Pod\napiVersion: v1\nmetadata:\n name: otter") @@ -358,101 +304,37 @@ func TestPerform(t *testing.T) { } for _, tt := range tests { - results := []*resource.Info{} + t.Run(tt.name, func(t *testing.T) { + results := []*resource.Info{} - fn := func(info *resource.Info) error { - results = append(results, info) + fn := func(info *resource.Info) error { + results = append(results, info) - if info.Namespace != tt.namespace { - t.Errorf("%q. expected namespace to be '%s', got %s", tt.name, tt.namespace, info.Namespace) + if info.Namespace != tt.namespace { + t.Errorf("expected namespace to be '%s', got %s", tt.namespace, info.Namespace) + } + return nil } - return nil - } - - f, _, _, _ := cmdtesting.NewAPIFactory() - c := newTestClient(f) - infos, err := c.Build(tt.namespace, tt.reader) - if err != nil && err.Error() != tt.errMessage { - t.Errorf("%q. Error while building manifests: %v", tt.name, err) - } - - err = perform(infos, fn) - if (err != nil) != tt.err { - t.Errorf("%q. expected error: %v, got %v", tt.name, tt.err, err) - } - if err != nil && err.Error() != tt.errMessage { - t.Errorf("%q. expected error message: %v, got %v", tt.name, tt.errMessage, err) - } - - if len(results) != tt.count { - t.Errorf("%q. expected %d result objects, got %d", tt.name, tt.count, len(results)) - } - } -} - -func TestWaitAndGetCompletedPodPhase(t *testing.T) { - tests := []struct { - podPhase core.PodPhase - expectedPhase core.PodPhase - err bool - errMessage string - }{ - { - podPhase: core.PodPending, - expectedPhase: core.PodUnknown, - err: true, - errMessage: "watch closed before Until timeout", - }, { - podPhase: core.PodRunning, - expectedPhase: core.PodUnknown, - err: true, - errMessage: "watch closed before Until timeout", - }, { - podPhase: core.PodSucceeded, - expectedPhase: core.PodSucceeded, - }, { - podPhase: core.PodFailed, - expectedPhase: core.PodFailed, - }, - } - for _, tt := range tests { - f, tf, codec, ns := cmdtesting.NewAPIFactory() - actions := make(map[string]string) - - var testPodList core.PodList - testPodList.Items = append(testPodList.Items, newPodWithStatus("bestpod", core.PodStatus{Phase: tt.podPhase}, "test")) - - tf.Client = &fake.RESTClient{ - NegotiatedSerializer: ns, - Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { - p, m := req.URL.Path, req.Method - actions[p] = m - switch { - case p == "/namespaces/test/pods/bestpod" && m == "GET": - return newResponse(200, &testPodList.Items[0]) - case p == "/namespaces/test/pods" && m == "GET": - event := watch.Event{Type: watch.Added, Object: &testPodList.Items[0]} - return newEventResponse(200, &event) - default: - t.Fatalf("unexpected request: %#v\n%#v", req.URL, req) - return nil, nil - } - }), - } + c := newTestClient() + defer c.Cleanup() + infos, err := c.Build(tt.namespace, tt.reader) + if err != nil && err.Error() != tt.errMessage { + t.Errorf("Error while building manifests: %v", err) + } - c := newTestClient(f) + err = perform(infos, fn) + if (err != nil) != tt.err { + t.Errorf("expected error: %v, got %v", tt.err, err) + } + if err != nil && err.Error() != tt.errMessage { + t.Errorf("expected error message: %v, got %v", tt.errMessage, err) + } - phase, err := c.WaitAndGetCompletedPodPhase("test", objBody(codec, &testPodList), 1*time.Second) - if (err != nil) != tt.err { - t.Fatalf("Expected error but there was none.") - } - if err != nil && err.Error() != tt.errMessage { - t.Fatalf("Expected error %s, got %s", tt.errMessage, err.Error()) - } - if phase != tt.expectedPhase { - t.Fatalf("Expected pod phase %s, got %s", tt.expectedPhase, phase) - } + if len(results) != tt.count { + t.Errorf("expected %d result objects, got %d", tt.count, len(results)) + } + }) } } diff --git a/pkg/kube/config.go b/pkg/kube/config.go index b6560486e..7504d9028 100644 --- a/pkg/kube/config.go +++ b/pkg/kube/config.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -16,10 +16,12 @@ limitations under the License. package kube // import "k8s.io/helm/pkg/kube" -import "k8s.io/client-go/tools/clientcmd" +import ( + "k8s.io/client-go/tools/clientcmd" +) // GetConfig returns a Kubernetes client config for a given context. -func GetConfig(context string) clientcmd.ClientConfig { +func GetConfig(context string, kubeconfig string) clientcmd.ClientConfig { rules := clientcmd.NewDefaultClientConfigLoadingRules() rules.DefaultClientConfig = &clientcmd.DefaultClientConfig @@ -28,5 +30,10 @@ func GetConfig(context string) clientcmd.ClientConfig { if context != "" { overrides.CurrentContext = context } + + if kubeconfig != "" { + rules.ExplicitPath = kubeconfig + } + return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(rules, overrides) } diff --git a/pkg/kube/log.go b/pkg/kube/log.go index fbe51823a..fc3683b1d 100644 --- a/pkg/kube/log.go +++ b/pkg/kube/log.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/kube/namespace.go b/pkg/kube/namespace.go index 9d2793d87..57e62bab7 100644 --- a/pkg/kube/namespace.go +++ b/pkg/kube/namespace.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -27,6 +27,9 @@ func createNamespace(client internalclientset.Interface, namespace string) error ns := &core.Namespace{ ObjectMeta: metav1.ObjectMeta{ Name: namespace, + Labels: map[string]string{ + "name": namespace, + }, }, } _, err := client.Core().Namespaces().Create(ns) @@ -40,7 +43,16 @@ func getNamespace(client internalclientset.Interface, namespace string) (*core.N func ensureNamespace(client internalclientset.Interface, namespace string) error { _, err := getNamespace(client, namespace) if err != nil && errors.IsNotFound(err) { - return createNamespace(client, namespace) + err = createNamespace(client, namespace) + + // If multiple commands which run `ensureNamespace` are run in + // parallel, then protect against the race condition in which + // the namespace did not exist when `getNamespace` was executed, + // but did exist when `createNamespace` was executed. If that + // happens, we can just proceed as normal. + if errors.IsAlreadyExists(err) { + return nil + } } return err } diff --git a/pkg/kube/namespace_test.go b/pkg/kube/namespace_test.go index eb96557d0..79e8e880c 100644 --- a/pkg/kube/namespace_test.go +++ b/pkg/kube/namespace_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/kube/result.go b/pkg/kube/result.go index 87c7e6ac1..0c6289e49 100644 --- a/pkg/kube/result.go +++ b/pkg/kube/result.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -16,7 +16,7 @@ limitations under the License. package kube // import "k8s.io/helm/pkg/kube" -import "k8s.io/kubernetes/pkg/kubectl/resource" +import "k8s.io/kubernetes/pkg/kubectl/genericclioptions/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 962e90426..503473c05 100644 --- a/pkg/kube/result_test.go +++ b/pkg/kube/result_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -19,15 +19,14 @@ package kube // import "k8s.io/helm/pkg/kube" import ( "testing" + "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/kubernetes/pkg/api/testapi" - "k8s.io/kubernetes/pkg/kubectl/resource" + "k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource" ) func TestResult(t *testing.T) { - mapping, err := testapi.Default.RESTMapper().RESTMapping(schema.GroupKind{Kind: "Pod"}) - if err != nil { - t.Fatal(err) + mapping := &meta.RESTMapping{ + Resource: schema.GroupVersionResource{Group: "group", Version: "version", Resource: "pod"}, } info := func(name string) *resource.Info { diff --git a/pkg/kube/tunnel.go b/pkg/kube/tunnel.go index 08280f25d..f4eaa7e26 100644 --- a/pkg/kube/tunnel.go +++ b/pkg/kube/tunnel.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/kube/tunnel_test.go b/pkg/kube/tunnel_test.go index 264200ddf..37fb296a3 100644 --- a/pkg/kube/tunnel_test.go +++ b/pkg/kube/tunnel_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/kube/wait.go b/pkg/kube/wait.go index 27ede15db..960409df9 100644 --- a/pkg/kube/wait.go +++ b/pkg/kube/wait.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -27,7 +27,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/kubernetes" podutil "k8s.io/kubernetes/pkg/api/v1/pod" @@ -37,8 +36,8 @@ import ( // deployment holds associated replicaSets for a deployment type deployment struct { - replicaSets *extensions.ReplicaSet - deployment *extensions.Deployment + replicaSets *appsv1.ReplicaSet + deployment *appsv1.Deployment } // waitForResources polls to get the current status of all pods, PVCs, and Services @@ -56,11 +55,7 @@ func (c *Client) waitForResources(timeout time.Duration, created Result) error { pvc := []v1.PersistentVolumeClaim{} deployments := []deployment{} for _, v := range created { - obj, err := c.AsVersionedObject(v.Object) - if err != nil && !runtime.IsNotRegisteredError(err) { - return false, err - } - switch value := obj.(type) { + switch value := asVersioned(v).(type) { case *v1.ReplicationController: list, err := getPods(kcs, value.Namespace, value.Spec.Selector) if err != nil { @@ -74,12 +69,12 @@ func (c *Client) waitForResources(timeout time.Duration, created Result) error { } pods = append(pods, *pod) case *appsv1.Deployment: - currentDeployment, err := kcs.ExtensionsV1beta1().Deployments(value.Namespace).Get(value.Name, metav1.GetOptions{}) + currentDeployment, err := kcs.AppsV1().Deployments(value.Namespace).Get(value.Name, metav1.GetOptions{}) if err != nil { return false, err } // Find RS associated with deployment - newReplicaSet, err := deploymentutil.GetNewReplicaSet(currentDeployment, kcs.ExtensionsV1beta1()) + newReplicaSet, err := deploymentutil.GetNewReplicaSet(currentDeployment, kcs.AppsV1()) if err != nil || newReplicaSet == nil { return false, err } @@ -89,12 +84,12 @@ func (c *Client) waitForResources(timeout time.Duration, created Result) error { } deployments = append(deployments, newDeployment) case *appsv1beta1.Deployment: - currentDeployment, err := kcs.ExtensionsV1beta1().Deployments(value.Namespace).Get(value.Name, metav1.GetOptions{}) + currentDeployment, err := kcs.AppsV1().Deployments(value.Namespace).Get(value.Name, metav1.GetOptions{}) if err != nil { return false, err } // Find RS associated with deployment - newReplicaSet, err := deploymentutil.GetNewReplicaSet(currentDeployment, kcs.ExtensionsV1beta1()) + newReplicaSet, err := deploymentutil.GetNewReplicaSet(currentDeployment, kcs.AppsV1()) if err != nil || newReplicaSet == nil { return false, err } @@ -104,12 +99,12 @@ func (c *Client) waitForResources(timeout time.Duration, created Result) error { } deployments = append(deployments, newDeployment) case *appsv1beta2.Deployment: - currentDeployment, err := kcs.ExtensionsV1beta1().Deployments(value.Namespace).Get(value.Name, metav1.GetOptions{}) + currentDeployment, err := kcs.AppsV1().Deployments(value.Namespace).Get(value.Name, metav1.GetOptions{}) if err != nil { return false, err } // Find RS associated with deployment - newReplicaSet, err := deploymentutil.GetNewReplicaSet(currentDeployment, kcs.ExtensionsV1beta1()) + newReplicaSet, err := deploymentutil.GetNewReplicaSet(currentDeployment, kcs.AppsV1()) if err != nil || newReplicaSet == nil { return false, err } @@ -119,12 +114,12 @@ func (c *Client) waitForResources(timeout time.Duration, created Result) error { } deployments = append(deployments, newDeployment) case *extensions.Deployment: - currentDeployment, err := kcs.ExtensionsV1beta1().Deployments(value.Namespace).Get(value.Name, metav1.GetOptions{}) + currentDeployment, err := kcs.AppsV1().Deployments(value.Namespace).Get(value.Name, metav1.GetOptions{}) if err != nil { return false, err } // Find RS associated with deployment - newReplicaSet, err := deploymentutil.GetNewReplicaSet(currentDeployment, kcs.ExtensionsV1beta1()) + newReplicaSet, err := deploymentutil.GetNewReplicaSet(currentDeployment, kcs.AppsV1()) if err != nil || newReplicaSet == nil { return false, err } diff --git a/pkg/lint/lint.go b/pkg/lint/lint.go index 256eab906..aa8df5814 100644 --- a/pkg/lint/lint.go +++ b/pkg/lint/lint.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/lint/lint_test.go b/pkg/lint/lint_test.go index d84faa10b..84dfbf508 100644 --- a/pkg/lint/lint_test.go +++ b/pkg/lint/lint_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/lint/rules/chartfile.go b/pkg/lint/rules/chartfile.go index 0dab0d250..12f028af1 100644 --- a/pkg/lint/rules/chartfile.go +++ b/pkg/lint/rules/chartfile.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/lint/rules/chartfile_test.go b/pkg/lint/rules/chartfile_test.go index 99dc4de0f..235e5fc4c 100644 --- a/pkg/lint/rules/chartfile_test.go +++ b/pkg/lint/rules/chartfile_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/lint/rules/template.go b/pkg/lint/rules/template.go index a8b6a6757..8b51b14f8 100644 --- a/pkg/lint/rules/template.go +++ b/pkg/lint/rules/template.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/lint/rules/template_test.go b/pkg/lint/rules/template_test.go index cb1be94a2..41a7384e7 100644 --- a/pkg/lint/rules/template_test.go +++ b/pkg/lint/rules/template_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/lint/rules/testdata/albatross/templates/svc.yaml b/pkg/lint/rules/testdata/albatross/templates/svc.yaml index 167148112..aea11d833 100644 --- a/pkg/lint/rules/testdata/albatross/templates/svc.yaml +++ b/pkg/lint/rules/testdata/albatross/templates/svc.yaml @@ -5,9 +5,9 @@ kind: Service metadata: name: "{{ .Values.name }}" labels: - heritage: {{ .Release.Service | quote }} - release: {{ .Release.Name | quote }} - chart: "{{.Chart.Name}}-{{.Chart.Version}}" + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{.Chart.Name}}-{{.Chart.Version}}" kubeVersion: {{ .Capabilities.KubeVersion.Major }} tillerVersion: {{ .Capabilities.TillerVersion }} spec: diff --git a/pkg/lint/rules/values.go b/pkg/lint/rules/values.go index 9b97598f0..4781cc176 100644 --- a/pkg/lint/rules/values.go +++ b/pkg/lint/rules/values.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/lint/support/doc.go b/pkg/lint/support/doc.go index 4cf7272e4..ede608906 100644 --- a/pkg/lint/support/doc.go +++ b/pkg/lint/support/doc.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/lint/support/message.go b/pkg/lint/support/message.go index 6a878031a..5efbc7a61 100644 --- a/pkg/lint/support/message.go +++ b/pkg/lint/support/message.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -18,7 +18,7 @@ package support import "fmt" -// Severity indicatest the severity of a Message. +// Severity indicates the severity of a Message. const ( // UnknownSev indicates that the severity of the error is unknown, and should not stop processing. UnknownSev = iota diff --git a/pkg/lint/support/message_test.go b/pkg/lint/support/message_test.go index 4a9c33c34..55675eeee 100644 --- a/pkg/lint/support/message_test.go +++ b/pkg/lint/support/message_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/plugin/cache/cache.go b/pkg/plugin/cache/cache.go index a1d3224c8..d846126f1 100644 --- a/pkg/plugin/cache/cache.go +++ b/pkg/plugin/cache/cache.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/plugin/hooks.go b/pkg/plugin/hooks.go index b5ca032ac..70ce5d122 100644 --- a/pkg/plugin/hooks.go +++ b/pkg/plugin/hooks.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/plugin/installer/base.go b/pkg/plugin/installer/base.go index 0664dae76..15ce3cbcf 100644 --- a/pkg/plugin/installer/base.go +++ b/pkg/plugin/installer/base.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/plugin/installer/doc.go b/pkg/plugin/installer/doc.go index a2a66f3e1..0089e33f8 100644 --- a/pkg/plugin/installer/doc.go +++ b/pkg/plugin/installer/doc.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/plugin/installer/http_installer.go b/pkg/plugin/installer/http_installer.go index 91d497651..fd58b88ca 100644 --- a/pkg/plugin/installer/http_installer.go +++ b/pkg/plugin/installer/http_installer.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 @@ -21,14 +21,17 @@ import ( "compress/gzip" "fmt" "io" - "k8s.io/helm/pkg/getter" - "k8s.io/helm/pkg/helm/environment" - "k8s.io/helm/pkg/helm/helmpath" - "k8s.io/helm/pkg/plugin/cache" "os" "path/filepath" "regexp" "strings" + + fp "github.com/cyphar/filepath-securejoin" + + "k8s.io/helm/pkg/getter" + "k8s.io/helm/pkg/helm/environment" + "k8s.io/helm/pkg/helm/helmpath" + "k8s.io/helm/pkg/plugin/cache" ) // HTTPInstaller installs plugins from an archive served by a web server. @@ -181,7 +184,10 @@ func (g *TarGzExtractor) Extract(buffer *bytes.Buffer, targetDir string) error { return err } - path := filepath.Join(targetDir, header.Name) + path, err := fp.SecureJoin(targetDir, header.Name) + if err != nil { + return err + } switch header.Typeflag { case tar.TypeDir: diff --git a/pkg/plugin/installer/http_installer_test.go b/pkg/plugin/installer/http_installer_test.go index ca1a71e3e..73af75e8c 100644 --- a/pkg/plugin/installer/http_installer_test.go +++ b/pkg/plugin/installer/http_installer_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 @@ -16,12 +16,15 @@ limitations under the License. package installer // import "k8s.io/helm/pkg/plugin/installer" import ( + "archive/tar" "bytes" + "compress/gzip" "encoding/base64" "fmt" "io/ioutil" "k8s.io/helm/pkg/helm/helmpath" "os" + "path/filepath" "testing" ) @@ -187,3 +190,88 @@ func TestHTTPInstallerUpdate(t *testing.T) { t.Error("update method not implemented for http installer") } } + +func TestExtract(t *testing.T) { + //create a temp home + hh, err := ioutil.TempDir("", "helm-home-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(hh) + + home := helmpath.Home(hh) + if err := os.MkdirAll(home.Plugins(), 0755); err != nil { + t.Fatalf("Could not create %s: %s", home.Plugins(), err) + } + + cacheDir := filepath.Join(home.Cache(), "plugins", "plugin-key") + if err := os.MkdirAll(cacheDir, 0755); err != nil { + t.Fatalf("Could not create %s: %s", cacheDir, err) + } + + //{"plugin.yaml", "plugin metadata up in here"}, + //{"README.md", "so you know what's upp"}, + //{"script.sh", "echo script"}, + + var tarbuf bytes.Buffer + tw := tar.NewWriter(&tarbuf) + var files = []struct { + Name, Body string + }{ + {"../../plugin.yaml", "sneaky plugin metadata"}, + {"README.md", "some text"}, + } + for _, file := range files { + hdr := &tar.Header{ + Name: file.Name, + Typeflag: tar.TypeReg, + Mode: 0600, + Size: int64(len(file.Body)), + } + if err := tw.WriteHeader(hdr); err != nil { + t.Fatal(err) + } + if _, err := tw.Write([]byte(file.Body)); err != nil { + t.Fatal(err) + } + } + if err := tw.Close(); err != nil { + t.Fatal(err) + } + + var buf bytes.Buffer + gz := gzip.NewWriter(&buf) + if _, err := gz.Write(tarbuf.Bytes()); err != nil { + t.Fatal(err) + } + gz.Close() + + source := "https://repo.localdomain/plugins/fake-plugin-0.0.1.tgz" + extr, err := NewExtractor(source) + if err != nil { + t.Fatal(err) + } + + if err = extr.Extract(&buf, cacheDir); err != nil { + t.Errorf("Did not expect error but got error: %v", err) + } + + pluginYAMLFullPath := filepath.Join(cacheDir, "plugin.yaml") + if _, err := os.Stat(pluginYAMLFullPath); err != nil { + if os.IsNotExist(err) { + t.Errorf("Expected %s to exist but doesn't", pluginYAMLFullPath) + } else { + t.Error(err) + } + } + + readmeFullPath := filepath.Join(cacheDir, "README.md") + if _, err := os.Stat(readmeFullPath); err != nil { + if os.IsNotExist(err) { + t.Errorf("Expected %s to exist but doesn't", readmeFullPath) + } else { + t.Error(err) + } + } + +} diff --git a/pkg/plugin/installer/installer.go b/pkg/plugin/installer/installer.go index 02aee9f46..76c751d50 100644 --- a/pkg/plugin/installer/installer.go +++ b/pkg/plugin/installer/installer.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/plugin/installer/local_installer.go b/pkg/plugin/installer/local_installer.go index 3cf6bb422..f39086a6e 100644 --- a/pkg/plugin/installer/local_installer.go +++ b/pkg/plugin/installer/local_installer.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/plugin/installer/local_installer_test.go b/pkg/plugin/installer/local_installer_test.go index 6a7c957d6..fb5fa2675 100644 --- a/pkg/plugin/installer/local_installer_test.go +++ b/pkg/plugin/installer/local_installer_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/plugin/installer/vcs_installer.go b/pkg/plugin/installer/vcs_installer.go index 0a373a971..4b502dae4 100644 --- a/pkg/plugin/installer/vcs_installer.go +++ b/pkg/plugin/installer/vcs_installer.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/plugin/installer/vcs_installer_test.go b/pkg/plugin/installer/vcs_installer_test.go index 453899543..548a7a49a 100644 --- a/pkg/plugin/installer/vcs_installer_test.go +++ b/pkg/plugin/installer/vcs_installer_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 @@ -133,9 +133,9 @@ func TestVCSInstallerNonExistentVersion(t *testing.T) { } if err := Install(i); err == nil { - t.Error("expected error for version does not exists, got none") + t.Error("expected error for version does not exist, got none") } else if err.Error() != fmt.Sprintf("requested version %q does not exist for plugin %q", version, source) { - t.Errorf("expected error for version does not exists, got (%v)", err) + t.Errorf("expected error for version does not exist, got (%v)", err) } } func TestVCSInstallerUpdate(t *testing.T) { diff --git a/pkg/plugin/plugin.go b/pkg/plugin/plugin.go index b3458c2d8..07fcc700a 100644 --- a/pkg/plugin/plugin.go +++ b/pkg/plugin/plugin.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/plugin/plugin_test.go b/pkg/plugin/plugin_test.go index 5ddbf15f3..338d949f8 100644 --- a/pkg/plugin/plugin_test.go +++ b/pkg/plugin/plugin_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/proto/hapi/release/hook.pb.go b/pkg/proto/hapi/release/hook.pb.go index 508448280..0a44165c8 100644 --- a/pkg/proto/hapi/release/hook.pb.go +++ b/pkg/proto/hapi/release/hook.pb.go @@ -52,6 +52,7 @@ const ( Hook_POST_ROLLBACK Hook_Event = 8 Hook_RELEASE_TEST_SUCCESS Hook_Event = 9 Hook_RELEASE_TEST_FAILURE Hook_Event = 10 + Hook_CRD_INSTALL Hook_Event = 11 ) var Hook_Event_name = map[int32]string{ @@ -66,6 +67,7 @@ var Hook_Event_name = map[int32]string{ 8: "POST_ROLLBACK", 9: "RELEASE_TEST_SUCCESS", 10: "RELEASE_TEST_FAILURE", + 11: "CRD_INSTALL", } var Hook_Event_value = map[string]int32{ "UNKNOWN": 0, @@ -79,6 +81,7 @@ var Hook_Event_value = map[string]int32{ "POST_ROLLBACK": 8, "RELEASE_TEST_SUCCESS": 9, "RELEASE_TEST_FAILURE": 10, + "CRD_INSTALL": 11, } func (x Hook_Event) String() string { @@ -89,17 +92,20 @@ func (Hook_Event) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []i type Hook_DeletePolicy int32 const ( - Hook_SUCCEEDED Hook_DeletePolicy = 0 - Hook_FAILED Hook_DeletePolicy = 1 + Hook_SUCCEEDED Hook_DeletePolicy = 0 + Hook_FAILED Hook_DeletePolicy = 1 + Hook_BEFORE_HOOK_CREATION Hook_DeletePolicy = 2 ) var Hook_DeletePolicy_name = map[int32]string{ 0: "SUCCEEDED", 1: "FAILED", + 2: "BEFORE_HOOK_CREATION", } var Hook_DeletePolicy_value = map[string]int32{ - "SUCCEEDED": 0, - "FAILED": 1, + "SUCCEEDED": 0, + "FAILED": 1, + "BEFORE_HOOK_CREATION": 2, } func (x Hook_DeletePolicy) String() string { @@ -196,32 +202,34 @@ func init() { func init() { proto.RegisterFile("hapi/release/hook.proto", fileDescriptor0) } var fileDescriptor0 = []byte{ - // 428 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x91, 0xd1, 0x6e, 0xda, 0x30, - 0x14, 0x86, 0x9b, 0x12, 0x12, 0x38, 0x50, 0xea, 0x59, 0xd3, 0x66, 0x71, 0x53, 0xc4, 0x15, 0xbb, - 0x09, 0x53, 0xa7, 0x3d, 0x40, 0x4a, 0xce, 0xd6, 0xaa, 0x11, 0x20, 0x27, 0x68, 0xd2, 0x6e, 0xa2, - 0x74, 0xb8, 0x10, 0x11, 0xe2, 0x88, 0x98, 0x4d, 0x7b, 0xa6, 0xbd, 0xce, 0x1e, 0x68, 0xb2, 0x09, - 0x59, 0xa5, 0xed, 0xee, 0x9c, 0xef, 0x7c, 0x76, 0xce, 0x1f, 0xc3, 0xdb, 0x6d, 0x5a, 0x66, 0xd3, - 0x83, 0xc8, 0x45, 0x5a, 0x89, 0xe9, 0x56, 0xca, 0x9d, 0x57, 0x1e, 0xa4, 0x92, 0xb4, 0xaf, 0x07, - 0x5e, 0x3d, 0x18, 0xde, 0x6c, 0xa4, 0xdc, 0xe4, 0x62, 0x6a, 0x66, 0x4f, 0xc7, 0xe7, 0xa9, 0xca, - 0xf6, 0xa2, 0x52, 0xe9, 0xbe, 0x3c, 0xe9, 0xe3, 0x5f, 0x36, 0xd8, 0xf7, 0x52, 0xee, 0x28, 0x05, - 0xbb, 0x48, 0xf7, 0x82, 0x59, 0x23, 0x6b, 0xd2, 0xe5, 0xa6, 0xd6, 0x6c, 0x97, 0x15, 0x6b, 0x76, - 0x79, 0x62, 0xba, 0xd6, 0xac, 0x4c, 0xd5, 0x96, 0xb5, 0x4e, 0x4c, 0xd7, 0x74, 0x08, 0x9d, 0x7d, - 0x5a, 0x64, 0xcf, 0xa2, 0x52, 0xcc, 0x36, 0xbc, 0xe9, 0xe9, 0x7b, 0x70, 0xc4, 0x77, 0x51, 0xa8, - 0x8a, 0xb5, 0x47, 0xad, 0xc9, 0xe0, 0x96, 0x79, 0x2f, 0x17, 0xf4, 0xf4, 0xb7, 0x3d, 0xd4, 0x02, - 0xaf, 0x3d, 0xfa, 0x11, 0x3a, 0x79, 0x5a, 0xa9, 0xe4, 0x70, 0x2c, 0x98, 0x33, 0xb2, 0x26, 0xbd, - 0xdb, 0xa1, 0x77, 0x8a, 0xe1, 0x9d, 0x63, 0x78, 0xf1, 0x39, 0x06, 0x77, 0xb5, 0xcb, 0x8f, 0x05, - 0x7d, 0x03, 0xce, 0x0f, 0x91, 0x6d, 0xb6, 0x8a, 0xb9, 0x23, 0x6b, 0xd2, 0xe6, 0x75, 0x47, 0xef, - 0xe1, 0x7a, 0x2d, 0x72, 0xa1, 0x44, 0x52, 0xca, 0x3c, 0xfb, 0x96, 0x89, 0x8a, 0x75, 0xcc, 0x26, - 0x37, 0xff, 0xd9, 0x24, 0x30, 0xe6, 0x52, 0x8b, 0x3f, 0xf9, 0x60, 0xfd, 0xb7, 0xcb, 0x44, 0x35, - 0xfe, 0x6d, 0x41, 0xdb, 0xac, 0x4a, 0x7b, 0xe0, 0xae, 0xe6, 0x8f, 0xf3, 0xc5, 0x97, 0x39, 0xb9, - 0xa0, 0xd7, 0xd0, 0x5b, 0x72, 0x4c, 0x1e, 0xe6, 0x51, 0xec, 0x87, 0x21, 0xb1, 0x28, 0x81, 0xfe, - 0x72, 0x11, 0xc5, 0x0d, 0xb9, 0xa4, 0x03, 0x00, 0xad, 0x04, 0x18, 0x62, 0x8c, 0xa4, 0x65, 0x8e, - 0x68, 0xa3, 0x06, 0xf6, 0xf9, 0x8e, 0xd5, 0xf2, 0x33, 0xf7, 0x03, 0x24, 0xed, 0xe6, 0x8e, 0x33, - 0x71, 0x0c, 0xe1, 0x98, 0xf0, 0x45, 0x18, 0xde, 0xf9, 0xb3, 0x47, 0xe2, 0xd2, 0x57, 0x70, 0x65, - 0x9c, 0x06, 0x75, 0x28, 0x83, 0xd7, 0x1c, 0x43, 0xf4, 0x23, 0x4c, 0x62, 0x8c, 0xe2, 0x24, 0x5a, - 0xcd, 0x66, 0x18, 0x45, 0xa4, 0xfb, 0xcf, 0xe4, 0x93, 0xff, 0x10, 0xae, 0x38, 0x12, 0x18, 0xbf, - 0x83, 0xfe, 0xcb, 0xd8, 0xf4, 0x0a, 0xba, 0xe6, 0x18, 0x06, 0x18, 0x90, 0x0b, 0x0a, 0xe0, 0x68, - 0x17, 0x03, 0x62, 0xdd, 0x75, 0xbf, 0xba, 0xf5, 0xef, 0x7a, 0x72, 0xcc, 0x5b, 0x7c, 0xf8, 0x13, - 0x00, 0x00, 0xff, 0xff, 0xb9, 0x8a, 0xe1, 0xaf, 0x89, 0x02, 0x00, 0x00, + // 453 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x91, 0x51, 0x8f, 0x9a, 0x40, + 0x10, 0x80, 0x8f, 0x53, 0x41, 0x47, 0xcf, 0xdb, 0x6e, 0x9a, 0x76, 0xe3, 0xcb, 0x19, 0x9f, 0x7c, + 0xc2, 0xe6, 0x9a, 0xfe, 0x00, 0x84, 0xb9, 0x6a, 0x24, 0x60, 0x16, 0x4c, 0x93, 0xbe, 0x10, 0xae, + 0xee, 0x29, 0x11, 0x81, 0x08, 0xb6, 0xe9, 0x1f, 0xed, 0x3f, 0xe8, 0xff, 0x68, 0x76, 0x45, 0x7a, + 0x49, 0xfb, 0x36, 0xf3, 0xcd, 0xb7, 0xb3, 0x33, 0xbb, 0xf0, 0x7e, 0x1f, 0x17, 0xc9, 0xec, 0x24, + 0x52, 0x11, 0x97, 0x62, 0xb6, 0xcf, 0xf3, 0x83, 0x59, 0x9c, 0xf2, 0x2a, 0xa7, 0x03, 0x59, 0x30, + 0xeb, 0xc2, 0xe8, 0x61, 0x97, 0xe7, 0xbb, 0x54, 0xcc, 0x54, 0xed, 0xf9, 0xfc, 0x32, 0xab, 0x92, + 0xa3, 0x28, 0xab, 0xf8, 0x58, 0x5c, 0xf4, 0xc9, 0xaf, 0x36, 0xb4, 0x17, 0x79, 0x7e, 0xa0, 0x14, + 0xda, 0x59, 0x7c, 0x14, 0x4c, 0x1b, 0x6b, 0xd3, 0x1e, 0x57, 0xb1, 0x64, 0x87, 0x24, 0xdb, 0xb2, + 0xdb, 0x0b, 0x93, 0xb1, 0x64, 0x45, 0x5c, 0xed, 0x59, 0xeb, 0xc2, 0x64, 0x4c, 0x47, 0xd0, 0x3d, + 0xc6, 0x59, 0xf2, 0x22, 0xca, 0x8a, 0xb5, 0x15, 0x6f, 0x72, 0xfa, 0x01, 0x74, 0xf1, 0x5d, 0x64, + 0x55, 0xc9, 0x3a, 0xe3, 0xd6, 0x74, 0xf8, 0xc8, 0xcc, 0xd7, 0x03, 0x9a, 0xf2, 0x6e, 0x13, 0xa5, + 0xc0, 0x6b, 0x8f, 0x7e, 0x82, 0x6e, 0x1a, 0x97, 0x55, 0x74, 0x3a, 0x67, 0x4c, 0x1f, 0x6b, 0xd3, + 0xfe, 0xe3, 0xc8, 0xbc, 0xac, 0x61, 0x5e, 0xd7, 0x30, 0xc3, 0xeb, 0x1a, 0xdc, 0x90, 0x2e, 0x3f, + 0x67, 0xf4, 0x1d, 0xe8, 0x3f, 0x44, 0xb2, 0xdb, 0x57, 0xcc, 0x18, 0x6b, 0xd3, 0x0e, 0xaf, 0x33, + 0xba, 0x80, 0xfb, 0xad, 0x48, 0x45, 0x25, 0xa2, 0x22, 0x4f, 0x93, 0x6f, 0x89, 0x28, 0x59, 0x57, + 0x4d, 0xf2, 0xf0, 0x9f, 0x49, 0x1c, 0x65, 0xae, 0xa5, 0xf8, 0x93, 0x0f, 0xb7, 0x7f, 0xb3, 0x44, + 0x94, 0x93, 0xdf, 0x1a, 0x74, 0xd4, 0xa8, 0xb4, 0x0f, 0xc6, 0xc6, 0x5b, 0x79, 0xfe, 0x17, 0x8f, + 0xdc, 0xd0, 0x7b, 0xe8, 0xaf, 0x39, 0x46, 0x4b, 0x2f, 0x08, 0x2d, 0xd7, 0x25, 0x1a, 0x25, 0x30, + 0x58, 0xfb, 0x41, 0xd8, 0x90, 0x5b, 0x3a, 0x04, 0x90, 0x8a, 0x83, 0x2e, 0x86, 0x48, 0x5a, 0xea, + 0x88, 0x34, 0x6a, 0xd0, 0xbe, 0xf6, 0xd8, 0xac, 0x3f, 0x73, 0xcb, 0x41, 0xd2, 0x69, 0x7a, 0x5c, + 0x89, 0xae, 0x08, 0xc7, 0x88, 0xfb, 0xae, 0x3b, 0xb7, 0xec, 0x15, 0x31, 0xe8, 0x1b, 0xb8, 0x53, + 0x4e, 0x83, 0xba, 0x94, 0xc1, 0x5b, 0x8e, 0x2e, 0x5a, 0x01, 0x46, 0x21, 0x06, 0x61, 0x14, 0x6c, + 0x6c, 0x1b, 0x83, 0x80, 0xf4, 0xfe, 0xa9, 0x3c, 0x59, 0x4b, 0x77, 0xc3, 0x91, 0x80, 0xbc, 0xdb, + 0xe6, 0x4e, 0x33, 0x6d, 0x7f, 0x62, 0xc3, 0xe0, 0xf5, 0x3b, 0xd0, 0x3b, 0xe8, 0xa9, 0x3e, 0xe8, + 0xa0, 0x43, 0x6e, 0x28, 0x80, 0x2e, 0x0f, 0xa3, 0x43, 0x34, 0xd9, 0x75, 0x8e, 0x4f, 0x3e, 0xc7, + 0x68, 0xe1, 0xfb, 0xab, 0xc8, 0xe6, 0x68, 0x85, 0x4b, 0xdf, 0x23, 0xb7, 0xf3, 0xde, 0x57, 0xa3, + 0x7e, 0xd9, 0x67, 0x5d, 0x7d, 0xdb, 0xc7, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x3b, 0xcf, 0xed, + 0xd9, 0xb4, 0x02, 0x00, 0x00, } diff --git a/pkg/proto/hapi/services/tiller.pb.go b/pkg/proto/hapi/services/tiller.pb.go index 37535aac7..c0b9ab7d3 100644 --- a/pkg/proto/hapi/services/tiller.pb.go +++ b/pkg/proto/hapi/services/tiller.pb.go @@ -376,6 +376,8 @@ type UpdateReleaseRequest struct { ReuseValues bool `protobuf:"varint,10,opt,name=reuse_values,json=reuseValues" json:"reuse_values,omitempty"` // Force resource update through delete/recreate if needed. Force bool `protobuf:"varint,11,opt,name=force" json:"force,omitempty"` + // Description, if set, will set the description for the updated release + Description string `protobuf:"bytes,12,opt,name=description" json:"description,omitempty"` } func (m *UpdateReleaseRequest) Reset() { *m = UpdateReleaseRequest{} } @@ -460,6 +462,13 @@ func (m *UpdateReleaseRequest) GetForce() bool { return false } +func (m *UpdateReleaseRequest) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + // UpdateReleaseResponse is the response to an update request. type UpdateReleaseResponse struct { Release *hapi_release5.Release `protobuf:"bytes,1,opt,name=release" json:"release,omitempty"` @@ -495,6 +504,8 @@ type RollbackReleaseRequest struct { Wait bool `protobuf:"varint,7,opt,name=wait" json:"wait,omitempty"` // Force resource update through delete/recreate if needed. Force bool `protobuf:"varint,8,opt,name=force" json:"force,omitempty"` + // Description, if set, will set the description for the rollback + Description string `protobuf:"bytes,9,opt,name=description" json:"description,omitempty"` } func (m *RollbackReleaseRequest) Reset() { *m = RollbackReleaseRequest{} } @@ -558,6 +569,13 @@ func (m *RollbackReleaseRequest) GetForce() bool { return false } +func (m *RollbackReleaseRequest) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + // RollbackReleaseResponse is the response to an update request. type RollbackReleaseResponse struct { Release *hapi_release5.Release `protobuf:"bytes,1,opt,name=release" json:"release,omitempty"` @@ -599,7 +617,10 @@ type InstallReleaseRequest struct { Timeout int64 `protobuf:"varint,8,opt,name=timeout" json:"timeout,omitempty"` // wait, if true, will wait until all Pods, PVCs, and Services are in a ready state // before marking the release as successful. It will wait for as long as timeout - Wait bool `protobuf:"varint,9,opt,name=wait" json:"wait,omitempty"` + Wait bool `protobuf:"varint,9,opt,name=wait" json:"wait,omitempty"` + DisableCrdHook bool `protobuf:"varint,10,opt,name=disable_crd_hook,json=disableCrdHook" json:"disable_crd_hook,omitempty"` + // Description, if set, will set the description for the installed release + Description string `protobuf:"bytes,11,opt,name=description" json:"description,omitempty"` } func (m *InstallReleaseRequest) Reset() { *m = InstallReleaseRequest{} } @@ -670,6 +691,20 @@ func (m *InstallReleaseRequest) GetWait() bool { return false } +func (m *InstallReleaseRequest) GetDisableCrdHook() bool { + if m != nil { + return m.DisableCrdHook + } + return false +} + +func (m *InstallReleaseRequest) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + // InstallReleaseResponse is the response from a release installation. type InstallReleaseResponse struct { Release *hapi_release5.Release `protobuf:"bytes,1,opt,name=release" json:"release,omitempty"` @@ -697,6 +732,8 @@ 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 string `protobuf:"bytes,5,opt,name=description" json:"description,omitempty"` } func (m *UninstallReleaseRequest) Reset() { *m = UninstallReleaseRequest{} } @@ -732,6 +769,13 @@ func (m *UninstallReleaseRequest) GetTimeout() int64 { return 0 } +func (m *UninstallReleaseRequest) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + // UninstallReleaseResponse represents a successful response to an uninstall request. type UninstallReleaseResponse struct { // Release is the release that was marked deleted. @@ -1368,82 +1412,85 @@ var _ReleaseService_serviceDesc = grpc.ServiceDesc{ func init() { proto.RegisterFile("hapi/services/tiller.proto", fileDescriptor0) } var fileDescriptor0 = []byte{ - // 1217 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x57, 0xdd, 0x6e, 0xe3, 0xc4, - 0x17, 0xaf, 0xf3, 0x9d, 0x93, 0x36, 0xff, 0x74, 0x9a, 0xb6, 0xae, 0xff, 0x0b, 0x2a, 0x46, 0xb0, - 0xd9, 0x85, 0x4d, 0x21, 0x70, 0x83, 0x84, 0x90, 0xba, 0xdd, 0xa8, 0x2d, 0x94, 0xae, 0xe4, 0x6c, - 0x17, 0x09, 0x01, 0x91, 0x9b, 0x4c, 0x5a, 0xb3, 0x8e, 0x27, 0x78, 0xc6, 0x65, 0x7b, 0xcb, 0x1d, - 0x8f, 0xc2, 0x5b, 0xf0, 0x1e, 0x5c, 0xc2, 0x83, 0x20, 0xcf, 0x87, 0xeb, 0x49, 0xed, 0xd6, 0xf4, - 0x26, 0x9e, 0x99, 0xf3, 0xfd, 0x3b, 0x67, 0xce, 0x9c, 0x80, 0x75, 0xe9, 0x2e, 0xbc, 0x3d, 0x8a, - 0xc3, 0x2b, 0x6f, 0x82, 0xe9, 0x1e, 0xf3, 0x7c, 0x1f, 0x87, 0xfd, 0x45, 0x48, 0x18, 0x41, 0xdd, - 0x98, 0xd6, 0x57, 0xb4, 0xbe, 0xa0, 0x59, 0x5b, 0x5c, 0x62, 0x72, 0xe9, 0x86, 0x4c, 0xfc, 0x0a, - 0x6e, 0x6b, 0x3b, 0x7d, 0x4e, 0x82, 0x99, 0x77, 0x21, 0x09, 0xc2, 0x44, 0x88, 0x7d, 0xec, 0x52, - 0xac, 0xbe, 0x9a, 0x90, 0xa2, 0x79, 0xc1, 0x8c, 0x48, 0xc2, 0xff, 0x35, 0x02, 0xc3, 0x94, 0x8d, - 0xc3, 0x28, 0x90, 0xc4, 0x1d, 0x8d, 0x48, 0x99, 0xcb, 0x22, 0xaa, 0x19, 0xbb, 0xc2, 0x21, 0xf5, - 0x48, 0xa0, 0xbe, 0x82, 0x66, 0xff, 0x59, 0x82, 0x8d, 0x13, 0x8f, 0x32, 0x47, 0x08, 0x52, 0x07, - 0xff, 0x12, 0x61, 0xca, 0x50, 0x17, 0xaa, 0xbe, 0x37, 0xf7, 0x98, 0x69, 0xec, 0x1a, 0xbd, 0xb2, - 0x23, 0x36, 0x68, 0x0b, 0x6a, 0x64, 0x36, 0xa3, 0x98, 0x99, 0xa5, 0x5d, 0xa3, 0xd7, 0x74, 0xe4, - 0x0e, 0x7d, 0x05, 0x75, 0x4a, 0x42, 0x36, 0x3e, 0xbf, 0x36, 0xcb, 0xbb, 0x46, 0xaf, 0x3d, 0xf8, - 0xa0, 0x9f, 0x85, 0x53, 0x3f, 0xb6, 0x34, 0x22, 0x21, 0xeb, 0xc7, 0x3f, 0xcf, 0xaf, 0x9d, 0x1a, - 0xe5, 0xdf, 0x58, 0xef, 0xcc, 0xf3, 0x19, 0x0e, 0xcd, 0x8a, 0xd0, 0x2b, 0x76, 0xe8, 0x10, 0x80, - 0xeb, 0x25, 0xe1, 0x14, 0x87, 0x66, 0x95, 0xab, 0xee, 0x15, 0x50, 0xfd, 0x32, 0xe6, 0x77, 0x9a, - 0x54, 0x2d, 0xd1, 0x97, 0xb0, 0x2a, 0x20, 0x19, 0x4f, 0xc8, 0x14, 0x53, 0xb3, 0xb6, 0x5b, 0xee, - 0xb5, 0x07, 0x3b, 0x42, 0x95, 0x82, 0x7f, 0x24, 0x40, 0x3b, 0x20, 0x53, 0xec, 0xb4, 0x04, 0x7b, - 0xbc, 0xa6, 0xe8, 0x11, 0x34, 0x03, 0x77, 0x8e, 0xe9, 0xc2, 0x9d, 0x60, 0xb3, 0xce, 0x3d, 0xbc, - 0x39, 0xb0, 0x7f, 0x82, 0x86, 0x32, 0x6e, 0x0f, 0xa0, 0x26, 0x42, 0x43, 0x2d, 0xa8, 0x9f, 0x9d, - 0x7e, 0x73, 0xfa, 0xf2, 0xbb, 0xd3, 0xce, 0x0a, 0x6a, 0x40, 0xe5, 0x74, 0xff, 0xdb, 0x61, 0xc7, - 0x40, 0xeb, 0xb0, 0x76, 0xb2, 0x3f, 0x7a, 0x35, 0x76, 0x86, 0x27, 0xc3, 0xfd, 0xd1, 0xf0, 0x45, - 0xa7, 0x64, 0xbf, 0x0b, 0xcd, 0xc4, 0x67, 0x54, 0x87, 0xf2, 0xfe, 0xe8, 0x40, 0x88, 0xbc, 0x18, - 0x8e, 0x0e, 0x3a, 0x86, 0xfd, 0xbb, 0x01, 0x5d, 0x3d, 0x45, 0x74, 0x41, 0x02, 0x8a, 0xe3, 0x1c, - 0x4d, 0x48, 0x14, 0x24, 0x39, 0xe2, 0x1b, 0x84, 0xa0, 0x12, 0xe0, 0xb7, 0x2a, 0x43, 0x7c, 0x1d, - 0x73, 0x32, 0xc2, 0x5c, 0x9f, 0x67, 0xa7, 0xec, 0x88, 0x0d, 0xfa, 0x14, 0x1a, 0x32, 0x74, 0x6a, - 0x56, 0x76, 0xcb, 0xbd, 0xd6, 0x60, 0x53, 0x07, 0x44, 0x5a, 0x74, 0x12, 0x36, 0xfb, 0x10, 0xb6, - 0x0f, 0xb1, 0xf2, 0x44, 0xe0, 0xa5, 0x2a, 0x26, 0xb6, 0xeb, 0xce, 0x31, 0x77, 0x26, 0xb6, 0xeb, - 0xce, 0x31, 0x32, 0xa1, 0x2e, 0xcb, 0x8d, 0xbb, 0x53, 0x75, 0xd4, 0xd6, 0x66, 0x60, 0xde, 0x56, - 0x24, 0xe3, 0xca, 0xd2, 0xf4, 0x21, 0x54, 0xe2, 0x9b, 0xc0, 0xd5, 0xb4, 0x06, 0x48, 0xf7, 0xf3, - 0x38, 0x98, 0x11, 0x87, 0xd3, 0xf5, 0x54, 0x95, 0x97, 0x53, 0x75, 0x94, 0xb6, 0x7a, 0x40, 0x02, - 0x86, 0x03, 0xf6, 0x30, 0xff, 0x4f, 0x60, 0x27, 0x43, 0x93, 0x0c, 0x60, 0x0f, 0xea, 0xd2, 0x35, - 0xae, 0x2d, 0x17, 0x57, 0xc5, 0x65, 0xff, 0x5d, 0x82, 0xee, 0xd9, 0x62, 0xea, 0x32, 0xac, 0x48, - 0x77, 0x38, 0xf5, 0x18, 0xaa, 0xbc, 0xa3, 0x48, 0x2c, 0xd6, 0x85, 0x6e, 0xd1, 0x76, 0x0e, 0xe2, - 0x5f, 0x47, 0xd0, 0xd1, 0x53, 0xa8, 0x5d, 0xb9, 0x7e, 0x84, 0x29, 0x07, 0x22, 0x41, 0x4d, 0x72, - 0xf2, 0x76, 0xe4, 0x48, 0x0e, 0xb4, 0x0d, 0xf5, 0x69, 0x78, 0x1d, 0xf7, 0x13, 0x7e, 0x05, 0x1b, - 0x4e, 0x6d, 0x1a, 0x5e, 0x3b, 0x51, 0x80, 0xde, 0x87, 0xb5, 0xa9, 0x47, 0xdd, 0x73, 0x1f, 0x8f, - 0x2f, 0x09, 0x79, 0x43, 0xf9, 0x2d, 0x6c, 0x38, 0xab, 0xf2, 0xf0, 0x28, 0x3e, 0x43, 0x56, 0x5c, - 0x49, 0x93, 0x10, 0xbb, 0x0c, 0x9b, 0x35, 0x4e, 0x4f, 0xf6, 0x31, 0x86, 0xcc, 0x9b, 0x63, 0x12, - 0x31, 0x7e, 0x75, 0xca, 0x8e, 0xda, 0xa2, 0xf7, 0x60, 0x35, 0xc4, 0x14, 0xb3, 0xb1, 0xf4, 0xb2, - 0xc1, 0x25, 0x5b, 0xfc, 0xec, 0xb5, 0x70, 0x0b, 0x41, 0xe5, 0x57, 0xd7, 0x63, 0x66, 0x93, 0x93, - 0xf8, 0x5a, 0x88, 0x45, 0x14, 0x2b, 0x31, 0x50, 0x62, 0x11, 0xc5, 0x52, 0xac, 0x0b, 0xd5, 0x19, - 0x09, 0x27, 0xd8, 0x6c, 0x71, 0x9a, 0xd8, 0xd8, 0x47, 0xb0, 0xb9, 0x04, 0xf2, 0x43, 0xf3, 0xf5, - 0x8f, 0x01, 0x5b, 0x0e, 0xf1, 0xfd, 0x73, 0x77, 0xf2, 0xa6, 0x40, 0xc6, 0x52, 0xe0, 0x96, 0xee, - 0x06, 0xb7, 0x9c, 0x01, 0x6e, 0xaa, 0x08, 0x2b, 0x5a, 0x11, 0x6a, 0xb0, 0x57, 0xf3, 0x61, 0xaf, - 0xe9, 0xb0, 0x2b, 0x4c, 0xeb, 0x29, 0x4c, 0x13, 0xc0, 0x1a, 0x69, 0xc0, 0xbe, 0x86, 0xed, 0x5b, - 0x51, 0x3e, 0x14, 0xb2, 0x3f, 0x4a, 0xb0, 0x79, 0x1c, 0x50, 0xe6, 0xfa, 0xfe, 0x12, 0x62, 0x49, - 0x3d, 0x1b, 0x85, 0xeb, 0xb9, 0xf4, 0x5f, 0xea, 0xb9, 0xac, 0x41, 0xae, 0xf2, 0x53, 0x49, 0xe5, - 0xa7, 0x50, 0x8d, 0x6b, 0x9d, 0xa5, 0xb6, 0xd4, 0x59, 0xd0, 0x3b, 0x00, 0xa2, 0x28, 0xb9, 0x72, - 0x01, 0x6d, 0x93, 0x9f, 0x9c, 0xca, 0x46, 0xa2, 0xb2, 0xd1, 0xc8, 0xce, 0x46, 0xaa, 0xc2, 0xed, - 0x63, 0xd8, 0x5a, 0x86, 0xea, 0xa1, 0xb0, 0xff, 0x66, 0xc0, 0xf6, 0x59, 0xe0, 0x65, 0x02, 0x9f, - 0x55, 0xaa, 0xb7, 0xa0, 0x28, 0x65, 0x40, 0xd1, 0x85, 0xea, 0x22, 0x0a, 0x2f, 0xb0, 0x84, 0x56, - 0x6c, 0xd2, 0x31, 0x56, 0xb4, 0x18, 0xed, 0x31, 0x98, 0xb7, 0x7d, 0x78, 0x60, 0x44, 0xb1, 0xd7, - 0xc9, 0x4b, 0xd0, 0x14, 0x5d, 0xdf, 0xde, 0x80, 0xf5, 0x43, 0xcc, 0x5e, 0x8b, 0x6b, 0x21, 0xc3, - 0xb3, 0x87, 0x80, 0xd2, 0x87, 0x37, 0xf6, 0xe4, 0x91, 0x6e, 0x4f, 0x8d, 0x45, 0x8a, 0x5f, 0x71, - 0xd9, 0x5f, 0x70, 0xdd, 0x47, 0x1e, 0x65, 0x24, 0xbc, 0xbe, 0x0b, 0xba, 0x0e, 0x94, 0xe7, 0xee, - 0x5b, 0xf9, 0x50, 0xc4, 0x4b, 0xfb, 0x90, 0x7b, 0x90, 0x88, 0x4a, 0x0f, 0xd2, 0xcf, 0xae, 0x51, - 0xec, 0xd9, 0xfd, 0x01, 0xd0, 0x2b, 0x9c, 0x4c, 0x00, 0xf7, 0xbc, 0x58, 0x2a, 0x09, 0x25, 0xbd, - 0xd0, 0x4c, 0xa8, 0x4f, 0x7c, 0xec, 0x06, 0xd1, 0x42, 0xa6, 0x4d, 0x6d, 0xed, 0x1f, 0x61, 0x43, - 0xd3, 0x2e, 0xfd, 0x8c, 0xe3, 0xa1, 0x17, 0x52, 0x7b, 0xbc, 0x44, 0x9f, 0x43, 0x4d, 0x8c, 0x45, - 0x5c, 0x77, 0x7b, 0xf0, 0x48, 0xf7, 0x9b, 0x2b, 0x89, 0x02, 0x39, 0x47, 0x39, 0x92, 0x77, 0xf0, - 0x57, 0x03, 0xda, 0xea, 0xa1, 0x17, 0x43, 0x1b, 0xf2, 0x60, 0x35, 0x3d, 0xd1, 0xa0, 0x27, 0xf9, - 0x33, 0xdd, 0xd2, 0x60, 0x6a, 0x3d, 0x2d, 0xc2, 0x2a, 0x22, 0xb0, 0x57, 0x3e, 0x31, 0x10, 0x85, - 0xce, 0xf2, 0xa0, 0x81, 0x9e, 0x65, 0xeb, 0xc8, 0x99, 0x6c, 0xac, 0x7e, 0x51, 0x76, 0x65, 0x16, - 0x5d, 0xf1, 0x9a, 0xd1, 0xa7, 0x03, 0x74, 0xaf, 0x1a, 0x7d, 0x20, 0xb1, 0xf6, 0x0a, 0xf3, 0x27, - 0x76, 0x7f, 0x86, 0x35, 0xed, 0x85, 0x43, 0x39, 0x68, 0x65, 0xcd, 0x1a, 0xd6, 0x47, 0x85, 0x78, - 0x13, 0x5b, 0x73, 0x68, 0xeb, 0x4d, 0x0a, 0xe5, 0x28, 0xc8, 0xec, 0xfa, 0xd6, 0xc7, 0xc5, 0x98, - 0x13, 0x73, 0x14, 0x3a, 0xcb, 0x3d, 0x24, 0x2f, 0x8f, 0x39, 0xfd, 0x2e, 0x2f, 0x8f, 0x79, 0xad, - 0xc9, 0x5e, 0x41, 0x2e, 0xc0, 0x4d, 0x0b, 0x41, 0x8f, 0x73, 0x13, 0xa2, 0x77, 0x1e, 0xab, 0x77, - 0x3f, 0x63, 0x62, 0x62, 0x01, 0xff, 0x5b, 0x7a, 0x63, 0x51, 0x0e, 0x34, 0xd9, 0x03, 0x87, 0xf5, - 0xac, 0x20, 0xf7, 0x52, 0x50, 0xb2, 0x2b, 0xdd, 0x11, 0x94, 0xde, 0xf2, 0xee, 0x08, 0x6a, 0xa9, - 0xc1, 0xd9, 0x2b, 0xc8, 0x83, 0xb6, 0x13, 0x05, 0xd2, 0x74, 0xdc, 0x16, 0x50, 0x8e, 0xf4, 0xed, - 0xae, 0x66, 0x3d, 0x29, 0xc0, 0x79, 0x73, 0xbf, 0x9f, 0xc3, 0xf7, 0x0d, 0xc5, 0x7a, 0x5e, 0xe3, - 0xff, 0x69, 0x3f, 0xfb, 0x37, 0x00, 0x00, 0xff, 0xff, 0xf3, 0x7c, 0x9c, 0x49, 0xc1, 0x0f, 0x00, - 0x00, + // 1267 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x57, 0xed, 0x6e, 0xe3, 0x44, + 0x17, 0x6e, 0xe2, 0x7c, 0x9e, 0x74, 0xf3, 0x66, 0x67, 0xb3, 0xad, 0xeb, 0x77, 0x41, 0xc1, 0x08, + 0x36, 0xbb, 0xb0, 0x29, 0x04, 0xfe, 0x20, 0x21, 0xa4, 0x6e, 0x36, 0x6a, 0x0b, 0xa5, 0x2b, 0x39, + 0xdb, 0x45, 0x42, 0x40, 0xe4, 0x26, 0x93, 0xd6, 0xac, 0x63, 0x07, 0xcf, 0xb8, 0x6c, 0x2f, 0x00, + 0x24, 0xee, 0x83, 0x0b, 0xe1, 0x3e, 0xb8, 0x0e, 0xfe, 0x23, 0xcf, 0x87, 0xeb, 0x71, 0xec, 0xd4, + 0xf4, 0x4f, 0xe3, 0x99, 0x73, 0xe6, 0x7c, 0x3c, 0xcf, 0x9c, 0x33, 0xa7, 0x60, 0x5c, 0xda, 0x2b, + 0x67, 0x9f, 0xe0, 0xe0, 0xca, 0x99, 0x61, 0xb2, 0x4f, 0x1d, 0xd7, 0xc5, 0xc1, 0x60, 0x15, 0xf8, + 0xd4, 0x47, 0xdd, 0x48, 0x36, 0x90, 0xb2, 0x01, 0x97, 0x19, 0x3b, 0xec, 0xc4, 0xec, 0xd2, 0x0e, + 0x28, 0xff, 0xcb, 0xb5, 0x8d, 0xdd, 0xe4, 0xbe, 0xef, 0x2d, 0x9c, 0x0b, 0x21, 0xe0, 0x2e, 0x02, + 0xec, 0x62, 0x9b, 0x60, 0xf9, 0xab, 0x1c, 0x92, 0x32, 0xc7, 0x5b, 0xf8, 0x42, 0xf0, 0x7f, 0x45, + 0x40, 0x31, 0xa1, 0xd3, 0x20, 0xf4, 0x84, 0x70, 0x4f, 0x11, 0x12, 0x6a, 0xd3, 0x90, 0x28, 0xce, + 0xae, 0x70, 0x40, 0x1c, 0xdf, 0x93, 0xbf, 0x5c, 0x66, 0xfe, 0x55, 0x86, 0x07, 0x27, 0x0e, 0xa1, + 0x16, 0x3f, 0x48, 0x2c, 0xfc, 0x4b, 0x88, 0x09, 0x45, 0x5d, 0xa8, 0xba, 0xce, 0xd2, 0xa1, 0x7a, + 0xa9, 0x57, 0xea, 0x6b, 0x16, 0x5f, 0xa0, 0x1d, 0xa8, 0xf9, 0x8b, 0x05, 0xc1, 0x54, 0x2f, 0xf7, + 0x4a, 0xfd, 0xa6, 0x25, 0x56, 0xe8, 0x2b, 0xa8, 0x13, 0x3f, 0xa0, 0xd3, 0xf3, 0x6b, 0x5d, 0xeb, + 0x95, 0xfa, 0xed, 0xe1, 0x07, 0x83, 0x2c, 0x9c, 0x06, 0x91, 0xa7, 0x89, 0x1f, 0xd0, 0x41, 0xf4, + 0xe7, 0xf9, 0xb5, 0x55, 0x23, 0xec, 0x37, 0xb2, 0xbb, 0x70, 0x5c, 0x8a, 0x03, 0xbd, 0xc2, 0xed, + 0xf2, 0x15, 0x3a, 0x04, 0x60, 0x76, 0xfd, 0x60, 0x8e, 0x03, 0xbd, 0xca, 0x4c, 0xf7, 0x0b, 0x98, + 0x7e, 0x19, 0xe9, 0x5b, 0x4d, 0x22, 0x3f, 0xd1, 0x97, 0xb0, 0xcd, 0x21, 0x99, 0xce, 0xfc, 0x39, + 0x26, 0x7a, 0xad, 0xa7, 0xf5, 0xdb, 0xc3, 0x3d, 0x6e, 0x4a, 0xc2, 0x3f, 0xe1, 0xa0, 0x8d, 0xfc, + 0x39, 0xb6, 0x5a, 0x5c, 0x3d, 0xfa, 0x26, 0xe8, 0x11, 0x34, 0x3d, 0x7b, 0x89, 0xc9, 0xca, 0x9e, + 0x61, 0xbd, 0xce, 0x22, 0xbc, 0xd9, 0x30, 0x7f, 0x82, 0x86, 0x74, 0x6e, 0x0e, 0xa1, 0xc6, 0x53, + 0x43, 0x2d, 0xa8, 0x9f, 0x9d, 0x7e, 0x73, 0xfa, 0xf2, 0xbb, 0xd3, 0xce, 0x16, 0x6a, 0x40, 0xe5, + 0xf4, 0xe0, 0xdb, 0x71, 0xa7, 0x84, 0xee, 0xc3, 0xbd, 0x93, 0x83, 0xc9, 0xab, 0xa9, 0x35, 0x3e, + 0x19, 0x1f, 0x4c, 0xc6, 0x2f, 0x3a, 0x65, 0xf3, 0x5d, 0x68, 0xc6, 0x31, 0xa3, 0x3a, 0x68, 0x07, + 0x93, 0x11, 0x3f, 0xf2, 0x62, 0x3c, 0x19, 0x75, 0x4a, 0xe6, 0x1f, 0x25, 0xe8, 0xaa, 0x14, 0x91, + 0x95, 0xef, 0x11, 0x1c, 0x71, 0x34, 0xf3, 0x43, 0x2f, 0xe6, 0x88, 0x2d, 0x10, 0x82, 0x8a, 0x87, + 0xdf, 0x4a, 0x86, 0xd8, 0x77, 0xa4, 0x49, 0x7d, 0x6a, 0xbb, 0x8c, 0x1d, 0xcd, 0xe2, 0x0b, 0xf4, + 0x29, 0x34, 0x44, 0xea, 0x44, 0xaf, 0xf4, 0xb4, 0x7e, 0x6b, 0xf8, 0x50, 0x05, 0x44, 0x78, 0xb4, + 0x62, 0x35, 0xf3, 0x10, 0x76, 0x0f, 0xb1, 0x8c, 0x84, 0xe3, 0x25, 0x6f, 0x4c, 0xe4, 0xd7, 0x5e, + 0x62, 0x16, 0x4c, 0xe4, 0xd7, 0x5e, 0x62, 0xa4, 0x43, 0x5d, 0x5c, 0x37, 0x16, 0x4e, 0xd5, 0x92, + 0x4b, 0x93, 0x82, 0xbe, 0x6e, 0x48, 0xe4, 0x95, 0x65, 0xe9, 0x43, 0xa8, 0x44, 0x95, 0xc0, 0xcc, + 0xb4, 0x86, 0x48, 0x8d, 0xf3, 0xd8, 0x5b, 0xf8, 0x16, 0x93, 0xab, 0x54, 0x69, 0x69, 0xaa, 0x8e, + 0x92, 0x5e, 0x47, 0xbe, 0x47, 0xb1, 0x47, 0xef, 0x16, 0xff, 0x09, 0xec, 0x65, 0x58, 0x12, 0x09, + 0xec, 0x43, 0x5d, 0x84, 0xc6, 0xac, 0xe5, 0xe2, 0x2a, 0xb5, 0xcc, 0xdf, 0x34, 0xe8, 0x9e, 0xad, + 0xe6, 0x36, 0xc5, 0x52, 0xb4, 0x21, 0xa8, 0xc7, 0x50, 0x65, 0x1d, 0x45, 0x60, 0x71, 0x9f, 0xdb, + 0xe6, 0x6d, 0x67, 0x14, 0xfd, 0xb5, 0xb8, 0x1c, 0x3d, 0x85, 0xda, 0x95, 0xed, 0x86, 0x98, 0x30, + 0x20, 0x62, 0xd4, 0x84, 0x26, 0x6b, 0x47, 0x96, 0xd0, 0x40, 0xbb, 0x50, 0x9f, 0x07, 0xd7, 0x51, + 0x3f, 0x61, 0x25, 0xd8, 0xb0, 0x6a, 0xf3, 0xe0, 0xda, 0x0a, 0x3d, 0xf4, 0x3e, 0xdc, 0x9b, 0x3b, + 0xc4, 0x3e, 0x77, 0xf1, 0xf4, 0xd2, 0xf7, 0xdf, 0x10, 0x56, 0x85, 0x0d, 0x6b, 0x5b, 0x6c, 0x1e, + 0x45, 0x7b, 0xc8, 0x88, 0x6e, 0xd2, 0x2c, 0xc0, 0x36, 0xc5, 0x7a, 0x8d, 0xc9, 0xe3, 0x75, 0x84, + 0x21, 0x75, 0x96, 0xd8, 0x0f, 0x29, 0x2b, 0x1d, 0xcd, 0x92, 0x4b, 0xf4, 0x1e, 0x6c, 0x07, 0x98, + 0x60, 0x3a, 0x15, 0x51, 0x36, 0xd8, 0xc9, 0x16, 0xdb, 0x7b, 0xcd, 0xc3, 0x42, 0x50, 0xf9, 0xd5, + 0x76, 0xa8, 0xde, 0x64, 0x22, 0xf6, 0xcd, 0x8f, 0x85, 0x04, 0xcb, 0x63, 0x20, 0x8f, 0x85, 0x04, + 0x8b, 0x63, 0x5d, 0xa8, 0x2e, 0xfc, 0x60, 0x86, 0xf5, 0x16, 0x93, 0xf1, 0x05, 0xea, 0x41, 0x6b, + 0x8e, 0xc9, 0x2c, 0x70, 0x56, 0x34, 0x62, 0x74, 0x9b, 0x61, 0x9a, 0xdc, 0x32, 0x8f, 0xe0, 0x61, + 0x8a, 0x86, 0xbb, 0x32, 0xfa, 0x7b, 0x19, 0x76, 0x2c, 0xdf, 0x75, 0xcf, 0xed, 0xd9, 0x9b, 0x02, + 0x9c, 0x26, 0xe0, 0x2f, 0x6f, 0x86, 0x5f, 0xcb, 0x80, 0x3f, 0x71, 0x4d, 0x2b, 0xca, 0x35, 0x55, + 0x88, 0xa9, 0xe6, 0x13, 0x53, 0x53, 0x89, 0x91, 0xa8, 0xd7, 0x13, 0xa8, 0xc7, 0x90, 0x36, 0x36, + 0x40, 0xda, 0x5c, 0x87, 0xf4, 0x6b, 0xd8, 0x5d, 0xc3, 0xe1, 0xae, 0xa0, 0xfe, 0x53, 0x86, 0x87, + 0xc7, 0x1e, 0xa1, 0xb6, 0xeb, 0xa6, 0x30, 0x8d, 0x6b, 0xa2, 0x54, 0xb8, 0x26, 0xca, 0xff, 0xa5, + 0x26, 0x34, 0x85, 0x14, 0xc9, 0x60, 0x25, 0xc1, 0x60, 0xa1, 0x3a, 0x51, 0xba, 0x53, 0x2d, 0xd5, + 0x9d, 0xd0, 0x3b, 0x00, 0xfc, 0x62, 0x33, 0xe3, 0x1c, 0xfc, 0x26, 0xdb, 0x39, 0x15, 0xcd, 0x48, + 0xf2, 0xd5, 0xc8, 0xe6, 0x2b, 0x59, 0x25, 0x7d, 0xe8, 0xc8, 0x78, 0x66, 0xc1, 0x9c, 0xc5, 0x24, + 0x2a, 0xa5, 0x2d, 0xf6, 0x47, 0xc1, 0x3c, 0x8a, 0x2a, 0xcd, 0x61, 0x6b, 0x9d, 0xc3, 0x63, 0xd8, + 0x49, 0xc3, 0x7e, 0x57, 0x0a, 0xff, 0x2c, 0xc1, 0xee, 0x99, 0xe7, 0x64, 0x92, 0x98, 0x55, 0x18, + 0x6b, 0xb0, 0x96, 0x33, 0x60, 0xed, 0x42, 0x75, 0x15, 0x06, 0x17, 0x58, 0xd0, 0xc4, 0x17, 0x49, + 0xbc, 0x2a, 0x2a, 0x5e, 0xa9, 0x8c, 0xab, 0xeb, 0x19, 0x4f, 0x41, 0x5f, 0x8f, 0xf2, 0x8e, 0x39, + 0x47, 0x79, 0xc5, 0x6f, 0x57, 0x93, 0xbf, 0x53, 0xe6, 0x03, 0xb8, 0x7f, 0x88, 0xe9, 0x6b, 0x5e, + 0xa6, 0x02, 0x00, 0x73, 0x0c, 0x28, 0xb9, 0x79, 0xe3, 0x4f, 0x6c, 0xa9, 0xfe, 0xe4, 0x20, 0x27, + 0xf5, 0xa5, 0x96, 0xf9, 0x05, 0xb3, 0x7d, 0xe4, 0x10, 0xea, 0x07, 0xd7, 0x9b, 0xc0, 0xed, 0x80, + 0xb6, 0xb4, 0xdf, 0x8a, 0xa7, 0x2d, 0xfa, 0x34, 0x0f, 0x59, 0x04, 0xf1, 0x51, 0x11, 0x41, 0x72, + 0x50, 0x28, 0x15, 0x1b, 0x14, 0x7e, 0x00, 0xf4, 0x0a, 0xc7, 0x33, 0xcb, 0x2d, 0x6f, 0xac, 0xa4, + 0xa9, 0xac, 0xd2, 0xa4, 0x43, 0x7d, 0xe6, 0x62, 0xdb, 0x0b, 0x57, 0x82, 0x58, 0xb9, 0x34, 0x7f, + 0x84, 0x07, 0x8a, 0x75, 0x11, 0x67, 0x94, 0x0f, 0xb9, 0x10, 0xd6, 0xa3, 0x4f, 0xf4, 0x39, 0xd4, + 0xf8, 0x20, 0xc7, 0x6c, 0xb7, 0x87, 0x8f, 0xd4, 0xb8, 0x99, 0x91, 0xd0, 0x13, 0x93, 0x9f, 0x25, + 0x74, 0x87, 0x7f, 0x37, 0xa0, 0x2d, 0x47, 0x13, 0x3e, 0x66, 0x22, 0x07, 0xb6, 0x93, 0x33, 0x18, + 0x7a, 0x92, 0x3f, 0x85, 0xa6, 0x46, 0x69, 0xe3, 0x69, 0x11, 0x55, 0x9e, 0x81, 0xb9, 0xf5, 0x49, + 0x09, 0x11, 0xe8, 0xa4, 0x47, 0x23, 0xf4, 0x2c, 0xdb, 0x46, 0xce, 0x2c, 0x66, 0x0c, 0x8a, 0xaa, + 0x4b, 0xb7, 0xe8, 0x8a, 0xdd, 0x19, 0x75, 0x9e, 0x41, 0xb7, 0x9a, 0x51, 0x47, 0x28, 0x63, 0xbf, + 0xb0, 0x7e, 0xec, 0xf7, 0x67, 0xb8, 0xa7, 0xbc, 0xb8, 0x28, 0x07, 0xad, 0xac, 0xe9, 0xc8, 0xf8, + 0xa8, 0x90, 0x6e, 0xec, 0x6b, 0x09, 0x6d, 0xb5, 0x8d, 0xa1, 0x1c, 0x03, 0x99, 0x6f, 0x8c, 0xf1, + 0x71, 0x31, 0xe5, 0xd8, 0x1d, 0x81, 0x4e, 0xba, 0x87, 0xe4, 0xf1, 0x98, 0xd3, 0x11, 0xf3, 0x78, + 0xcc, 0x6b, 0x4d, 0xe6, 0x16, 0xb2, 0x01, 0x6e, 0x5a, 0x08, 0x7a, 0x9c, 0x4b, 0x88, 0xda, 0x79, + 0x8c, 0xfe, 0xed, 0x8a, 0xb1, 0x8b, 0x15, 0xfc, 0x2f, 0xf5, 0xa2, 0xa3, 0x1c, 0x68, 0xb2, 0x07, + 0x20, 0xe3, 0x59, 0x41, 0xed, 0x54, 0x52, 0xa2, 0x2b, 0x6d, 0x48, 0x4a, 0x6d, 0x79, 0x1b, 0x92, + 0x4a, 0x35, 0x38, 0x73, 0x0b, 0x39, 0xd0, 0xb6, 0x42, 0x4f, 0xb8, 0x8e, 0xda, 0x02, 0xca, 0x39, + 0xbd, 0xde, 0xd5, 0x8c, 0x27, 0x05, 0x34, 0x6f, 0xea, 0xfb, 0x39, 0x7c, 0xdf, 0x90, 0xaa, 0xe7, + 0x35, 0xf6, 0x5f, 0xf8, 0x67, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0x9d, 0x73, 0x4f, 0x4d, 0x73, + 0x10, 0x00, 0x00, } diff --git a/pkg/provenance/doc.go b/pkg/provenance/doc.go index dacfa9e69..bee484944 100644 --- a/pkg/provenance/doc.go +++ b/pkg/provenance/doc.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/provenance/sign.go b/pkg/provenance/sign.go index ecd6612a3..5e23c2dda 100644 --- a/pkg/provenance/sign.go +++ b/pkg/provenance/sign.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/provenance/sign_test.go b/pkg/provenance/sign_test.go index 388941deb..d74e23887 100644 --- a/pkg/provenance/sign_test.go +++ b/pkg/provenance/sign_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/releasetesting/environment.go b/pkg/releasetesting/environment.go index 3b3d07933..17a22c21d 100644 --- a/pkg/releasetesting/environment.go +++ b/pkg/releasetesting/environment.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/releasetesting/environment_test.go b/pkg/releasetesting/environment_test.go index 0199b74eb..4403ab6a9 100644 --- a/pkg/releasetesting/environment_test.go +++ b/pkg/releasetesting/environment_test.go @@ -1,5 +1,5 @@ /* -Copyright 2017 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/releasetesting/test_suite.go b/pkg/releasetesting/test_suite.go index 2e42400ce..79f00301e 100644 --- a/pkg/releasetesting/test_suite.go +++ b/pkg/releasetesting/test_suite.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/releasetesting/test_suite_test.go b/pkg/releasetesting/test_suite_test.go index e6cc8bcf5..828b14e99 100644 --- a/pkg/releasetesting/test_suite_test.go +++ b/pkg/releasetesting/test_suite_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -134,7 +134,7 @@ func TestRun(t *testing.T) { } if result2.Status != release.TestRun_FAILURE { - t.Errorf("Expected test result to be successful, got: %v", result2.Status) + t.Errorf("Expected test result to be failure, got: %v", result2.Status) } } diff --git a/pkg/releaseutil/filter.go b/pkg/releaseutil/filter.go index fdd2cc381..458da705f 100644 --- a/pkg/releaseutil/filter.go +++ b/pkg/releaseutil/filter.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/releaseutil/filter_test.go b/pkg/releaseutil/filter_test.go index 590952363..802b1db7a 100644 --- a/pkg/releaseutil/filter_test.go +++ b/pkg/releaseutil/filter_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/releaseutil/manifest.go b/pkg/releaseutil/manifest.go index a0449cc55..78c2979c4 100644 --- a/pkg/releaseutil/manifest.go +++ b/pkg/releaseutil/manifest.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/releaseutil/manifest_test.go b/pkg/releaseutil/manifest_test.go index 7906279ad..8e0793d5f 100644 --- a/pkg/releaseutil/manifest_test.go +++ b/pkg/releaseutil/manifest_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/releaseutil/sorter.go b/pkg/releaseutil/sorter.go index 1b744d72c..1a13298b0 100644 --- a/pkg/releaseutil/sorter.go +++ b/pkg/releaseutil/sorter.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/releaseutil/sorter_test.go b/pkg/releaseutil/sorter_test.go index 7d4e31e2e..a3323bd96 100644 --- a/pkg/releaseutil/sorter_test.go +++ b/pkg/releaseutil/sorter_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/repo/chartrepo.go b/pkg/repo/chartrepo.go index c76cc7913..cd9d6c547 100644 --- a/pkg/repo/chartrepo.go +++ b/pkg/repo/chartrepo.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -119,12 +119,9 @@ func (r *ChartRepository) DownloadIndexFile(cachePath string) error { parsedURL.Path = strings.TrimSuffix(parsedURL.Path, "/") + "/index.yaml" indexURL = parsedURL.String() - g, err := getter.NewHTTPGetter(indexURL, r.Config.CertFile, r.Config.KeyFile, r.Config.CAFile) - if err != nil { - return err - } - g.SetCredentials(r.Config.Username, r.Config.Password) - resp, err := g.Get(indexURL) + + r.setCredentials() + resp, err := r.Client.Get(indexURL) if err != nil { return err } @@ -152,6 +149,13 @@ func (r *ChartRepository) DownloadIndexFile(cachePath string) error { return ioutil.WriteFile(cp, index, 0644) } +// If HttpGetter is used, this method sets the configured repository credentials on the HttpGetter. +func (r *ChartRepository) setCredentials() { + if t, ok := r.Client.(*getter.HttpGetter); ok { + t.SetCredentials(r.Config.Username, r.Config.Password) + } +} + // Index generates an index for the chart repository and writes an index.yaml file. func (r *ChartRepository) Index() error { err := r.generateIndex() @@ -196,9 +200,9 @@ func FindChartInRepoURL(repoURL, chartName, chartVersion, certFile, keyFile, caF return FindChartInAuthRepoURL(repoURL, "", "", chartName, chartVersion, certFile, keyFile, caFile, getters) } -// FindChartInRepoURL finds chart in chart repository pointed by repoURL -// without adding repo to repositories. -// Unlike the FindChartInRepoURL function, this function also receives credentials for the chart repository. +// FindChartInAuthRepoURL finds chart in chart repository pointed by repoURL +// without adding repo to repositories, like FindChartInRepoURL, +// but it also receives credentials for the chart repository. func FindChartInAuthRepoURL(repoURL, username, password, chartName, chartVersion, certFile, keyFile, caFile string, getters getter.Providers) (string, error) { // Download and write the index file to a temporary location @@ -266,5 +270,13 @@ func ResolveReferenceURL(baseURL, refURL string) (string, error) { return "", fmt.Errorf("failed to parse %s as URL: %v", refURL, err) } - return parsedBaseURL.ResolveReference(parsedRefURL).String(), nil + // if the base URL contains query string parameters, + // propagate them to the child URL but only if the + // refURL is relative to baseURL + resolvedURL := parsedBaseURL.ResolveReference(parsedRefURL) + if (resolvedURL.Hostname() == parsedBaseURL.Hostname()) && (resolvedURL.Port() == parsedBaseURL.Port()) { + resolvedURL.RawQuery = parsedBaseURL.RawQuery + } + + return resolvedURL.String(), nil } diff --git a/pkg/repo/chartrepo_test.go b/pkg/repo/chartrepo_test.go index 948ee12d3..19071872d 100644 --- a/pkg/repo/chartrepo_test.go +++ b/pkg/repo/chartrepo_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -287,6 +287,14 @@ func TestResolveReferenceURL(t *testing.T) { t.Errorf("%s", chartURL) } + chartURL, err = ResolveReferenceURL("http://localhost:8123/charts/?st=2018-08-06T22%3A59%3A04Z&se=2018-08-07T22%3A59%3A04Z&sp=rl&sv=2018-03-28&sr=c&sig=cyqM4%2F5G7HNk%2F3faaHSDMaWxFxefCglvZlYSnmQBwiY%3D", "nginx-0.2.0.tgz") + if err != nil { + t.Errorf("%s", err) + } + if chartURL != "http://localhost:8123/charts/nginx-0.2.0.tgz?st=2018-08-06T22%3A59%3A04Z&se=2018-08-07T22%3A59%3A04Z&sp=rl&sv=2018-03-28&sr=c&sig=cyqM4%2F5G7HNk%2F3faaHSDMaWxFxefCglvZlYSnmQBwiY%3D" { + t.Errorf("%s does not contain the query string of the base URL", chartURL) + } + chartURL, err = ResolveReferenceURL("http://localhost:8123", "https://kubernetes-charts.storage.googleapis.com/nginx-0.2.0.tgz") if err != nil { t.Errorf("%s", err) @@ -294,4 +302,12 @@ func TestResolveReferenceURL(t *testing.T) { if chartURL != "https://kubernetes-charts.storage.googleapis.com/nginx-0.2.0.tgz" { t.Errorf("%s", chartURL) } + + chartURL, err = ResolveReferenceURL("http://localhost:8123/?querystring", "https://kubernetes-charts.storage.googleapis.com/nginx-0.2.0.tgz") + if err != nil { + t.Errorf("%s", err) + } + if chartURL != "https://kubernetes-charts.storage.googleapis.com/nginx-0.2.0.tgz" { + t.Errorf("%s contains query string from base URL when it shouldn't", chartURL) + } } diff --git a/pkg/repo/doc.go b/pkg/repo/doc.go index fb8b3f4b2..19ccf267c 100644 --- a/pkg/repo/doc.go +++ b/pkg/repo/doc.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/repo/index.go b/pkg/repo/index.go index 174ceea01..01bf4a8ca 100644 --- a/pkg/repo/index.go +++ b/pkg/repo/index.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/repo/index_test.go b/pkg/repo/index_test.go index ba426b174..2ce817ce3 100644 --- a/pkg/repo/index_test.go +++ b/pkg/repo/index_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/repo/local.go b/pkg/repo/local.go index f13a4d0ac..caca1b9c2 100644 --- a/pkg/repo/local.go +++ b/pkg/repo/local.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/repo/local_test.go b/pkg/repo/local_test.go index 1e5359dee..cf6cf2d11 100644 --- a/pkg/repo/local_test.go +++ b/pkg/repo/local_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/repo/repo.go b/pkg/repo/repo.go index 194eace79..fa550357a 100644 --- a/pkg/repo/repo.go +++ b/pkg/repo/repo.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -31,7 +31,8 @@ import ( var ErrRepoOutOfDate = errors.New("repository file is out of date") // RepoFile represents the repositories.yaml file in $HELM_HOME -type RepoFile struct { +// TODO: change type name to File in Helm 3 to resolve linter warning +type RepoFile struct { // nolint APIVersion string `json:"apiVersion"` Generated time.Time `json:"generated"` Repositories []*Entry `json:"repositories"` diff --git a/pkg/repo/repo_test.go b/pkg/repo/repo_test.go index 4b5bcdbf5..264e9bc3c 100644 --- a/pkg/repo/repo_test.go +++ b/pkg/repo/repo_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/repo/repotest/doc.go b/pkg/repo/repotest/doc.go index 34d4bc6b0..3bf98aa7e 100644 --- a/pkg/repo/repotest/doc.go +++ b/pkg/repo/repotest/doc.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/repo/repotest/server.go b/pkg/repo/repotest/server.go index 8ea9103a0..36ab10d70 100644 --- a/pkg/repo/repotest/server.go +++ b/pkg/repo/repotest/server.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/repo/repotest/server_test.go b/pkg/repo/repotest/server_test.go index 61c056172..e4819fbf7 100644 --- a/pkg/repo/repotest/server_test.go +++ b/pkg/repo/repotest/server_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/resolver/resolver.go b/pkg/resolver/resolver.go index ec8ea2cce..8177df2d3 100644 --- a/pkg/resolver/resolver.go +++ b/pkg/resolver/resolver.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/resolver/resolver_test.go b/pkg/resolver/resolver_test.go index 78a0bc46c..689ffbc32 100644 --- a/pkg/resolver/resolver_test.go +++ b/pkg/resolver/resolver_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/rudder/client.go b/pkg/rudder/client.go index 219bb010a..093a0c360 100644 --- a/pkg/rudder/client.go +++ b/pkg/rudder/client.go @@ -1,5 +1,5 @@ /* -Copyright 2017 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/storage/driver/cfgmaps.go b/pkg/storage/driver/cfgmaps.go index 51fa8f8f6..3f5ee204a 100644 --- a/pkg/storage/driver/cfgmaps.go +++ b/pkg/storage/driver/cfgmaps.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/storage/driver/cfgmaps_test.go b/pkg/storage/driver/cfgmaps_test.go index 7501ad9cb..c028e9fdf 100644 --- a/pkg/storage/driver/cfgmaps_test.go +++ b/pkg/storage/driver/cfgmaps_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/storage/driver/driver.go b/pkg/storage/driver/driver.go index e01d35d64..d8c4122b5 100644 --- a/pkg/storage/driver/driver.go +++ b/pkg/storage/driver/driver.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/storage/driver/labels.go b/pkg/storage/driver/labels.go index 8668d665b..eb7118fe5 100644 --- a/pkg/storage/driver/labels.go +++ b/pkg/storage/driver/labels.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/storage/driver/labels_test.go b/pkg/storage/driver/labels_test.go index af0bd24e5..e8d7fc90c 100644 --- a/pkg/storage/driver/labels_test.go +++ b/pkg/storage/driver/labels_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/storage/driver/memory.go b/pkg/storage/driver/memory.go index ceb0d67dd..ea3faf26b 100644 --- a/pkg/storage/driver/memory.go +++ b/pkg/storage/driver/memory.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/storage/driver/memory_test.go b/pkg/storage/driver/memory_test.go index 1062071e7..4f45cf72b 100644 --- a/pkg/storage/driver/memory_test.go +++ b/pkg/storage/driver/memory_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/storage/driver/mock_test.go b/pkg/storage/driver/mock_test.go index 979d11cb6..1ebe7f650 100644 --- a/pkg/storage/driver/mock_test.go +++ b/pkg/storage/driver/mock_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/storage/driver/records.go b/pkg/storage/driver/records.go index ce72308a8..bc793d8b3 100644 --- a/pkg/storage/driver/records.go +++ b/pkg/storage/driver/records.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/storage/driver/records_test.go b/pkg/storage/driver/records_test.go index 79380afb8..8063ab9dc 100644 --- a/pkg/storage/driver/records_test.go +++ b/pkg/storage/driver/records_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/storage/driver/secrets.go b/pkg/storage/driver/secrets.go index e8f3984f6..1b8064e53 100644 --- a/pkg/storage/driver/secrets.go +++ b/pkg/storage/driver/secrets.go @@ -1,5 +1,5 @@ /* -Copyright 2017 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/storage/driver/secrets_test.go b/pkg/storage/driver/secrets_test.go index e6f62e702..6c9c63ad4 100644 --- a/pkg/storage/driver/secrets_test.go +++ b/pkg/storage/driver/secrets_test.go @@ -1,5 +1,5 @@ /* -Copyright 2017 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/storage/driver/util.go b/pkg/storage/driver/util.go index 65fb17e7c..7807382b6 100644 --- a/pkg/storage/driver/util.go +++ b/pkg/storage/driver/util.go @@ -1,5 +1,5 @@ /* -Copyright 2017 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/storage/storage.go b/pkg/storage/storage.go index 4b39e0bb2..40fc558a1 100644 --- a/pkg/storage/storage.go +++ b/pkg/storage/storage.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -163,7 +163,7 @@ func (s *Storage) History(name string) ([]*rspb.Release, error) { return s.Driver.Query(map[string]string{"NAME": name, "OWNER": "TILLER"}) } -// removeLeastRecent removes items from history until the lengh number of releases +// removeLeastRecent removes items from history until the length number of releases // does not exceed max. // // We allow max to be set explicitly so that calling functions can "make space" diff --git a/pkg/storage/storage_test.go b/pkg/storage/storage_test.go index fb2824de7..19d786ad9 100644 --- a/pkg/storage/storage_test.go +++ b/pkg/storage/storage_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/strvals/doc.go b/pkg/strvals/doc.go index d2b859e67..f17290587 100644 --- a/pkg/strvals/doc.go +++ b/pkg/strvals/doc.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/strvals/parser.go b/pkg/strvals/parser.go index 8a999feb7..532a8c4ac 100644 --- a/pkg/strvals/parser.go +++ b/pkg/strvals/parser.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 @@ -50,7 +50,21 @@ func Parse(s string) (map[string]interface{}, error) { return vals, err } -// Parse parses a set line and forces a string value. +// ParseFile parses a set line, but its final value is loaded from the file at the path specified by the original value. +// +// A set line is of the form name1=path1,name2=path2 +// +// When the files at path1 and path2 contained "val1" and "val2" respectively, the set line is consumed as +// name1=val1,name2=val2 +func ParseFile(s string, runesToVal runesToVal) (map[string]interface{}, error) { + vals := map[string]interface{}{} + scanner := bytes.NewBufferString(s) + t := newFileParser(scanner, vals, runesToVal) + err := t.parse() + return vals, err +} + +// ParseString parses a set line and forces a string value. // // A set line is of the form name1=value1,name2=value2 func ParseString(s string) (map[string]interface{}, error) { @@ -71,7 +85,16 @@ func ParseInto(s string, dest map[string]interface{}) error { return t.parse() } -// ParseIntoString parses a strvals line nad merges the result into dest. +// ParseIntoFile parses a filevals line and merges the result into dest. +// +// This method always returns a string as the value. +func ParseIntoFile(s string, dest map[string]interface{}, runesToVal runesToVal) error { + scanner := bytes.NewBufferString(s) + t := newFileParser(scanner, dest, runesToVal) + return t.parse() +} + +// ParseIntoString parses a strvals line and merges the result into dest. // // This method always returns a string as the value. func ParseIntoString(s string, dest map[string]interface{}) error { @@ -82,14 +105,27 @@ func ParseIntoString(s string, dest map[string]interface{}) error { // parser is a simple parser that takes a strvals line and parses it into a // map representation. +// +// where sc is the source of the original data being parsed +// where data is the final parsed data from the parses with correct types +// where st is a boolean to figure out if we're forcing it to parse values as string type parser struct { - sc *bytes.Buffer - data map[string]interface{} - st bool + sc *bytes.Buffer + data map[string]interface{} + runesToVal runesToVal } +type runesToVal func([]rune) (interface{}, error) + func newParser(sc *bytes.Buffer, data map[string]interface{}, stringBool bool) *parser { - return &parser{sc: sc, data: data, st: stringBool} + rs2v := func(rs []rune) (interface{}, error) { + return typedVal(rs, stringBool), nil + } + return &parser{sc: sc, data: data, runesToVal: rs2v} +} + +func newFileParser(sc *bytes.Buffer, data map[string]interface{}, runesToVal runesToVal) *parser { + return &parser{sc: sc, data: data, runesToVal: runesToVal} } func (t *parser) parse() error { @@ -153,8 +189,12 @@ func (t *parser) key(data map[string]interface{}) error { set(data, string(k), "") return e case ErrNotList: - v, e := t.val() - set(data, string(k), typedVal(v, t.st)) + rs, e := t.val() + if e != nil && e != io.EOF { + return e + } + v, e := t.runesToVal(rs) + set(data, string(k), v) return e default: return e @@ -226,8 +266,12 @@ func (t *parser) listItem(list []interface{}, i int) ([]interface{}, error) { case io.EOF: return setIndex(list, i, ""), err case ErrNotList: - v, e := t.val() - return setIndex(list, i, typedVal(v, t.st)), e + rs, e := t.val() + if e != nil && e != io.EOF { + return list, e + } + v, e := t.runesToVal(rs) + return setIndex(list, i, v), e default: return list, e } @@ -275,7 +319,7 @@ func (t *parser) valList() ([]interface{}, error) { list := []interface{}{} stop := runeSet([]rune{',', '}'}) for { - switch v, last, err := runesUntil(t.sc, stop); { + switch rs, last, err := runesUntil(t.sc, stop); { case err != nil: if err == io.EOF { err = errors.New("list must terminate with '}'") @@ -286,10 +330,15 @@ func (t *parser) valList() ([]interface{}, error) { if r, _, e := t.sc.ReadRune(); e == nil && r != ',' { t.sc.UnreadRune() } - list = append(list, typedVal(v, t.st)) - return list, nil + v, e := t.runesToVal(rs) + list = append(list, v) + return list, e case last == ',': - list = append(list, typedVal(v, t.st)) + v, e := t.runesToVal(rs) + if e != nil { + return list, e + } + list = append(list, v) } } } @@ -321,6 +370,11 @@ func inMap(k rune, m map[rune]bool) bool { func typedVal(v []rune, st bool) interface{} { val := string(v) + + if st { + return val + } + if strings.EqualFold(val, "true") { return true } @@ -329,8 +383,12 @@ func typedVal(v []rune, st bool) interface{} { return false } - // If this value does not start with zero, and not returnString, try parsing it to an int - if !st && len(val) != 0 && val[0] != '0' { + if strings.EqualFold(val, "null") { + return nil + } + + // If this value does not start with zero, try parsing it to an int + if len(val) != 0 && val[0] != '0' { if iv, err := strconv.ParseInt(val, 10, 64); err == nil { return iv } diff --git a/pkg/strvals/parser_test.go b/pkg/strvals/parser_test.go index 3f9828498..e5d878149 100644 --- a/pkg/strvals/parser_test.go +++ b/pkg/strvals/parser_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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 @@ -75,12 +75,27 @@ func TestParseSet(t *testing.T) { expect: map[string]interface{}{"long_int_string": "1234567890"}, err: false, }, + { + str: "boolean=true", + expect: map[string]interface{}{"boolean": "true"}, + err: false, + }, + { + str: "is_null=null", + expect: map[string]interface{}{"is_null": "null"}, + err: false, + }, } tests := []struct { str string expect map[string]interface{} err bool }{ + { + "name1=null,f=false,t=true", + map[string]interface{}{"name1": nil, "f": false, "t": true}, + false, + }, { "name1=value1", map[string]interface{}{"name1": "value1"}, @@ -112,6 +127,15 @@ func TestParseSet(t *testing.T) { str: "long_int=1234567890", expect: map[string]interface{}{"long_int": 1234567890}, }, + { + str: "boolean=true", + expect: map[string]interface{}{"boolean": true}, + }, + { + str: "is_null=null", + expect: map[string]interface{}{"is_null": nil}, + err: false, + }, { str: "name1,name2=", err: true, @@ -331,12 +355,13 @@ func TestParseInto(t *testing.T) { "inner2": "value2", }, } - input := "outer.inner1=value1,outer.inner3=value3" + input := "outer.inner1=value1,outer.inner3=value3,outer.inner4=4" expect := map[string]interface{}{ "outer": map[string]interface{}{ "inner1": "value1", "inner2": "value2", "inner3": "value3", + "inner4": 4, }, } @@ -357,6 +382,72 @@ func TestParseInto(t *testing.T) { t.Errorf("%s: Expected:\n%s\nGot:\n%s", input, y1, y2) } } +func TestParseIntoString(t *testing.T) { + got := map[string]interface{}{ + "outer": map[string]interface{}{ + "inner1": "overwrite", + "inner2": "value2", + }, + } + input := "outer.inner1=1,outer.inner3=3" + expect := map[string]interface{}{ + "outer": map[string]interface{}{ + "inner1": "1", + "inner2": "value2", + "inner3": "3", + }, + } + + if err := ParseIntoString(input, got); err != nil { + t.Fatal(err) + } + + y1, err := yaml.Marshal(expect) + if err != nil { + t.Fatal(err) + } + y2, err := yaml.Marshal(got) + if err != nil { + t.Fatalf("Error serializing parsed value: %s", err) + } + + if string(y1) != string(y2) { + t.Errorf("%s: Expected:\n%s\nGot:\n%s", input, y1, y2) + } +} + +func TestParseIntoFile(t *testing.T) { + got := map[string]interface{}{} + input := "name1=path1" + expect := map[string]interface{}{ + "name1": "value1", + } + rs2v := func(rs []rune) (interface{}, error) { + v := string(rs) + if v != "path1" { + t.Errorf("%s: runesToVal: Expected value path1, got %s", input, v) + return "", nil + } + return "value1", nil + } + + if err := ParseIntoFile(input, got, rs2v); err != nil { + t.Fatal(err) + } + + y1, err := yaml.Marshal(expect) + if err != nil { + t.Fatal(err) + } + y2, err := yaml.Marshal(got) + if err != nil { + t.Fatalf("Error serializing parsed value: %s", err) + } + + if string(y1) != string(y2) { + t.Errorf("%s: Expected:\n%s\nGot:\n%s", input, y1, y2) + } +} func TestToYAML(t *testing.T) { // The TestParse does the hard part. We just verify that YAML formatting is diff --git a/pkg/sympath/walk.go b/pkg/sympath/walk.go index 77fa04153..b2500284a 100644 --- a/pkg/sympath/walk.go +++ b/pkg/sympath/walk.go @@ -4,7 +4,7 @@ the BSD license. https://github.com/golang/go/blob/master/LICENSE -Copyright 2017 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/sympath/walk_test.go b/pkg/sympath/walk_test.go index d86d8dabd..ab8e0eb4c 100644 --- a/pkg/sympath/walk_test.go +++ b/pkg/sympath/walk_test.go @@ -4,7 +4,7 @@ the BSD license. https://github.com/golang/go/blob/master/LICENSE -Copyright 2017 The Kubernetes Authors All rights reserved. +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 diff --git a/pkg/tiller/environment/environment.go b/pkg/tiller/environment/environment.go index 366fdf522..c9ddab3ab 100644 --- a/pkg/tiller/environment/environment.go +++ b/pkg/tiller/environment/environment.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -27,7 +27,7 @@ import ( "time" "k8s.io/kubernetes/pkg/apis/core" - "k8s.io/kubernetes/pkg/kubectl/resource" + "k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource" "k8s.io/helm/pkg/chartutil" "k8s.io/helm/pkg/engine" @@ -98,8 +98,6 @@ type Engine interface { type KubeClient interface { // Create creates one or more resources. // - // namespace must contain a valid existing namespace. - // // reader must contain a YAML stream (one or more YAML documents separated // by "\n---\n"). Create(namespace string, reader io.Reader, timeout int64, shouldWait bool) error diff --git a/pkg/tiller/environment/environment_test.go b/pkg/tiller/environment/environment_test.go index d8c82b901..b835a976d 100644 --- a/pkg/tiller/environment/environment_test.go +++ b/pkg/tiller/environment/environment_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -23,7 +23,7 @@ import ( "time" "k8s.io/kubernetes/pkg/apis/core" - "k8s.io/kubernetes/pkg/kubectl/resource" + "k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource" "k8s.io/helm/pkg/chartutil" "k8s.io/helm/pkg/kube" diff --git a/pkg/tiller/hook_sorter.go b/pkg/tiller/hook_sorter.go index 42d546620..11fa61533 100644 --- a/pkg/tiller/hook_sorter.go +++ b/pkg/tiller/hook_sorter.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/tiller/hook_sorter_test.go b/pkg/tiller/hook_sorter_test.go index ac5b9bf8d..efe960ca4 100644 --- a/pkg/tiller/hook_sorter_test.go +++ b/pkg/tiller/hook_sorter_test.go @@ -1,5 +1,5 @@ /* -Copyright 2017 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/tiller/hooks.go b/pkg/tiller/hooks.go index 6ac2cc636..d53ed504f 100644 --- a/pkg/tiller/hooks.go +++ b/pkg/tiller/hooks.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -42,12 +42,14 @@ var events = map[string]release.Hook_Event{ hooks.PostRollback: release.Hook_POST_ROLLBACK, hooks.ReleaseTestSuccess: release.Hook_RELEASE_TEST_SUCCESS, hooks.ReleaseTestFailure: release.Hook_RELEASE_TEST_FAILURE, + hooks.CRDInstall: release.Hook_CRD_INSTALL, } // deletePolices represents a mapping between the key in the annotation for label deleting policy and its real meaning var deletePolices = map[string]release.Hook_DeletePolicy{ - hooks.HookSucceeded: release.Hook_SUCCEEDED, - hooks.HookFailed: release.Hook_FAILED, + hooks.HookSucceeded: release.Hook_SUCCEEDED, + hooks.HookFailed: release.Hook_FAILED, + hooks.BeforeHookCreation: release.Hook_BEFORE_HOOK_CREATION, } // Manifest represents a manifest file, which has a name and some content. @@ -136,10 +138,6 @@ func (file *manifestFile) sort(result *result) error { return e } - if entry.Version != "" && !file.apis.Has(entry.Version) { - return fmt.Errorf("apiVersion %q in %s is not available", entry.Version, file.path) - } - if !hasAnyAnnotation(entry) { result.generic = append(result.generic, Manifest{ Name: file.path, @@ -189,23 +187,15 @@ func (file *manifestFile) sort(result *result) error { result.hooks = append(result.hooks, h) - isKnownDeletePolices := false - dps, ok := entry.Metadata.Annotations[hooks.HookDeleteAnno] - if ok { - for _, dp := range strings.Split(dps, ",") { - dp = strings.ToLower(strings.TrimSpace(dp)) - p, exist := deletePolices[dp] - if exist { - isKnownDeletePolices = true - h.DeletePolicies = append(h.DeletePolicies, p) - } - } - if !isKnownDeletePolices { - log.Printf("info: skipping unknown hook delete policy: %q", dps) + operateAnnotationValues(entry, hooks.HookDeleteAnno, func(value string) { + policy, exist := deletePolices[value] + if exist { + h.DeletePolicies = append(h.DeletePolicies, policy) + } else { + log.Printf("info: skipping unknown hook delete policy: %q", value) } - } + }) } - return nil } @@ -228,3 +218,12 @@ func calculateHookWeight(entry util.SimpleHead) int32 { return int32(hw) } + +func operateAnnotationValues(entry util.SimpleHead, annotation string, operate func(p string)) { + if dps, ok := entry.Metadata.Annotations[annotation]; ok { + for _, dp := range strings.Split(dps, ",") { + dp = strings.ToLower(strings.TrimSpace(dp)) + operate(dp) + } + } +} diff --git a/pkg/tiller/hooks_test.go b/pkg/tiller/hooks_test.go index 658f859f4..8bd928500 100644 --- a/pkg/tiller/hooks_test.go +++ b/pkg/tiller/hooks_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/tiller/kind_sorter.go b/pkg/tiller/kind_sorter.go index f367e65c8..65e3f478d 100644 --- a/pkg/tiller/kind_sorter.go +++ b/pkg/tiller/kind_sorter.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -30,6 +30,7 @@ var InstallOrder SortOrder = []string{ "Namespace", "ResourceQuota", "LimitRange", + "PodSecurityPolicy", "Secret", "ConfigMap", "StorageClass", @@ -80,6 +81,7 @@ var UninstallOrder SortOrder = []string{ "StorageClass", "ConfigMap", "Secret", + "PodSecurityPolicy", "LimitRange", "ResourceQuota", "Namespace", diff --git a/pkg/tiller/kind_sorter_test.go b/pkg/tiller/kind_sorter_test.go index ef7296e89..fb3e8ad57 100644 --- a/pkg/tiller/kind_sorter_test.go +++ b/pkg/tiller/kind_sorter_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -85,6 +85,10 @@ func TestKindSorter(t *testing.T) { Name: "o", Head: &util.SimpleHead{Kind: "Pod"}, }, + { + Name: "3", + Head: &util.SimpleHead{Kind: "PodSecurityPolicy"}, + }, { Name: "q", Head: &util.SimpleHead{Kind: "ReplicaSet"}, @@ -136,8 +140,8 @@ func TestKindSorter(t *testing.T) { order SortOrder expected string }{ - {"install", InstallOrder, "abcde1fgh2ijklmnopqrstuvw!"}, - {"uninstall", UninstallOrder, "wvmutsrqponlkji2hgf1edcba!"}, + {"install", InstallOrder, "abc3de1fgh2ijklmnopqrstuvw!"}, + {"uninstall", UninstallOrder, "wvmutsrqponlkji2hgf1ed3cba!"}, } { var buf bytes.Buffer t.Run(test.description, func(t *testing.T) { diff --git a/pkg/tiller/release_content.go b/pkg/tiller/release_content.go index fd783d6b6..2315f1aaa 100644 --- a/pkg/tiller/release_content.go +++ b/pkg/tiller/release_content.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/tiller/release_content_test.go b/pkg/tiller/release_content_test.go index 7c003f709..4a29c5d3e 100644 --- a/pkg/tiller/release_content_test.go +++ b/pkg/tiller/release_content_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/tiller/release_history.go b/pkg/tiller/release_history.go index 0dd525978..fe7ad1395 100644 --- a/pkg/tiller/release_history.go +++ b/pkg/tiller/release_history.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/tiller/release_history_test.go b/pkg/tiller/release_history_test.go index 5df98410f..58b7fad9a 100644 --- a/pkg/tiller/release_history_test.go +++ b/pkg/tiller/release_history_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/tiller/release_install.go b/pkg/tiller/release_install.go index 8e7fd3acd..973da3581 100644 --- a/pkg/tiller/release_install.go +++ b/pkg/tiller/release_install.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -127,20 +127,59 @@ func (s *ReleaseServer) prepareRelease(req *services.InstallReleaseRequest) (*re rel.Info.Status.Notes = notesTxt } - err = validateManifest(s.env.KubeClient, req.Namespace, manifestDoc.Bytes()) - return rel, err + return rel, nil +} + +func hasCRDHook(hs []*release.Hook) bool { + for _, h := range hs { + for _, e := range h.Events { + if e == events[hooks.CRDInstall] { + return true + } + } + } + return false } // performRelease runs a release. func (s *ReleaseServer) performRelease(r *release.Release, req *services.InstallReleaseRequest) (*services.InstallReleaseResponse, error) { res := &services.InstallReleaseResponse{Release: r} + manifestDoc := []byte(r.Manifest) if req.DryRun { s.Log("dry run for %s", r.Name) + + if !req.DisableCrdHook && hasCRDHook(r.Hooks) { + s.Log("validation skipped because CRD hook is present") + res.Release.Info.Description = "Validation skipped because CRDs are not installed" + return res, nil + } + + // Here's the problem with dry runs and CRDs: We can't install a CRD + // during a dry run, which means it cannot be validated. + if err := validateManifest(s.env.KubeClient, req.Namespace, manifestDoc); err != nil { + return res, err + } + res.Release.Info.Description = "Dry run complete" return res, nil } + // crd-install hooks + if !req.DisableHooks && !req.DisableCrdHook { + if err := s.execHook(r.Hooks, r.Name, r.Namespace, hooks.CRDInstall, req.Timeout); err != nil { + fmt.Printf("Finished installing CRD: %s", err) + return res, err + } + } else { + s.Log("CRD install hooks disabled for %s", req.Name) + } + + // Because the CRDs are installed, they are used for validation during this step. + if err := validateManifest(s.env.KubeClient, req.Namespace, manifestDoc); err != nil { + return res, fmt.Errorf("validation failed: %s", err) + } + // pre-install hooks if !req.DisableHooks { if err := s.execHook(r.Hooks, r.Name, r.Namespace, hooks.PreInstall, req.Timeout); err != nil { @@ -211,7 +250,11 @@ func (s *ReleaseServer) performRelease(r *release.Release, req *services.Install } r.Info.Status.Code = release.Status_DEPLOYED - r.Info.Description = "Install complete" + if req.Description == "" { + r.Info.Description = "Install complete" + } else { + r.Info.Description = req.Description + } // This is a tricky case. The release has been created, but the result // cannot be recorded. The truest thing to tell the user is that the // release was created. However, the user will not be able to do anything diff --git a/pkg/tiller/release_install_test.go b/pkg/tiller/release_install_test.go index 793a36e94..f5e84d870 100644 --- a/pkg/tiller/release_install_test.go +++ b/pkg/tiller/release_install_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -28,21 +28,43 @@ import ( "k8s.io/helm/pkg/version" ) +func TestHasCRDHook(t *testing.T) { + tests := []struct { + hooks []*release.Hook + expect bool + }{ + { + hooks: []*release.Hook{ + {Events: []release.Hook_Event{release.Hook_PRE_DELETE}}, + }, + expect: false, + }, + { + hooks: []*release.Hook{ + {Events: []release.Hook_Event{release.Hook_CRD_INSTALL}}, + }, + expect: true, + }, + { + hooks: []*release.Hook{ + {Events: []release.Hook_Event{release.Hook_PRE_UPGRADE, release.Hook_CRD_INSTALL}}, + }, + expect: true, + }, + } + + for i, tt := range tests { + if tt.expect != hasCRDHook(tt.hooks) { + t.Errorf("test %d: expected %t, got %t", i, tt.expect, !tt.expect) + } + } +} + func TestInstallRelease(t *testing.T) { c := helm.NewContext() rs := rsFixture() - // TODO: Refactor this into a mock. - req := &services.InstallReleaseRequest{ - Namespace: "spaced", - Chart: &chart.Chart{ - Metadata: &chart.Metadata{Name: "hello"}, - Templates: []*chart.Template{ - {Name: "templates/hello", Data: []byte("hello: world")}, - {Name: "templates/hooks", Data: []byte(manifestWithHook)}, - }, - }, - } + req := installRequest() res, err := rs.InstallRelease(c, req) if err != nil { t.Fatalf("Failed install: %s", err) @@ -96,18 +118,9 @@ func TestInstallRelease_WithNotes(t *testing.T) { c := helm.NewContext() rs := rsFixture() - // TODO: Refactor this into a mock. - req := &services.InstallReleaseRequest{ - Namespace: "spaced", - Chart: &chart.Chart{ - Metadata: &chart.Metadata{Name: "hello"}, - Templates: []*chart.Template{ - {Name: "templates/hello", Data: []byte("hello: world")}, - {Name: "templates/hooks", Data: []byte(manifestWithHook)}, - {Name: "templates/NOTES.txt", Data: []byte(notesText)}, - }, - }, - } + req := installRequest( + withChart(withNotes(notesText)), + ) res, err := rs.InstallRelease(c, req) if err != nil { t.Fatalf("Failed install: %s", err) @@ -165,18 +178,9 @@ func TestInstallRelease_WithNotesRendered(t *testing.T) { c := helm.NewContext() rs := rsFixture() - // TODO: Refactor this into a mock. - req := &services.InstallReleaseRequest{ - Namespace: "spaced", - Chart: &chart.Chart{ - Metadata: &chart.Metadata{Name: "hello"}, - Templates: []*chart.Template{ - {Name: "templates/hello", Data: []byte("hello: world")}, - {Name: "templates/hooks", Data: []byte(manifestWithHook)}, - {Name: "templates/NOTES.txt", Data: []byte(notesText + " {{.Release.Name}}")}, - }, - }, - } + req := installRequest( + withChart(withNotes(notesText + " {{.Release.Name}}")), + ) res, err := rs.InstallRelease(c, req) if err != nil { t.Fatalf("Failed install: %s", err) @@ -236,17 +240,9 @@ func TestInstallRelease_TillerVersion(t *testing.T) { c := helm.NewContext() rs := rsFixture() - // TODO: Refactor this into a mock. - req := &services.InstallReleaseRequest{ - Namespace: "spaced", - Chart: &chart.Chart{ - Metadata: &chart.Metadata{Name: "hello", TillerVersion: ">=2.2.0"}, - Templates: []*chart.Template{ - {Name: "templates/hello", Data: []byte("hello: world")}, - {Name: "templates/hooks", Data: []byte(manifestWithHook)}, - }, - }, - } + req := installRequest( + withChart(withTiller(">=2.2.0")), + ) _, err := rs.InstallRelease(c, req) if err != nil { t.Fatalf("Expected valid range. Got %q", err) @@ -258,17 +254,9 @@ func TestInstallRelease_WrongTillerVersion(t *testing.T) { c := helm.NewContext() rs := rsFixture() - // TODO: Refactor this into a mock. - req := &services.InstallReleaseRequest{ - Namespace: "spaced", - Chart: &chart.Chart{ - Metadata: &chart.Metadata{Name: "hello", TillerVersion: "<2.0.0"}, - Templates: []*chart.Template{ - {Name: "templates/hello", Data: []byte("hello: world")}, - {Name: "templates/hooks", Data: []byte(manifestWithHook)}, - }, - }, - } + req := installRequest( + withChart(withTiller("<2.0.0")), + ) _, err := rs.InstallRelease(c, req) if err == nil { t.Fatalf("Expected to fail because of wrong version") @@ -284,29 +272,10 @@ func TestInstallRelease_WithChartAndDependencyNotes(t *testing.T) { c := helm.NewContext() rs := rsFixture() - // TODO: Refactor this into a mock. - req := &services.InstallReleaseRequest{ - Namespace: "spaced", - Chart: &chart.Chart{ - Metadata: &chart.Metadata{Name: "hello"}, - Templates: []*chart.Template{ - {Name: "templates/hello", Data: []byte("hello: world")}, - {Name: "templates/hooks", Data: []byte(manifestWithHook)}, - {Name: "templates/NOTES.txt", Data: []byte(notesText)}, - }, - Dependencies: []*chart.Chart{ - { - Metadata: &chart.Metadata{Name: "hello"}, - Templates: []*chart.Template{ - {Name: "templates/hello", Data: []byte("hello: world")}, - {Name: "templates/hooks", Data: []byte(manifestWithHook)}, - {Name: "templates/NOTES.txt", Data: []byte(notesText + " child")}, - }, - }, - }, - }, - } - + req := installRequest(withChart( + withNotes(notesText), + withDependency(withNotes(notesText+" child")), + )) res, err := rs.InstallRelease(c, req) if err != nil { t.Fatalf("Failed install: %s", err) @@ -335,10 +304,9 @@ func TestInstallRelease_DryRun(t *testing.T) { c := helm.NewContext() rs := rsFixture() - req := &services.InstallReleaseRequest{ - Chart: chartStub(), - DryRun: true, - } + req := installRequest(withDryRun(), + withChart(withSampleTemplates()), + ) res, err := rs.InstallRelease(c, req) if err != nil { t.Errorf("Failed install: %s", err) @@ -389,10 +357,7 @@ func TestInstallRelease_NoHooks(t *testing.T) { rs := rsFixture() rs.env.Releases.Create(releaseStub()) - req := &services.InstallReleaseRequest{ - Chart: chartStub(), - DisableHooks: true, - } + req := installRequest(withDisabledHooks()) res, err := rs.InstallRelease(c, req) if err != nil { t.Errorf("Failed install: %s", err) @@ -403,15 +368,62 @@ func TestInstallRelease_NoHooks(t *testing.T) { } } +func TestInstallRelease_CRDInstallHook(t *testing.T) { + c := helm.NewContext() + rs := rsFixture() + rs.env.Releases.Create(releaseStub()) + + req := installRequest() + req.Chart.Templates = append(req.Chart.Templates, &chart.Template{ + Name: "templates/crdhook", + Data: []byte(manifestWithCRDHook), + }) + + res, err := rs.InstallRelease(c, req) + if err != nil { + t.Errorf("Failed install: %s", err) + } + + // The new hook should have been pulled from the manifest. + if l := len(res.Release.Hooks); l != 2 { + t.Fatalf("expected 2 hooks, got %d", l) + } + + expect := "Install complete" + if got := res.Release.Info.Description; got != expect { + t.Errorf("Expected Description to be %q, got %q", expect, got) + } +} + +func TestInstallRelease_DryRunCRDInstallHook(t *testing.T) { + c := helm.NewContext() + rs := rsFixture() + rs.env.Releases.Create(releaseStub()) + + req := installRequest(withDryRun()) + req.Chart.Templates = append(req.Chart.Templates, &chart.Template{ + Name: "templates/crdhook", + Data: []byte(manifestWithCRDHook), + }) + + res, err := rs.InstallRelease(c, req) + if err != nil { + t.Errorf("Failed install: %s", err) + } + + expect := "Validation skipped because CRDs are not installed" + if res.Release.Info.Description != expect { + t.Errorf("Expected Description %q, got %q", expect, res.Release.Info.Description) + } +} + func TestInstallRelease_FailedHooks(t *testing.T) { c := helm.NewContext() rs := rsFixture() rs.env.Releases.Create(releaseStub()) rs.env.KubeClient = newHookFailingKubeClient() - req := &services.InstallReleaseRequest{ - Chart: chartStub(), - } + req := installRequest() res, err := rs.InstallRelease(c, req) if err == nil { t.Error("Expected failed install") @@ -429,11 +441,10 @@ func TestInstallRelease_ReuseName(t *testing.T) { rel.Info.Status.Code = release.Status_DELETED rs.env.Releases.Create(rel) - req := &services.InstallReleaseRequest{ - Chart: chartStub(), - ReuseName: true, - Name: rel.Name, - } + req := installRequest( + withReuseName(), + withName(rel.Name), + ) res, err := rs.InstallRelease(c, req) if err != nil { t.Fatalf("Failed install: %s", err) @@ -457,18 +468,10 @@ func TestInstallRelease_KubeVersion(t *testing.T) { c := helm.NewContext() rs := rsFixture() - // TODO: Refactor this into a mock. - req := &services.InstallReleaseRequest{ - Chart: &chart.Chart{ - Metadata: &chart.Metadata{Name: "hello", KubeVersion: ">=0.0.0"}, - Templates: []*chart.Template{ - {Name: "templates/hello", Data: []byte("hello: world")}, - {Name: "templates/hooks", Data: []byte(manifestWithHook)}, - }, - }, - } + req := installRequest( + withChart(withKube(">=0.0.0")), + ) _, err := rs.InstallRelease(c, req) - fmt.Println(err) if err != nil { t.Fatalf("Expected valid range. Got %q", err) } @@ -478,16 +481,10 @@ func TestInstallRelease_WrongKubeVersion(t *testing.T) { c := helm.NewContext() rs := rsFixture() - // TODO: Refactor this into a mock. - req := &services.InstallReleaseRequest{ - Chart: &chart.Chart{ - Metadata: &chart.Metadata{Name: "hello", KubeVersion: ">=5.0.0"}, - Templates: []*chart.Template{ - {Name: "templates/hello", Data: []byte("hello: world")}, - {Name: "templates/hooks", Data: []byte(manifestWithHook)}, - }, - }, - } + req := installRequest( + withChart(withKube(">=5.0.0")), + ) + _, err := rs.InstallRelease(c, req) if err == nil { t.Fatalf("Expected to fail because of wrong version") @@ -498,3 +495,23 @@ func TestInstallRelease_WrongKubeVersion(t *testing.T) { t.Errorf("Expected %q to contain %q", err.Error(), expect) } } + +func TestInstallRelease_Description(t *testing.T) { + c := helm.NewContext() + rs := rsFixture() + rs.env.Releases.Create(releaseStub()) + + customDescription := "foo" + req := &services.InstallReleaseRequest{ + Chart: chartStub(), + Description: customDescription, + } + res, err := rs.InstallRelease(c, req) + if err != nil { + t.Errorf("Failed install: %s", err) + } + + if desc := res.Release.Info.Description; desc != customDescription { + t.Errorf("Expected description %q. Got %q", customDescription, desc) + } +} diff --git a/pkg/tiller/release_list.go b/pkg/tiller/release_list.go index 9ccc8a686..3344888dc 100644 --- a/pkg/tiller/release_list.go +++ b/pkg/tiller/release_list.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -18,11 +18,11 @@ package tiller import ( "fmt" - "regexp" - + "github.com/golang/protobuf/proto" "k8s.io/helm/pkg/proto/hapi/release" "k8s.io/helm/pkg/proto/hapi/services" relutil "k8s.io/helm/pkg/releaseutil" + "regexp" ) // ListReleases lists the releases found by the server. @@ -107,14 +107,50 @@ func (s *ReleaseServer) ListReleases(req *services.ListReleasesRequest, stream s rels = rels[0:req.Limit] l = int64(len(rels)) } - res := &services.ListReleasesResponse{ - Next: next, - Count: l, - Total: total, - Releases: rels, + Next: next, + Count: l, + Total: total, } - return stream.Send(res) + chunks := s.partition(rels[:min(len(rels), int(req.Limit))], maxMsgSize-proto.Size(res)) + for res.Releases = range chunks { + if err := stream.Send(res); err != nil { + for range chunks { // drain + } + return err + } + } + return nil +} + +// partition packs releases into slices upto the capacity cap in bytes. +func (s *ReleaseServer) partition(rels []*release.Release, cap int) <-chan []*release.Release { + chunks := make(chan []*release.Release, 1) + go func() { + var ( + fill = 0 // fill is space available to fill + size int // size is size of a release + ) + var chunk []*release.Release + for _, rls := range rels { + if size = proto.Size(rls); size+fill > cap { + // Over-cap, push chunk onto channel to send over gRPC stream + s.Log("partitioned at %d with %d releases (cap=%d)", fill, len(chunk), cap) + chunks <- chunk + // reset paritioning state + chunk = chunk[:0] + fill = 0 + } + chunk = append(chunk, rls) + fill += size + } + if len(chunk) > 0 { + // send remaining if any + chunks <- chunk + } + close(chunks) + }() + return chunks } func filterByNamespace(namespace string, rels []*release.Release) ([]*release.Release, error) { diff --git a/pkg/tiller/release_list_test.go b/pkg/tiller/release_list_test.go index 64877422a..7b0fe6830 100644 --- a/pkg/tiller/release_list_test.go +++ b/pkg/tiller/release_list_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/tiller/release_modules.go b/pkg/tiller/release_modules.go index 876e1ba37..a587581ed 100644 --- a/pkg/tiller/release_modules.go +++ b/pkg/tiller/release_modules.go @@ -1,5 +1,5 @@ /* -Copyright 2017 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/tiller/release_rollback.go b/pkg/tiller/release_rollback.go index fe9a6a032..75e282fb8 100644 --- a/pkg/tiller/release_rollback.go +++ b/pkg/tiller/release_rollback.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -86,6 +86,11 @@ func (s *ReleaseServer) prepareRollback(req *services.RollbackReleaseRequest) (* return nil, nil, err } + description := req.Description + if req.Description == "" { + description = fmt.Sprintf("Rollback to %d", previousVersion) + } + // Store a new release object with previous release's configuration targetRelease := &release.Release{ Name: req.Name, @@ -101,7 +106,7 @@ func (s *ReleaseServer) prepareRollback(req *services.RollbackReleaseRequest) (* }, // Because we lose the reference to previous version elsewhere, we set the // message here, and only override it later if we experience failure. - Description: fmt.Sprintf("Rollback to %d", previousVersion), + Description: description, }, Version: currentRelease.Version + 1, Manifest: previousRelease.Manifest, @@ -135,7 +140,7 @@ func (s *ReleaseServer) performRollback(currentRelease, targetRelease *release.R targetRelease.Info.Status.Code = release.Status_FAILED targetRelease.Info.Description = msg s.recordRelease(currentRelease, true) - s.recordRelease(targetRelease, false) + s.recordRelease(targetRelease, true) return res, err } diff --git a/pkg/tiller/release_rollback_test.go b/pkg/tiller/release_rollback_test.go index b73501a36..d7909ed8b 100644 --- a/pkg/tiller/release_rollback_test.go +++ b/pkg/tiller/release_rollback_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -252,3 +252,35 @@ func TestRollbackReleaseFailure(t *testing.T) { t.Errorf("Expected SUPERSEDED status on previous Release version. Got %v", oldStatus) } } + +func TestRollbackReleaseWithCustomDescription(t *testing.T) { + c := helm.NewContext() + rs := rsFixture() + rel := releaseStub() + rs.env.Releases.Create(rel) + upgradedRel := upgradeReleaseVersion(rel) + rs.env.Releases.Update(rel) + rs.env.Releases.Create(upgradedRel) + + customDescription := "foo" + req := &services.RollbackReleaseRequest{ + Name: rel.Name, + Description: customDescription, + } + res, err := rs.RollbackRelease(c, req) + if err != nil { + t.Fatalf("Failed rollback: %s", err) + } + + if res.Release.Name == "" { + t.Errorf("Expected release name.") + } + + if res.Release.Name != rel.Name { + t.Errorf("Updated release name does not match previous release name. Expected %s, got %s", rel.Name, res.Release.Name) + } + + if res.Release.Info.Description != customDescription { + t.Errorf("Expected Description to be %q, got %q", customDescription, res.Release.Info.Description) + } +} diff --git a/pkg/tiller/release_server.go b/pkg/tiller/release_server.go index 56831fce9..f266cb9fa 100644 --- a/pkg/tiller/release_server.go +++ b/pkg/tiller/release_server.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -24,6 +24,7 @@ import ( "regexp" "strings" + "github.com/ghodss/yaml" "github.com/technosophos/moniker" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/discovery" @@ -135,7 +136,24 @@ func (s *ReleaseServer) reuseValues(req *services.UpdateReleaseRequest, current if err != nil { return err } + + // merge new values with current + if current.Config != nil && current.Config.Raw != "" && current.Config.Raw != "{}\n" { + req.Values.Raw = current.Config.Raw + "\n" + req.Values.Raw + } req.Chart.Values = &chart.Config{Raw: nv} + + // yaml unmarshal and marshal to remove duplicate keys + y := map[string]interface{}{} + if err := yaml.Unmarshal([]byte(req.Values.Raw), &y); err != nil { + return err + } + data, err := yaml.Marshal(y) + if err != nil { + return err + } + + req.Values.Raw = string(data) return nil } @@ -174,7 +192,7 @@ func (s *ReleaseServer) uniqName(start string, reuse bool) (string, error) { s.Log("name %s exists but is not in use, reusing name", start) return start, nil } else if reuse { - return "", errors.New("cannot re-use a name that is still in use") + 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 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) @@ -347,6 +365,9 @@ func (s *ReleaseServer) execHook(hs []*release.Hook, name, namespace, hook strin executingHooks = sortByHookWeight(executingHooks) for index, h := range executingHooks { + if err := s.deleteHookByPolicy(h, hooks.BeforeHookCreation, name, namespace, hook, kubeCli); err != nil { + return err + } b := bytes.NewBufferString(h.Manifest) if err := kubeCli.Create(namespace, b, timeout, false); err != nil { @@ -356,33 +377,24 @@ func (s *ReleaseServer) execHook(hs []*release.Hook, name, namespace, hook strin // No way to rewind a bytes.Buffer()? b.Reset() b.WriteString(h.Manifest) - if err := kubeCli.WatchUntilReady(namespace, b, timeout, false); err != nil { - s.Log("warning: Release %s %s %s could not complete: %s", name, hook, h.Path, err) - // If a hook is failed, checkout the annotation of the hook to determine whether the hook should be deleted - // under failed condition. If so, then clear the corresponding resource object in the hook - // Delete previous succeeded hooks with hook-delete-policy hook-succeeded - for _, hp := range executingHooks[:index] { - if hookShouldBeDeleted(hp, hooks.HookSucceeded) { - b.Reset() - b.WriteString(hp.Manifest) - s.Log("deleting %s hook %s for release %s due to %q policy", hook, hp.Name, name, hooks.HookSucceeded) - if errHookDelete := kubeCli.Delete(namespace, b); errHookDelete != nil { - s.Log("warning: Release %s %s %S could not be deleted: %s", name, hook, hp.Path, errHookDelete) - return errHookDelete + + // We can't watch CRDs + if hook != hooks.CRDInstall { + if err := kubeCli.WatchUntilReady(namespace, b, timeout, false); err != nil { + s.Log("warning: Release %s %s %s could not complete: %s", name, hook, h.Path, err) + // If a hook is failed, checkout the annotation of the hook to determine whether the hook should be deleted + // under failed condition. If so, then clear the corresponding resource object in the hook + // Delete previous succeeded hooks with hook-delete-policy hook-succeeded + for _, hp := range executingHooks[:index] { + if err := s.deleteHookByPolicy(hp, hooks.HookSucceeded, name, namespace, hook, kubeCli); err != nil { + return err } } - hp.LastRun = timeconv.Now() - } - if hookShouldBeDeleted(h, hooks.HookFailed) { - b.Reset() - b.WriteString(h.Manifest) - s.Log("deleting %s hook %s for release %s due to %q policy", hook, h.Name, name, hooks.HookFailed) - if errHookDelete := kubeCli.Delete(namespace, b); errHookDelete != nil { - s.Log("warning: Release %s %s %S could not be deleted: %s", name, hook, h.Path, errHookDelete) - return errHookDelete + if err := s.deleteHookByPolicy(h, hooks.HookFailed, name, namespace, hook, kubeCli); err != nil { + return err } + return err } - return err } } @@ -390,13 +402,8 @@ func (s *ReleaseServer) execHook(hs []*release.Hook, name, namespace, hook strin // If all hooks are succeeded, checkout the annotation of each hook to determine whether the hook should be deleted // under succeeded condition. If so, then clear the corresponding resource object in each hook for _, h := range executingHooks { - b := bytes.NewBufferString(h.Manifest) - if hookShouldBeDeleted(h, hooks.HookSucceeded) { - s.Log("deleting %s hook %s for release %s due to %q policy", hook, h.Name, name, hooks.HookSucceeded) - if errHookDelete := kubeCli.Delete(namespace, b); errHookDelete != nil { - s.Log("warning: Release %s %s %S could not be deleted: %s", name, hook, h.Path, errHookDelete) - return errHookDelete - } + if err := s.deleteHookByPolicy(h, hooks.HookSucceeded, name, namespace, hook, kubeCli); err != nil { + return err } h.LastRun = timeconv.Now() } @@ -422,11 +429,23 @@ func validateReleaseName(releaseName string) error { return nil } +func (s *ReleaseServer) deleteHookByPolicy(h *release.Hook, policy string, name, namespace, hook string, kubeCli environment.KubeClient) error { + b := bytes.NewBufferString(h.Manifest) + if hookHasDeletePolicy(h, policy) { + s.Log("deleting %s hook %s for release %s due to %q policy", hook, h.Name, name, policy) + if errHookDelete := kubeCli.Delete(namespace, b); errHookDelete != nil { + s.Log("warning: Release %s %s %S could not be deleted: %s", name, hook, h.Path, errHookDelete) + return errHookDelete + } + } + return nil +} + // hookShouldBeDeleted determines whether the defined hook deletion policy matches the hook deletion polices // supported by helm. If so, mark the hook as one should be deleted. -func hookShouldBeDeleted(hook *release.Hook, policy string) bool { +func hookHasDeletePolicy(h *release.Hook, policy string) bool { if dp, ok := deletePolices[policy]; ok { - for _, v := range hook.DeletePolicies { + for _, v := range h.DeletePolicies { if dp == v { return true } diff --git a/pkg/tiller/release_server_test.go b/pkg/tiller/release_server_test.go index d71e34bee..122ab9dd4 100644 --- a/pkg/tiller/release_server_test.go +++ b/pkg/tiller/release_server_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -18,18 +18,25 @@ package tiller import ( "errors" + "fmt" "io" "io/ioutil" "os" "regexp" "testing" + "time" + "github.com/ghodss/yaml" "github.com/golang/protobuf/ptypes/timestamp" "golang.org/x/net/context" "google.golang.org/grpc/metadata" + "k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" + "k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource" "k8s.io/helm/pkg/helm" + "k8s.io/helm/pkg/hooks" + "k8s.io/helm/pkg/kube" "k8s.io/helm/pkg/proto/hapi/chart" "k8s.io/helm/pkg/proto/hapi/release" "k8s.io/helm/pkg/proto/hapi/services" @@ -48,6 +55,25 @@ metadata: data: name: value` +var manifestWithCRDHook = ` +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: crontabs.stable.example.com + annotations: + "helm.sh/hook": crd-install +spec: + group: stable.example.com + version: v1 + scope: Namespaced + names: + plural: crontabs + singular: crontab + kind: CronTab + shortNames: + - ct +` + var manifestWithTestHook = `kind: Pod metadata: name: finding-nemo, @@ -98,23 +124,128 @@ func rsFixture() *ReleaseServer { } } -// chartStub creates a fully stubbed out chart. -func chartStub() *chart.Chart { - return &chart.Chart{ - // TODO: This should be more complete. - Metadata: &chart.Metadata{ - Name: "hello", +type chartOptions struct { + *chart.Chart +} + +type chartOption func(*chartOptions) + +func buildChart(opts ...chartOption) *chart.Chart { + c := &chartOptions{ + Chart: &chart.Chart{ + // TODO: This should be more complete. + Metadata: &chart.Metadata{ + Name: "hello", + }, + // This adds a basic template and hooks. + Templates: []*chart.Template{ + {Name: "templates/hello", Data: []byte("hello: world")}, + {Name: "templates/hooks", Data: []byte(manifestWithHook)}, + }, }, - // This adds basic templates, partials, and hooks. - Templates: []*chart.Template{ - {Name: "templates/hello", Data: []byte("hello: world")}, + } + + for _, opt := range opts { + opt(c) + } + + return c.Chart +} + +func withKube(version string) chartOption { + return func(opts *chartOptions) { + opts.Metadata.KubeVersion = version + } +} + +func withTiller(version string) chartOption { + return func(opts *chartOptions) { + opts.Metadata.TillerVersion = version + } +} + +func withDependency(dependencyOpts ...chartOption) chartOption { + return func(opts *chartOptions) { + opts.Dependencies = append(opts.Dependencies, buildChart(dependencyOpts...)) + } +} + +func withNotes(notes string) chartOption { + return func(opts *chartOptions) { + opts.Templates = append(opts.Templates, &chart.Template{ + Name: "templates/NOTES.txt", + Data: []byte(notes), + }) + } +} + +func withSampleTemplates() chartOption { + return func(opts *chartOptions) { + sampleTemplates := []*chart.Template{ + // This adds basic templates and partials. {Name: "templates/goodbye", Data: []byte("goodbye: world")}, {Name: "templates/empty", Data: []byte("")}, {Name: "templates/with-partials", Data: []byte(`hello: {{ template "_planet" . }}`)}, {Name: "templates/partials/_planet", Data: []byte(`{{define "_planet"}}Earth{{end}}`)}, - {Name: "templates/hooks", Data: []byte(manifestWithHook)}, + } + opts.Templates = append(opts.Templates, sampleTemplates...) + } +} + +type installOptions struct { + *services.InstallReleaseRequest +} + +type installOption func(*installOptions) + +func withName(name string) installOption { + return func(opts *installOptions) { + opts.Name = name + } +} + +func withDryRun() installOption { + return func(opts *installOptions) { + opts.DryRun = true + } +} + +func withDisabledHooks() installOption { + return func(opts *installOptions) { + opts.DisableHooks = true + } +} + +func withReuseName() installOption { + return func(opts *installOptions) { + opts.ReuseName = true + } +} + +func withChart(chartOpts ...chartOption) installOption { + return func(opts *installOptions) { + opts.Chart = buildChart(chartOpts...) + } +} + +func installRequest(opts ...installOption) *services.InstallReleaseRequest { + reqOpts := &installOptions{ + &services.InstallReleaseRequest{ + Namespace: "spaced", + Chart: buildChart(), }, } + + for _, opt := range opts { + opt(reqOpts) + } + + return reqOpts.InstallReleaseRequest +} + +// chartStub creates a fully stubbed out chart. +func chartStub() *chart.Chart { + return buildChart(withSampleTemplates()) } // releaseStub creates a release stub, complete with the chartStub as its chart. @@ -345,3 +476,460 @@ func (rs mockRunReleaseTestServer) SetTrailer(m metadata.MD) {} func (rs mockRunReleaseTestServer) SendMsg(v interface{}) error { return nil } func (rs mockRunReleaseTestServer) RecvMsg(v interface{}) error { return nil } func (rs mockRunReleaseTestServer) Context() context.Context { return helm.NewContext() } + +type mockHooksManifest struct { + Metadata struct { + Name string + Annotations map[string]string + } +} +type mockHooksKubeClient struct { + Resources map[string]*mockHooksManifest +} + +var errResourceExists = errors.New("resource already exists") + +func (kc *mockHooksKubeClient) makeManifest(r io.Reader) (*mockHooksManifest, error) { + b, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + + manifest := &mockHooksManifest{} + err = yaml.Unmarshal(b, manifest) + if err != nil { + return nil, err + } + + return manifest, nil +} +func (kc *mockHooksKubeClient) Create(ns string, r io.Reader, timeout int64, shouldWait bool) error { + manifest, err := kc.makeManifest(r) + if err != nil { + return err + } + + if _, hasKey := kc.Resources[manifest.Metadata.Name]; hasKey { + return errResourceExists + } + + kc.Resources[manifest.Metadata.Name] = manifest + + return nil +} +func (kc *mockHooksKubeClient) Get(ns string, r io.Reader) (string, error) { + return "", nil +} +func (kc *mockHooksKubeClient) Delete(ns string, r io.Reader) error { + manifest, err := kc.makeManifest(r) + if err != nil { + return err + } + + delete(kc.Resources, manifest.Metadata.Name) + + return nil +} +func (kc *mockHooksKubeClient) WatchUntilReady(ns string, r io.Reader, timeout int64, shouldWait bool) error { + paramManifest, err := kc.makeManifest(r) + if err != nil { + return err + } + + manifest, hasManifest := kc.Resources[paramManifest.Metadata.Name] + if !hasManifest { + return fmt.Errorf("mockHooksKubeClient.WatchUntilReady: no such resource %s found", paramManifest.Metadata.Name) + } + + if manifest.Metadata.Annotations["mockHooksKubeClient/Emulate"] == "hook-failed" { + return fmt.Errorf("mockHooksKubeClient.WatchUntilReady: hook-failed") + } + + return nil +} +func (kc *mockHooksKubeClient) Update(ns string, currentReader, modifiedReader io.Reader, force bool, recreate bool, timeout int64, shouldWait bool) error { + return nil +} +func (kc *mockHooksKubeClient) Build(ns string, reader io.Reader) (kube.Result, error) { + return []*resource.Info{}, nil +} +func (kc *mockHooksKubeClient) BuildUnstructured(ns string, reader io.Reader) (kube.Result, error) { + return []*resource.Info{}, nil +} +func (kc *mockHooksKubeClient) WaitAndGetCompletedPodPhase(namespace string, reader io.Reader, timeout time.Duration) (core.PodPhase, error) { + return core.PodUnknown, nil +} + +func deletePolicyStub(kubeClient *mockHooksKubeClient) *ReleaseServer { + e := environment.New() + e.Releases = storage.Init(driver.NewMemory()) + e.KubeClient = kubeClient + + clientset := fake.NewSimpleClientset() + return &ReleaseServer{ + ReleaseModule: &LocalReleaseModule{ + clientset: clientset, + }, + env: e, + clientset: clientset, + Log: func(_ string, _ ...interface{}) {}, + } +} + +func deletePolicyHookStub(hookName string, extraAnnotations map[string]string, DeletePolicies []release.Hook_DeletePolicy) *release.Hook { + extraAnnotationsStr := "" + for k, v := range extraAnnotations { + extraAnnotationsStr += fmt.Sprintf(" \"%s\": \"%s\"\n", k, v) + } + + return &release.Hook{ + Name: hookName, + Kind: "Job", + Path: hookName, + Manifest: fmt.Sprintf(`kind: Job +metadata: + name: %s + annotations: + "helm.sh/hook": pre-install,pre-upgrade +%sdata: +name: value`, hookName, extraAnnotationsStr), + Events: []release.Hook_Event{ + release.Hook_PRE_INSTALL, + release.Hook_PRE_UPGRADE, + }, + DeletePolicies: DeletePolicies, + } +} + +func execHookShouldSucceed(rs *ReleaseServer, hook *release.Hook, releaseName string, namespace string, hookType string) error { + err := rs.execHook([]*release.Hook{hook}, releaseName, namespace, hookType, 600) + if err != nil { + return fmt.Errorf("expected hook %s to be successful: %s", hook.Name, err) + } + return nil +} + +func execHookShouldFail(rs *ReleaseServer, hook *release.Hook, releaseName string, namespace string, hookType string) error { + err := rs.execHook([]*release.Hook{hook}, releaseName, namespace, hookType, 600) + if err == nil { + return fmt.Errorf("expected hook %s to be failed", hook.Name) + } + return nil +} + +func execHookShouldFailWithError(rs *ReleaseServer, hook *release.Hook, releaseName string, namespace string, hookType string, expectedError error) error { + err := rs.execHook([]*release.Hook{hook}, releaseName, namespace, hookType, 600) + if err != expectedError { + return fmt.Errorf("expected hook %s to fail with error %v, got %v", hook.Name, expectedError, err) + } + return nil +} + +type deletePolicyContext struct { + ReleaseServer *ReleaseServer + ReleaseName string + Namespace string + HookName string + KubeClient *mockHooksKubeClient +} + +func newDeletePolicyContext() *deletePolicyContext { + kubeClient := &mockHooksKubeClient{ + Resources: make(map[string]*mockHooksManifest), + } + + return &deletePolicyContext{ + KubeClient: kubeClient, + ReleaseServer: deletePolicyStub(kubeClient), + ReleaseName: "flying-carp", + Namespace: "river", + HookName: "migration-job", + } +} + +func TestSuccessfulHookWithoutDeletePolicy(t *testing.T) { + ctx := newDeletePolicyContext() + hook := deletePolicyHookStub(ctx.HookName, nil, nil) + + err := execHookShouldSucceed(ctx.ReleaseServer, hook, ctx.ReleaseName, ctx.Namespace, hooks.PreInstall) + if err != nil { + t.Error(err) + } + if _, hasResource := ctx.KubeClient.Resources[hook.Name]; !hasResource { + t.Errorf("expected resource %s to be created by kube client", hook.Name) + } +} + +func TestFailedHookWithoutDeletePolicy(t *testing.T) { + ctx := newDeletePolicyContext() + hook := deletePolicyHookStub(ctx.HookName, + map[string]string{"mockHooksKubeClient/Emulate": "hook-failed"}, + nil, + ) + + err := execHookShouldFail(ctx.ReleaseServer, hook, ctx.ReleaseName, ctx.Namespace, hooks.PreInstall) + if err != nil { + t.Error(err) + } + if _, hasResource := ctx.KubeClient.Resources[hook.Name]; !hasResource { + t.Errorf("expected resource %s to be created by kube client", hook.Name) + } +} + +func TestSuccessfulHookWithSucceededDeletePolicy(t *testing.T) { + ctx := newDeletePolicyContext() + hook := deletePolicyHookStub(ctx.HookName, + map[string]string{"helm.sh/hook-delete-policy": "hook-succeeded"}, + []release.Hook_DeletePolicy{release.Hook_SUCCEEDED}, + ) + + err := execHookShouldSucceed(ctx.ReleaseServer, hook, ctx.ReleaseName, ctx.Namespace, hooks.PreInstall) + if err != nil { + t.Error(err) + } + if _, hasResource := ctx.KubeClient.Resources[hook.Name]; hasResource { + t.Errorf("expected resource %s to be unexisting after hook succeeded", hook.Name) + } +} + +func TestSuccessfulHookWithFailedDeletePolicy(t *testing.T) { + ctx := newDeletePolicyContext() + hook := deletePolicyHookStub(ctx.HookName, + map[string]string{"helm.sh/hook-delete-policy": "hook-failed"}, + []release.Hook_DeletePolicy{release.Hook_FAILED}, + ) + + err := execHookShouldSucceed(ctx.ReleaseServer, hook, ctx.ReleaseName, ctx.Namespace, hooks.PreInstall) + if err != nil { + t.Error(err) + } + if _, hasResource := ctx.KubeClient.Resources[hook.Name]; !hasResource { + t.Errorf("expected resource %s to be existing after hook succeeded", hook.Name) + } +} + +func TestFailedHookWithSucceededDeletePolicy(t *testing.T) { + ctx := newDeletePolicyContext() + + hook := deletePolicyHookStub(ctx.HookName, + map[string]string{ + "mockHooksKubeClient/Emulate": "hook-failed", + "helm.sh/hook-delete-policy": "hook-succeeded", + }, + []release.Hook_DeletePolicy{release.Hook_SUCCEEDED}, + ) + + err := execHookShouldFail(ctx.ReleaseServer, hook, ctx.ReleaseName, ctx.Namespace, hooks.PreInstall) + if err != nil { + t.Error(err) + } + if _, hasResource := ctx.KubeClient.Resources[hook.Name]; !hasResource { + t.Errorf("expected resource %s to be existing after hook failed", hook.Name) + } +} + +func TestFailedHookWithFailedDeletePolicy(t *testing.T) { + ctx := newDeletePolicyContext() + + hook := deletePolicyHookStub(ctx.HookName, + map[string]string{ + "mockHooksKubeClient/Emulate": "hook-failed", + "helm.sh/hook-delete-policy": "hook-failed", + }, + []release.Hook_DeletePolicy{release.Hook_FAILED}, + ) + + err := execHookShouldFail(ctx.ReleaseServer, hook, ctx.ReleaseName, ctx.Namespace, hooks.PreInstall) + if err != nil { + t.Error(err) + } + if _, hasResource := ctx.KubeClient.Resources[hook.Name]; hasResource { + t.Errorf("expected resource %s to be unexisting after hook failed", hook.Name) + } +} + +func TestSuccessfulHookWithSuccededOrFailedDeletePolicy(t *testing.T) { + ctx := newDeletePolicyContext() + + hook := deletePolicyHookStub(ctx.HookName, + map[string]string{ + "helm.sh/hook-delete-policy": "hook-succeeded,hook-failed", + }, + []release.Hook_DeletePolicy{release.Hook_SUCCEEDED, release.Hook_FAILED}, + ) + + err := execHookShouldSucceed(ctx.ReleaseServer, hook, ctx.ReleaseName, ctx.Namespace, hooks.PreInstall) + if err != nil { + t.Error(err) + } + if _, hasResource := ctx.KubeClient.Resources[hook.Name]; hasResource { + t.Errorf("expected resource %s to be unexisting after hook succeeded", hook.Name) + } +} + +func TestFailedHookWithSuccededOrFailedDeletePolicy(t *testing.T) { + ctx := newDeletePolicyContext() + + hook := deletePolicyHookStub(ctx.HookName, + map[string]string{ + "mockHooksKubeClient/Emulate": "hook-failed", + "helm.sh/hook-delete-policy": "hook-succeeded,hook-failed", + }, + []release.Hook_DeletePolicy{release.Hook_SUCCEEDED, release.Hook_FAILED}, + ) + + err := execHookShouldFail(ctx.ReleaseServer, hook, ctx.ReleaseName, ctx.Namespace, hooks.PreInstall) + if err != nil { + t.Error(err) + } + if _, hasResource := ctx.KubeClient.Resources[hook.Name]; hasResource { + t.Errorf("expected resource %s to be unexisting after hook failed", hook.Name) + } +} + +func TestHookAlreadyExists(t *testing.T) { + ctx := newDeletePolicyContext() + + hook := deletePolicyHookStub(ctx.HookName, nil, nil) + + err := execHookShouldSucceed(ctx.ReleaseServer, hook, ctx.ReleaseName, ctx.Namespace, hooks.PreInstall) + if err != nil { + t.Error(err) + } + + if _, hasResource := ctx.KubeClient.Resources[hook.Name]; !hasResource { + t.Errorf("expected resource %s to be existing after hook succeeded", hook.Name) + } + + err = execHookShouldFailWithError(ctx.ReleaseServer, hook, ctx.ReleaseName, ctx.Namespace, hooks.PreUpgrade, errResourceExists) + if err != nil { + t.Error(err) + } + + if _, hasResource := ctx.KubeClient.Resources[hook.Name]; !hasResource { + t.Errorf("expected resource %s to be existing after already exists error", hook.Name) + } +} + +func TestHookDeletingWithBeforeHookCreationDeletePolicy(t *testing.T) { + ctx := newDeletePolicyContext() + + hook := deletePolicyHookStub(ctx.HookName, + map[string]string{"helm.sh/hook-delete-policy": "before-hook-creation"}, + []release.Hook_DeletePolicy{release.Hook_BEFORE_HOOK_CREATION}, + ) + + err := execHookShouldSucceed(ctx.ReleaseServer, hook, ctx.ReleaseName, ctx.Namespace, hooks.PreInstall) + if err != nil { + t.Error(err) + } + + if _, hasResource := ctx.KubeClient.Resources[hook.Name]; !hasResource { + t.Errorf("expected resource %s to be existing after hook succeeded", hook.Name) + } + + err = execHookShouldSucceed(ctx.ReleaseServer, hook, ctx.ReleaseName, ctx.Namespace, hooks.PreUpgrade) + if err != nil { + t.Error(err) + } + + if _, hasResource := ctx.KubeClient.Resources[hook.Name]; !hasResource { + t.Errorf("expected resource %s to be existing after hook succeeded", hook.Name) + } +} + +func TestSuccessfulHookWithMixedDeletePolicies(t *testing.T) { + ctx := newDeletePolicyContext() + + hook := deletePolicyHookStub(ctx.HookName, + map[string]string{ + "helm.sh/hook-delete-policy": "hook-succeeded,before-hook-creation", + }, + []release.Hook_DeletePolicy{release.Hook_SUCCEEDED, release.Hook_BEFORE_HOOK_CREATION}, + ) + + err := execHookShouldSucceed(ctx.ReleaseServer, hook, ctx.ReleaseName, ctx.Namespace, hooks.PreInstall) + if err != nil { + t.Error(err) + } + + if _, hasResource := ctx.KubeClient.Resources[hook.Name]; hasResource { + t.Errorf("expected resource %s to be unexisting after hook succeeded", hook.Name) + } + + err = execHookShouldSucceed(ctx.ReleaseServer, hook, ctx.ReleaseName, ctx.Namespace, hooks.PreUpgrade) + if err != nil { + t.Error(err) + } + + if _, hasResource := ctx.KubeClient.Resources[hook.Name]; hasResource { + t.Errorf("expected resource %s to be unexisting after hook succeeded", hook.Name) + } +} + +func TestFailedHookWithMixedDeletePolicies(t *testing.T) { + ctx := newDeletePolicyContext() + + hook := deletePolicyHookStub(ctx.HookName, + map[string]string{ + "mockHooksKubeClient/Emulate": "hook-failed", + "helm.sh/hook-delete-policy": "hook-succeeded,before-hook-creation", + }, + []release.Hook_DeletePolicy{release.Hook_SUCCEEDED, release.Hook_BEFORE_HOOK_CREATION}, + ) + + err := execHookShouldFail(ctx.ReleaseServer, hook, ctx.ReleaseName, ctx.Namespace, hooks.PreInstall) + if err != nil { + t.Error(err) + } + + if _, hasResource := ctx.KubeClient.Resources[hook.Name]; !hasResource { + t.Errorf("expected resource %s to be existing after hook failed", hook.Name) + } + + err = execHookShouldFail(ctx.ReleaseServer, hook, ctx.ReleaseName, ctx.Namespace, hooks.PreUpgrade) + if err != nil { + t.Error(err) + } + + if _, hasResource := ctx.KubeClient.Resources[hook.Name]; !hasResource { + t.Errorf("expected resource %s to be existing after hook failed", hook.Name) + } +} + +func TestFailedThenSuccessfulHookWithMixedDeletePolicies(t *testing.T) { + ctx := newDeletePolicyContext() + + hook := deletePolicyHookStub(ctx.HookName, + map[string]string{ + "mockHooksKubeClient/Emulate": "hook-failed", + "helm.sh/hook-delete-policy": "hook-succeeded,before-hook-creation", + }, + []release.Hook_DeletePolicy{release.Hook_SUCCEEDED, release.Hook_BEFORE_HOOK_CREATION}, + ) + + err := execHookShouldFail(ctx.ReleaseServer, hook, ctx.ReleaseName, ctx.Namespace, hooks.PreInstall) + if err != nil { + t.Error(err) + } + + if _, hasResource := ctx.KubeClient.Resources[hook.Name]; !hasResource { + t.Errorf("expected resource %s to be existing after hook failed", hook.Name) + } + + hook = deletePolicyHookStub(ctx.HookName, + map[string]string{ + "helm.sh/hook-delete-policy": "hook-succeeded,before-hook-creation", + }, + []release.Hook_DeletePolicy{release.Hook_SUCCEEDED, release.Hook_BEFORE_HOOK_CREATION}, + ) + + err = execHookShouldSucceed(ctx.ReleaseServer, hook, ctx.ReleaseName, ctx.Namespace, hooks.PreUpgrade) + if err != nil { + t.Error(err) + } + + if _, hasResource := ctx.KubeClient.Resources[hook.Name]; hasResource { + t.Errorf("expected resource %s to be unexisting after hook succeeded", hook.Name) + } +} diff --git a/pkg/tiller/release_status.go b/pkg/tiller/release_status.go index e0d75877d..3f8047118 100644 --- a/pkg/tiller/release_status.go +++ b/pkg/tiller/release_status.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/tiller/release_status_test.go b/pkg/tiller/release_status_test.go index 4ba0f6cd5..69a710143 100644 --- a/pkg/tiller/release_status_test.go +++ b/pkg/tiller/release_status_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/tiller/release_testing.go b/pkg/tiller/release_testing.go index a44b67e6f..06d41e323 100644 --- a/pkg/tiller/release_testing.go +++ b/pkg/tiller/release_testing.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/tiller/release_testing_test.go b/pkg/tiller/release_testing_test.go index f8d92ebcc..e0fc7df41 100644 --- a/pkg/tiller/release_testing_test.go +++ b/pkg/tiller/release_testing_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/tiller/release_uninstall.go b/pkg/tiller/release_uninstall.go index 423b6e7ef..2ae3e4c36 100644 --- a/pkg/tiller/release_uninstall.go +++ b/pkg/tiller/release_uninstall.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -97,7 +97,11 @@ func (s *ReleaseServer) UninstallRelease(c ctx.Context, req *services.UninstallR } rel.Info.Status.Code = release.Status_DELETED - rel.Info.Description = "Deletion complete" + if req.Description == "" { + rel.Info.Description = "Deletion complete" + } else { + rel.Info.Description = req.Description + } if req.Purge { s.Log("purge requested for %s", req.Name) diff --git a/pkg/tiller/release_uninstall_test.go b/pkg/tiller/release_uninstall_test.go index 20bfd2486..d33e9c2a6 100644 --- a/pkg/tiller/release_uninstall_test.go +++ b/pkg/tiller/release_uninstall_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -176,3 +176,24 @@ func TestUninstallReleaseNoHooks(t *testing.T) { t.Errorf("Expected LastRun to be zero, got %d.", res.Release.Hooks[0].LastRun.Seconds) } } + +func TestUninstallReleaseCustomDescription(t *testing.T) { + c := helm.NewContext() + rs := rsFixture() + rs.env.Releases.Create(releaseStub()) + + customDescription := "foo" + req := &services.UninstallReleaseRequest{ + Name: "angry-panda", + Description: "foo", + } + + res, err := rs.UninstallRelease(c, req) + if err != nil { + t.Errorf("Failed uninstall: %s", err) + } + + if res.Release.Info.Description != customDescription { + t.Errorf("Expected description to be %q, got %q", customDescription, res.Release.Info.Description) + } +} diff --git a/pkg/tiller/release_update.go b/pkg/tiller/release_update.go index cb8b57792..5cd82dfc5 100644 --- a/pkg/tiller/release_update.go +++ b/pkg/tiller/release_update.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -80,7 +80,7 @@ func (s *ReleaseServer) prepareUpdate(req *services.UpdateReleaseRequest) (*rele return nil, nil, err } - // If new values were not supplied in the upgrade, re-use the existing values. + // determine if values will be reused if err := s.reuseValues(req, currentRelease); err != nil { return nil, nil, err } @@ -161,6 +161,10 @@ func (s *ReleaseServer) performUpdateForce(req *services.UpdateReleaseRequest) ( Timeout: req.Timeout, Wait: req.Wait, }) + + // update new release with next revision number so as to append to the old release's history + newRelease.Version = oldRelease.Version + 1 + res := &services.UpdateReleaseResponse{Release: newRelease} if err != nil { s.Log("failed update prepare step: %s", err) @@ -172,6 +176,12 @@ func (s *ReleaseServer) performUpdateForce(req *services.UpdateReleaseRequest) ( return res, err } + if req.DryRun { + s.Log("dry run for %s", newRelease.Name) + res.Release.Info.Description = "Dry run complete" + return res, nil + } + // From here on out, the release is considered to be in Status_DELETING or Status_DELETED // state. There is no turning back. oldRelease.Info.Status.Code = release.Status_DELETING @@ -218,8 +228,6 @@ func (s *ReleaseServer) performUpdateForce(req *services.UpdateReleaseRequest) ( } } - // update new release with next revision number so as to append to the old release's history - newRelease.Version = oldRelease.Version + 1 s.recordRelease(newRelease, false) if err := s.ReleaseModule.Update(oldRelease, newRelease, req, s.env); err != nil { msg := fmt.Sprintf("Upgrade %q failed: %s", newRelease.Name, err) @@ -243,7 +251,11 @@ func (s *ReleaseServer) performUpdateForce(req *services.UpdateReleaseRequest) ( } newRelease.Info.Status.Code = release.Status_DEPLOYED - newRelease.Info.Description = "Upgrade complete" + if req.Description == "" { + newRelease.Info.Description = "Upgrade complete" + } else { + newRelease.Info.Description = req.Description + } s.recordRelease(newRelease, true) return res, nil @@ -287,7 +299,11 @@ func (s *ReleaseServer) performUpdate(originalRelease, updatedRelease *release.R s.recordRelease(originalRelease, true) updatedRelease.Info.Status.Code = release.Status_DEPLOYED - updatedRelease.Info.Description = "Upgrade complete" + if req.Description == "" { + updatedRelease.Info.Description = "Upgrade complete" + } else { + updatedRelease.Info.Description = req.Description + } return res, nil } diff --git a/pkg/tiller/release_update_test.go b/pkg/tiller/release_update_test.go index 642952f19..5edd53b82 100644 --- a/pkg/tiller/release_update_test.go +++ b/pkg/tiller/release_update_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -17,6 +17,7 @@ limitations under the License. package tiller import ( + "fmt" "strings" "testing" @@ -128,6 +129,147 @@ func TestUpdateRelease_ResetValues(t *testing.T) { } } +func TestUpdateRelease_ReuseValuesWithNoValues(t *testing.T) { + c := helm.NewContext() + rs := rsFixture() + + installReq := &services.InstallReleaseRequest{ + Namespace: "spaced", + Chart: &chart.Chart{ + Metadata: &chart.Metadata{Name: "hello"}, + Templates: []*chart.Template{ + {Name: "templates/hello", Data: []byte("hello: world")}, + {Name: "templates/hooks", Data: []byte(manifestWithHook)}, + }, + Values: &chart.Config{Raw: "defaultFoo: defaultBar"}, + }, + } + + installResp, err := rs.InstallRelease(c, installReq) + if err != nil { + t.Fatal(err) + } + + rel := installResp.Release + req := &services.UpdateReleaseRequest{ + Name: rel.Name, + Chart: &chart.Chart{ + Metadata: &chart.Metadata{Name: "hello"}, + Templates: []*chart.Template{ + {Name: "templates/hello", Data: []byte("hello: world")}, + }, + }, + Values: &chart.Config{Raw: ""}, + ReuseValues: true, + } + + _, err = rs.UpdateRelease(c, req) + if err != nil { + t.Fatalf("Failed updated: %s", err) + } +} + +// This is a regression test for bug found in issue #3655 +func TestUpdateRelease_ComplexReuseValues(t *testing.T) { + c := helm.NewContext() + rs := rsFixture() + + installReq := &services.InstallReleaseRequest{ + Namespace: "spaced", + Chart: &chart.Chart{ + Metadata: &chart.Metadata{Name: "hello"}, + Templates: []*chart.Template{ + {Name: "templates/hello", Data: []byte("hello: world")}, + {Name: "templates/hooks", Data: []byte(manifestWithHook)}, + }, + Values: &chart.Config{Raw: "defaultFoo: defaultBar"}, + }, + Values: &chart.Config{Raw: "foo: bar"}, + } + + fmt.Println("Running Install release with foo: bar override") + installResp, err := rs.InstallRelease(c, installReq) + if err != nil { + t.Fatal(err) + } + + rel := installResp.Release + req := &services.UpdateReleaseRequest{ + Name: rel.Name, + Chart: &chart.Chart{ + Metadata: &chart.Metadata{Name: "hello"}, + Templates: []*chart.Template{ + {Name: "templates/hello", Data: []byte("hello: world")}, + {Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)}, + }, + Values: &chart.Config{Raw: "defaultFoo: defaultBar"}, + }, + } + + fmt.Println("Running Update release with no overrides and no reuse-values flag") + res, err := rs.UpdateRelease(c, req) + if err != nil { + t.Fatalf("Failed updated: %s", err) + } + + expect := "foo: bar" + if res.Release.Config != nil && res.Release.Config.Raw != expect { + t.Errorf("Expected chart values to be %q, got %q", expect, res.Release.Config.Raw) + } + + rel = res.Release + req = &services.UpdateReleaseRequest{ + Name: rel.Name, + Chart: &chart.Chart{ + Metadata: &chart.Metadata{Name: "hello"}, + Templates: []*chart.Template{ + {Name: "templates/hello", Data: []byte("hello: world")}, + {Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)}, + }, + Values: &chart.Config{Raw: "defaultFoo: defaultBar"}, + }, + Values: &chart.Config{Raw: "foo2: bar2"}, + ReuseValues: true, + } + + fmt.Println("Running Update release with foo2: bar2 override and reuse-values") + res, err = rs.UpdateRelease(c, req) + if err != nil { + t.Fatalf("Failed updated: %s", err) + } + + // This should have the newly-passed overrides. + expect = "foo: bar\nfoo2: bar2\n" + if res.Release.Config != nil && res.Release.Config.Raw != expect { + t.Errorf("Expected request config to be %q, got %q", expect, res.Release.Config.Raw) + } + + rel = res.Release + req = &services.UpdateReleaseRequest{ + Name: rel.Name, + Chart: &chart.Chart{ + Metadata: &chart.Metadata{Name: "hello"}, + Templates: []*chart.Template{ + {Name: "templates/hello", Data: []byte("hello: world")}, + {Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)}, + }, + Values: &chart.Config{Raw: "defaultFoo: defaultBar"}, + }, + Values: &chart.Config{Raw: "foo: baz"}, + ReuseValues: true, + } + + fmt.Println("Running Update release with foo=baz override with reuse-values flag") + res, err = rs.UpdateRelease(c, req) + if err != nil { + t.Fatalf("Failed updated: %s", err) + } + expect = "foo: baz\nfoo2: bar2\n" + if res.Release.Config != nil && res.Release.Config.Raw != expect { + t.Errorf("Expected chart values to be %q, got %q", expect, res.Release.Config.Raw) + } +} + func TestUpdateRelease_ReuseValues(t *testing.T) { c := helm.NewContext() rs := rsFixture() @@ -157,8 +299,8 @@ func TestUpdateRelease_ReuseValues(t *testing.T) { if res.Release.Chart.Values != nil && res.Release.Chart.Values.Raw != expect { t.Errorf("Expected chart values to be %q, got %q", expect, res.Release.Chart.Values.Raw) } - // This should have the newly-passed overrides. - expect = "name2: val2" + // This should have the newly-passed overrides and any other computed values. `name: value` comes from release Config via releaseStub() + expect = "name: value\nname2: val2\n" if res.Release.Config != nil && res.Release.Config.Raw != expect { t.Errorf("Expected request config to be %q, got %q", expect, res.Release.Config.Raw) } @@ -330,6 +472,55 @@ func TestUpdateReleaseNoChanges(t *testing.T) { } } +func TestUpdateReleaseCustomDescription(t *testing.T) { + c := helm.NewContext() + rs := rsFixture() + rel := releaseStub() + rs.env.Releases.Create(rel) + + customDescription := "foo" + + req := &services.UpdateReleaseRequest{ + Name: rel.Name, + Chart: rel.GetChart(), + Description: customDescription, + } + + res, err := rs.UpdateRelease(c, req) + if err != nil { + t.Fatalf("Failed updated: %s", err) + } + if res.Release.Info.Description != customDescription { + t.Errorf("Expected release description to be %q, got %q", customDescription, res.Release.Info.Description) + } + compareStoredAndReturnedRelease(t, *rs, *res) +} + +func TestUpdateReleaseCustomDescription_Force(t *testing.T) { + c := helm.NewContext() + rs := rsFixture() + rel := releaseStub() + rs.env.Releases.Create(rel) + + customDescription := "foo" + + req := &services.UpdateReleaseRequest{ + Name: rel.Name, + Chart: rel.GetChart(), + Force: true, + Description: customDescription, + } + + res, err := rs.UpdateRelease(c, req) + if err != nil { + t.Fatalf("Failed updated: %s", err) + } + if res.Release.Info.Description != customDescription { + t.Errorf("Expected release description to be %q, got %q", customDescription, res.Release.Info.Description) + } + compareStoredAndReturnedRelease(t, *rs, *res) +} + func compareStoredAndReturnedRelease(t *testing.T, rs ReleaseServer, res services.UpdateReleaseResponse) *release.Release { storedRelease, err := rs.env.Releases.Get(res.Release.Name, res.Release.Version) if err != nil { diff --git a/pkg/tiller/release_version.go b/pkg/tiller/release_version.go index 66b7137bb..0656a1ab9 100644 --- a/pkg/tiller/release_version.go +++ b/pkg/tiller/release_version.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/tiller/resource_policy.go b/pkg/tiller/resource_policy.go index 66da1283f..cca2391d8 100644 --- a/pkg/tiller/resource_policy.go +++ b/pkg/tiller/resource_policy.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/tiller/server.go b/pkg/tiller/server.go index 818cfd47a..0fbcd4533 100644 --- a/pkg/tiller/server.go +++ b/pkg/tiller/server.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/timeconv/doc.go b/pkg/timeconv/doc.go index 235167391..0565a45cd 100644 --- a/pkg/timeconv/doc.go +++ b/pkg/timeconv/doc.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/timeconv/timeconv.go b/pkg/timeconv/timeconv.go index 24ff10f4e..4d11abfe6 100644 --- a/pkg/timeconv/timeconv.go +++ b/pkg/timeconv/timeconv.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/timeconv/timeconv_test.go b/pkg/timeconv/timeconv_test.go index f673df3c9..bd22a238d 100644 --- a/pkg/timeconv/timeconv_test.go +++ b/pkg/timeconv/timeconv_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/tlsutil/cfg.go b/pkg/tlsutil/cfg.go index 9ce3109e1..2c1dfd340 100644 --- a/pkg/tlsutil/cfg.go +++ b/pkg/tlsutil/cfg.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -33,6 +33,9 @@ type Options struct { CertFile string // Client-only options InsecureSkipVerify bool + // Overrides the server name used to verify the hostname on the returned + // certificates from the server. + ServerName string // Server-only options ClientAuth tls.ClientAuthType } @@ -55,8 +58,12 @@ func ClientConfig(opts Options) (cfg *tls.Config, err error) { return nil, err } } - - cfg = &tls.Config{InsecureSkipVerify: opts.InsecureSkipVerify, Certificates: []tls.Certificate{*cert}, RootCAs: pool} + cfg = &tls.Config{ + InsecureSkipVerify: opts.InsecureSkipVerify, + Certificates: []tls.Certificate{*cert}, + ServerName: opts.ServerName, + RootCAs: pool, + } return cfg, nil } diff --git a/pkg/tlsutil/tls.go b/pkg/tlsutil/tls.go index df698fd4e..6b0052acc 100644 --- a/pkg/tlsutil/tls.go +++ b/pkg/tlsutil/tls.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -21,17 +21,20 @@ import ( "crypto/x509" "fmt" "io/ioutil" + "k8s.io/helm/pkg/urlutil" ) -// NewClientTLS returns tls.Config appropriate for client auth. -func NewClientTLS(certFile, keyFile, caFile string) (*tls.Config, error) { - cert, err := CertFromFilePair(certFile, keyFile) - if err != nil { - return nil, err - } - config := tls.Config{ - Certificates: []tls.Certificate{*cert}, +func newTLSConfigCommon(certFile, keyFile, caFile string) (*tls.Config, error) { + config := tls.Config{} + + if certFile != "" && keyFile != "" { + cert, err := CertFromFilePair(certFile, keyFile) + if err != nil { + return nil, err + } + config.Certificates = []tls.Certificate{*cert} } + if caFile != "" { cp, err := CertPoolFromFile(caFile) if err != nil { @@ -39,9 +42,32 @@ func NewClientTLS(certFile, keyFile, caFile string) (*tls.Config, error) { } config.RootCAs = cp } + return &config, nil } +// NewClientTLS returns tls.Config appropriate for client auth. +func NewClientTLS(certFile, keyFile, caFile string) (*tls.Config, error) { + return newTLSConfigCommon(certFile, keyFile, caFile) +} + +// NewTLSConfig returns tls.Config appropriate for client and/or server auth. +func NewTLSConfig(url, certFile, keyFile, caFile string) (*tls.Config, error) { + config, err := newTLSConfigCommon(certFile, keyFile, caFile) + if err != nil { + return nil, err + } + config.BuildNameToCertificate() + + serverName, err := urlutil.ExtractHostname(url) + if err != nil { + return nil, err + } + config.ServerName = serverName + + return config, nil +} + // CertPoolFromFile returns an x509.CertPool containing the certificates // in the given PEM-encoded file. // Returns an error if the file could not be read, a certificate could not diff --git a/pkg/tlsutil/tlsutil_test.go b/pkg/tlsutil/tlsutil_test.go index 4f04d50ab..a4b3c9c22 100644 --- a/pkg/tlsutil/tlsutil_test.go +++ b/pkg/tlsutil/tlsutil_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/urlutil/urlutil.go b/pkg/urlutil/urlutil.go index fb67708ae..272907de0 100644 --- a/pkg/urlutil/urlutil.go +++ b/pkg/urlutil/urlutil.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/urlutil/urlutil_test.go b/pkg/urlutil/urlutil_test.go index f0c82c0a9..616c4f14f 100644 --- a/pkg/urlutil/urlutil_test.go +++ b/pkg/urlutil/urlutil_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/version/compatible.go b/pkg/version/compatible.go index 735610778..d0516a9d0 100644 --- a/pkg/version/compatible.go +++ b/pkg/version/compatible.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/version/compatible_test.go b/pkg/version/compatible_test.go index adc1c489e..7a3b23a7d 100644 --- a/pkg/version/compatible_test.go +++ b/pkg/version/compatible_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/version/doc.go b/pkg/version/doc.go index 23c9e500d..3b61dd50e 100644 --- a/pkg/version/doc.go +++ b/pkg/version/doc.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/pkg/version/version.go b/pkg/version/version.go index 6f5a1a452..c4ce4b381 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -26,7 +26,7 @@ var ( // Increment major number for new feature additions and behavioral changes. // Increment minor number for bug fixes and performance enhancements. // Increment patch number for critical fixes to existing releases. - Version = "v2.8" + Version = "v2.10" // BuildMetadata is extra build time data BuildMetadata = "unreleased" diff --git a/pkg/version/version_test.go b/pkg/version/version_test.go index e0e4cac0f..eba573533 100644 --- a/pkg/version/version_test.go +++ b/pkg/version/version_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. diff --git a/rootfs/Dockerfile b/rootfs/Dockerfile index 53757cd8d..82dfa0d4c 100644 --- a/rootfs/Dockerfile +++ b/rootfs/Dockerfile @@ -1,4 +1,4 @@ -# Copyright 2016 The Kubernetes Authors. +# 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. @@ -12,15 +12,16 @@ # See the License for the specific language governing permissions and # limitations under the License. -FROM alpine:3.3 +FROM alpine:3.7 -RUN apk update && apk add ca-certificates && rm -rf /var/cache/apk/* +RUN apk update && apk add ca-certificates socat && rm -rf /var/cache/apk/* ENV HOME /tmp +COPY helm /helm COPY tiller /tiller EXPOSE 44134 - -CMD ["/tiller"] +USER nobody +ENTRYPOINT ["/tiller"] diff --git a/rootfs/Dockerfile.experimental b/rootfs/Dockerfile.experimental index 990bcde51..ca0c87f30 100644 --- a/rootfs/Dockerfile.experimental +++ b/rootfs/Dockerfile.experimental @@ -1,4 +1,4 @@ -# Copyright 2017 The Kubernetes Authors. +# 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. @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -FROM alpine:3.3 +FROM alpine:3.7 RUN apk update && apk add ca-certificates && rm -rf /var/cache/apk/* @@ -21,6 +21,6 @@ ENV HOME /tmp COPY tiller /tiller EXPOSE 44134 - -CMD ["/tiller", "--experimental-release"] +USER nobody +ENTRYPOINT ["/tiller", "--experimental-release"] diff --git a/rootfs/Dockerfile.rudder b/rootfs/Dockerfile.rudder index 6bb3a2d92..61afb8af8 100644 --- a/rootfs/Dockerfile.rudder +++ b/rootfs/Dockerfile.rudder @@ -1,4 +1,4 @@ -# Copyright 2017 The Kubernetes Authors. +# 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. diff --git a/scripts/coverage.sh b/scripts/coverage.sh index 1863d5835..62d495769 100755 --- a/scripts/coverage.sh +++ b/scripts/coverage.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Copyright 2016 The Kubernetes Authors All rights reserved. +# 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. diff --git a/scripts/get b/scripts/get index 6654fd226..29cd47e1a 100755 --- a/scripts/get +++ b/scripts/get @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Copyright 2016 The Kubernetes Authors All rights reserved. +# 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. @@ -63,7 +63,7 @@ verifySupported() { local supported="darwin-386\ndarwin-amd64\nlinux-386\nlinux-amd64\nlinux-arm\nlinux-arm64\nlinux-ppc64le\nwindows-386\nwindows-amd64" if ! echo "${supported}" | grep -q "${OS}-${ARCH}"; then echo "No prebuilt binary for ${OS}-${ARCH}." - echo "To build from source, go to https://github.com/kubernetes/helm" + echo "To build from source, go to https://github.com/helm/helm" exit 1 fi @@ -76,11 +76,11 @@ 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/kubernetes/helm/releases/${DESIRED_VERSION:-latest}" + 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 | cut -d '"' -f 2 | awk '{n=split($NF,a,"/");print a[n]}' | awk 'a !~ $0{print}; {a=$0}') + 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\//' | cut -d '"' -f 2 | awk '{n=split($NF,a,"/");print a[n]}' | awk 'a !~ $0{print}; {a=$0}') + 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." @@ -92,7 +92,7 @@ checkDesiredVersion() { # if it needs to be changed. checkHelmInstalledVersion() { if [[ -f "${HELM_INSTALL_DIR}/${PROJECT_NAME}" ]]; then - local version=$(helm version | grep '^Client' | cut -d'"' -f2) + local version=$(helm version -c | grep '^Client' | cut -d'"' -f2) if [[ "$version" == "$TAG" ]]; then echo "Helm ${version} is already ${DESIRED_VERSION:-latest}" return 0 @@ -155,7 +155,7 @@ fail_trap() { else echo "Failed to install $PROJECT_NAME" fi - echo -e "\tFor support, go to https://github.com/kubernetes/helm." + echo -e "\tFor support, go to https://github.com/helm/helm." fi cleanup exit $result @@ -182,9 +182,11 @@ help () { echo -e "\te.g. --version v2.4.0 or -v latest" } -# cleanup temporary files to avoid https://github.com/kubernetes/helm/issues/2977 +# cleanup temporary files to avoid https://github.com/helm/helm/issues/2977 cleanup() { - rm -rf "$HELM_TMP_ROOT" + if [[ -d "${HELM_TMP_ROOT:-}" ]]; then + rm -rf "$HELM_TMP_ROOT" + fi } # Execution diff --git a/scripts/sync-repo.sh b/scripts/sync-repo.sh index 3795b1a7c..453102072 100755 --- a/scripts/sync-repo.sh +++ b/scripts/sync-repo.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Copyright 2016 The Kubernetes Authors All rights reserved. +# 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. diff --git a/scripts/update-docs.sh b/scripts/update-docs.sh index e014b537e..d3018be50 100755 --- a/scripts/update-docs.sh +++ b/scripts/update-docs.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Copyright 2017 The Kubernetes Authors All rights reserved. +# 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. diff --git a/scripts/util.sh b/scripts/util.sh index 09caaf972..c1e6c3751 100644 --- a/scripts/util.sh +++ b/scripts/util.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Copyright 2016 The Kubernetes Authors All rights reserved. +# 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. diff --git a/scripts/validate-go.sh b/scripts/validate-go.sh index 2ecf5dfb3..328ce40f9 100755 --- a/scripts/validate-go.sh +++ b/scripts/validate-go.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Copyright 2016 The Kubernetes Authors All rights reserved. +# 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. diff --git a/scripts/validate-license.sh b/scripts/validate-license.sh index fe7ec481b..12c76f75c 100755 --- a/scripts/validate-license.sh +++ b/scripts/validate-license.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Copyright 2016 The Kubernetes Authors All rights reserved. +# 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. @@ -27,10 +27,19 @@ find_files() { \( -name '*.go' -o -name '*.sh' -o -name 'Dockerfile' \) } -failed=($(find_files | xargs grep -L 'Licensed under the Apache License, Version 2.0 (the "License");')) -if (( ${#failed[@]} > 0 )); then +failed_license_header=($(find_files | xargs grep -L 'Licensed under the Apache License, Version 2.0 (the "License");')) +if (( ${#failed_license_header[@]} > 0 )); then echo "Some source files are missing license headers." - for f in "${failed[@]}"; do + for f in "${failed_license_header[@]}"; do + echo " $f" + done + exit 1 +fi + +failed_copyright_header=($(find_files | xargs grep -L 'Copyright The Helm Authors.')) +if (( ${#failed_copyright_header[@]} > 0 )); then + echo "Some source files are missing the copyright header." + for f in "${failed_copyright_header[@]}"; do echo " $f" done exit 1 diff --git a/scripts/verify-docs.sh b/scripts/verify-docs.sh index b0b799eac..b176b036e 100755 --- a/scripts/verify-docs.sh +++ b/scripts/verify-docs.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Copyright 2017 The Kubernetes Authors All rights reserved. +# 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.