mirror of https://github.com/helm/helm.git
				
				
				
			Merge branch 'master' into master
This commit is contained in:
		
						commit
						39db9ec6e8
					
				|  | @ -6,6 +6,7 @@ _dist/ | |||
| _proto/*.pb.go | ||||
| bin/ | ||||
| rootfs/tiller | ||||
| rootfs/rudder | ||||
| vendor/ | ||||
| *.exe | ||||
| .idea/ | ||||
|  |  | |||
							
								
								
									
										12
									
								
								.travis.yml
								
								
								
								
							
							
						
						
									
										12
									
								
								.travis.yml
								
								
								
								
							|  | @ -1,12 +0,0 @@ | |||
| language: go | ||||
| 
 | ||||
| go: | ||||
|   - '1.7.x' | ||||
| 
 | ||||
| go_import_path: k8s.io/helm | ||||
| 
 | ||||
| before_install: | ||||
|   - make bootstrap | ||||
| 
 | ||||
| script: | ||||
|   - make test | ||||
							
								
								
									
										16
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										16
									
								
								Makefile
								
								
								
								
							|  | @ -1,6 +1,7 @@ | |||
| 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 | ||||
| DIST_DIRS         = find * -type d -exec | ||||
| APP               = helm | ||||
|  | @ -66,6 +67,19 @@ docker-build: check-docker docker-binary | |||
| 	docker build --rm -t ${IMAGE} rootfs | ||||
| 	docker tag ${IMAGE} ${MUTABLE_IMAGE} | ||||
| 
 | ||||
| .PHONY: docker-binary-rudder | ||||
| docker-binary-rudder: BINDIR = ./rootfs | ||||
| docker-binary-rudder: GOFLAGS += -a -installsuffix cgo | ||||
| docker-binary-rudder: | ||||
| 	GOOS=linux GOARCH=amd64 CGO_ENABLED=0 $(GO) build -o $(BINDIR)/rudder $(GOFLAGS) -tags '$(TAGS)' -ldflags '$(LDFLAGS)' k8s.io/helm/cmd/rudder | ||||
| 
 | ||||
| .PHONY: docker-build-experimental | ||||
| docker-build-experimental: check-docker docker-binary docker-binary-rudder | ||||
| 	docker build --rm -t ${IMAGE} rootfs -f rootfs/Dockerfile.experimental | ||||
| 	docker tag ${IMAGE} ${MUTABLE_IMAGE} | ||||
| 	docker build --rm -t ${IMAGE_RUDDER} rootfs -f rootfs/Dockerfile.rudder | ||||
| 	docker tag ${IMAGE_RUDDER} ${MUTABLE_IMAGE_RUDDER} | ||||
| 
 | ||||
| .PHONY: test | ||||
| test: build | ||||
| test: TESTFLAGS += -race -v | ||||
|  | @ -74,6 +88,8 @@ test: test-unit | |||
| 
 | ||||
| .PHONY: test-unit | ||||
| test-unit: | ||||
| 	@echo | ||||
| 	@echo "==> Running unit tests <==" | ||||
| 	HELM_HOME=/no/such/dir $(GO) test $(GOFLAGS) -run $(TESTS) $(PKG) $(TESTFLAGS) | ||||
| 
 | ||||
| .PHONY: test-style | ||||
|  |  | |||
|  | @ -33,9 +33,9 @@ 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.3.0-darwin-amd64.tar.gz) | ||||
| - [Linux](https://kubernetes-helm.storage.googleapis.com/helm-v2.3.0-linux-amd64.tar.gz) | ||||
| - [Linux 32-bit](https://kubernetes-helm.storage.googleapis.com/helm-v2.3.0-linux-386.tar.gz) | ||||
| - [OSX](https://kubernetes-helm.storage.googleapis.com/helm-v2.4.2-darwin-amd64.tar.gz) | ||||
| - [Linux](https://kubernetes-helm.storage.googleapis.com/helm-v2.4.2-linux-amd64.tar.gz) | ||||
| - [Linux 32-bit](https://kubernetes-helm.storage.googleapis.com/helm-v2.4.2-linux-386.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`. | ||||
|  | @ -45,7 +45,6 @@ To rapidly get Helm up and running, start with the [Quick Start Guide](docs/quic | |||
| See the [installation guide](docs/install.md) for more options, | ||||
| including installing pre-releases. | ||||
| 
 | ||||
| 
 | ||||
| ## Docs | ||||
| 
 | ||||
| Get started with the [Quick Start guide](docs/quickstart.md) or plunge into the [complete documentation](docs/index.md) | ||||
|  |  | |||
|  | @ -20,6 +20,10 @@ services_ias = $(subst $(space),$(comma),$(addsuffix =$(import_path)/$(services_ | |||
| services_pbs = $(sort $(wildcard hapi/services/*.proto)) | ||||
| services_pkg = services | ||||
| 
 | ||||
| rudder_ias = $(subst $(space),$(comma),$(addsuffix =$(import_path)/$(rudder_pkg),$(addprefix M,$(rudder_pbs)))) | ||||
| rudder_pbs = $(sort $(wildcard hapi/rudder/*.proto)) | ||||
| rudder_pkg = rudder | ||||
| 
 | ||||
| version_ias    = $(subst $(space),$(comma),$(addsuffix =$(import_path)/$(version_pkg),$(addprefix M,$(version_pbs)))) | ||||
| version_pbs    = $(sort $(wildcard hapi/version/*.proto)) | ||||
| version_pkg    = version | ||||
|  | @ -27,7 +31,7 @@ version_pkg    = version | |||
| google_deps	 = Mgoogle/protobuf/timestamp.proto=github.com/golang/protobuf/ptypes/timestamp,Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any | ||||
| 
 | ||||
| .PHONY: all | ||||
| all: chart release services version | ||||
| all: chart release services rudder version | ||||
| 
 | ||||
| .PHONY: chart | ||||
| chart: | ||||
|  | @ -41,6 +45,10 @@ release: | |||
| services: | ||||
| 	PATH=../bin:$(PATH) protoc --$(target)_out=plugins=$(plugins),$(google_deps),$(chart_ias),$(version_ias),$(release_ias):$(dst) $(services_pbs) | ||||
| 
 | ||||
| .PHONY: rudder | ||||
| rudder: | ||||
| 	PATH=../bin:$(PATH) protoc --$(target)_out=plugins=$(plugins),$(google_deps),$(chart_ias),$(version_ias),$(release_ias):$(dst) $(rudder_pbs) | ||||
| 
 | ||||
| .PHONY: version | ||||
| version: | ||||
| 	PATH=../bin:$(PATH) protoc --$(target)_out=plugins=$(plugins),$(google_deps):$(dst) $(version_pbs) | ||||
|  |  | |||
|  | @ -26,6 +26,7 @@ message TestRun { | |||
|         UNKNOWN = 0; | ||||
|         SUCCESS = 1; | ||||
|         FAILURE = 2; | ||||
|         RUNNING = 3; | ||||
|     } | ||||
| 
 | ||||
|     string name = 1; | ||||
|  |  | |||
|  | @ -0,0 +1,120 @@ | |||
| // Copyright 2017 The Kubernetes Authors All rights reserved. | ||||
| // | ||||
| // 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. | ||||
| 
 | ||||
| syntax = "proto3"; | ||||
| 
 | ||||
| package hapi.services.rudder; | ||||
| 
 | ||||
| import "hapi/release/info.proto"; | ||||
| import "hapi/release/release.proto"; | ||||
| 
 | ||||
| option go_package = "rudder"; | ||||
| 
 | ||||
| service ReleaseModuleService { | ||||
| 	rpc Version(VersionReleaseRequest) returns (VersionReleaseResponse)  { | ||||
| 	} | ||||
| 
 | ||||
| 	// InstallRelease requests installation of a chart as a new release. | ||||
| 	rpc InstallRelease(InstallReleaseRequest) returns (InstallReleaseResponse) { | ||||
| 	} | ||||
| 
 | ||||
| 	// DeleteRelease requests deletion of a named release. | ||||
| 	rpc DeleteRelease(DeleteReleaseRequest) returns (DeleteReleaseResponse) { | ||||
| 	} | ||||
| 
 | ||||
| 	// RollbackRelease rolls back a release to a previous version. | ||||
| 	rpc RollbackRelease(RollbackReleaseRequest) returns (RollbackReleaseResponse) { | ||||
| 	} | ||||
| 
 | ||||
| 	// UpgradeRelease updates release content. | ||||
| 	rpc UpgradeRelease(UpgradeReleaseRequest) returns (UpgradeReleaseResponse) { | ||||
| 	} | ||||
| 
 | ||||
| 	// ReleaseStatus retrieves release status. | ||||
| 	rpc ReleaseStatus(ReleaseStatusRequest) returns (ReleaseStatusResponse) { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| message Result { | ||||
| 	enum Status { | ||||
| 		// No status set | ||||
| 		UNKNOWN = 0; | ||||
| 		// Operation was successful | ||||
| 		SUCCESS = 1; | ||||
| 		// Operation had no results (e.g. upgrade identical, rollback to same, delete non-existent) | ||||
| 		UNCHANGED = 2; | ||||
| 		// Operation failed | ||||
| 		ERROR = 3; | ||||
| 	} | ||||
| 	string info = 1; | ||||
| 	repeated string log = 2; | ||||
| } | ||||
| 
 | ||||
| message VersionReleaseRequest { | ||||
| } | ||||
| 
 | ||||
| message VersionReleaseResponse { | ||||
| 	string name = 1;     // The canonical name of the release module | ||||
| 	string version = 2;  // The version of the release module | ||||
| } | ||||
| 
 | ||||
| message InstallReleaseRequest { | ||||
| 	hapi.release.Release release = 1; | ||||
| } | ||||
| message InstallReleaseResponse { | ||||
| 	hapi.release.Release release = 1; | ||||
| 	Result result = 2; | ||||
| } | ||||
| 
 | ||||
| message DeleteReleaseRequest { | ||||
| 	hapi.release.Release release = 1; | ||||
| } | ||||
| message DeleteReleaseResponse { | ||||
| 	hapi.release.Release release = 1; | ||||
| 	Result result = 2; | ||||
| } | ||||
| 
 | ||||
| message UpgradeReleaseRequest{ | ||||
|         hapi.release.Release current = 1; | ||||
|         hapi.release.Release target = 2; | ||||
|         int64 Timeout = 3; | ||||
|         bool Wait = 4; | ||||
|         bool Recreate = 5; | ||||
|         bool Force = 6; | ||||
| } | ||||
| message UpgradeReleaseResponse{ | ||||
| 	hapi.release.Release release = 1; | ||||
| 	Result result = 2; | ||||
| } | ||||
| 
 | ||||
| message RollbackReleaseRequest{ | ||||
|         hapi.release.Release current = 1; | ||||
|         hapi.release.Release target = 2; | ||||
|         int64 Timeout = 3; | ||||
|         bool Wait = 4; | ||||
|         bool Recreate = 5; | ||||
|         bool Force = 6; | ||||
| } | ||||
| message RollbackReleaseResponse{ | ||||
| 	hapi.release.Release release = 1; | ||||
| 	Result result = 2; | ||||
| } | ||||
| 
 | ||||
| message ReleaseStatusRequest{ | ||||
|         hapi.release.Release release = 1; | ||||
| } | ||||
| message ReleaseStatusResponse{ | ||||
| 	hapi.release.Release release = 1; | ||||
| 	hapi.release.Info info = 2; | ||||
| } | ||||
|  | @ -20,6 +20,7 @@ import "hapi/chart/chart.proto"; | |||
| import "hapi/chart/config.proto"; | ||||
| import "hapi/release/release.proto"; | ||||
| import "hapi/release/info.proto"; | ||||
| import "hapi/release/test_run.proto"; | ||||
| import "hapi/release/status.proto"; | ||||
| import "hapi/version/version.proto"; | ||||
| 
 | ||||
|  | @ -206,6 +207,8 @@ message UpdateReleaseRequest { | |||
| 	// ReuseValues will cause Tiller to reuse the values from the last release. | ||||
| 	// This is ignored if reset_values is set. | ||||
| 	bool reuse_values = 10; | ||||
| 	// Force resource update through delete/recreate if needed. | ||||
| 	bool force = 11; | ||||
| } | ||||
| 
 | ||||
| // UpdateReleaseResponse is the response to an update request. | ||||
|  | @ -229,6 +232,8 @@ message RollbackReleaseRequest { | |||
| 	// 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 = 7; | ||||
| 	// Force resource update through delete/recreate if needed. | ||||
| 	bool force = 8; | ||||
| } | ||||
| 
 | ||||
| // RollbackReleaseResponse is the response to an update request. | ||||
|  | @ -327,4 +332,6 @@ message TestReleaseRequest { | |||
| // TestReleaseResponse represents a message from executing a test | ||||
| message TestReleaseResponse { | ||||
| 	string msg = 1; | ||||
| 	hapi.release.TestRun.Status status = 2; | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ machine: | |||
|     - curl -sSL https://s3.amazonaws.com/circle-downloads/install-circleci-docker.sh | bash -s -- 1.10.0 | ||||
| 
 | ||||
|   environment: | ||||
|     GOVERSION: "1.7.5" | ||||
|     GOVERSION: "1.8.3" | ||||
|     GOPATH:  "${HOME}/.go_workspace" | ||||
|     WORKDIR: "${GOPATH}/src/k8s.io/helm" | ||||
|     PROJECT_NAME: "kubernetes-helm" | ||||
|  |  | |||
|  | @ -16,32 +16,214 @@ limitations under the License. | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 
 | ||||
| 	"github.com/spf13/cobra" | ||||
| ) | ||||
| 
 | ||||
| const completionDesc = ` | ||||
| Generate bash autocompletions script for Helm. | ||||
| Generate autocompletions script for Helm for the specified shell (bash or zsh). | ||||
| 
 | ||||
| This command can generate shell autocompletions. | ||||
| This command can generate shell autocompletions. e.g. | ||||
| 
 | ||||
| 	$ helm completion | ||||
| 	$ helm completion bash | ||||
| 
 | ||||
| Can be sourced as such | ||||
| 
 | ||||
| 	$ source <(helm completion) | ||||
| 	$ source <(helm completion bash) | ||||
| ` | ||||
| 
 | ||||
| func newCompletionCmd(out io.Writer) *cobra.Command { | ||||
| 	cmd := &cobra.Command{ | ||||
| 		Use:    "completion", | ||||
| 		Short:  "Generate bash autocompletions script", | ||||
| 		Long:   completionDesc, | ||||
| 		Hidden: false, | ||||
| 		RunE: func(cmd *cobra.Command, _ []string) error { | ||||
| 			return cmd.Root().GenBashCompletion(out) | ||||
| 		}, | ||||
| var ( | ||||
| 	completionShells = map[string]func(out io.Writer, cmd *cobra.Command) error{ | ||||
| 		"bash": runCompletionBash, | ||||
| 		"zsh":  runCompletionZsh, | ||||
| 	} | ||||
| ) | ||||
| 
 | ||||
| func newCompletionCmd(out io.Writer) *cobra.Command { | ||||
| 	shells := []string{} | ||||
| 	for s := range completionShells { | ||||
| 		shells = append(shells, s) | ||||
| 	} | ||||
| 
 | ||||
| 	cmd := &cobra.Command{ | ||||
| 		Use:   "completion SHELL", | ||||
| 		Short: "Generate autocompletions script for the specified shell (bash or zsh)", | ||||
| 		Long:  completionDesc, | ||||
| 		RunE: func(cmd *cobra.Command, args []string) error { | ||||
| 			return runCompletion(out, cmd, args) | ||||
| 		}, | ||||
| 		ValidArgs: shells, | ||||
| 	} | ||||
| 
 | ||||
| 	return cmd | ||||
| } | ||||
| 
 | ||||
| func runCompletion(out io.Writer, cmd *cobra.Command, args []string) error { | ||||
| 	if len(args) == 0 { | ||||
| 		return fmt.Errorf("shell not specified") | ||||
| 	} | ||||
| 	if len(args) > 1 { | ||||
| 		return fmt.Errorf("too many arguments, expected only the shell type") | ||||
| 	} | ||||
| 	run, found := completionShells[args[0]] | ||||
| 	if !found { | ||||
| 		return fmt.Errorf("unsupported shell type %q", args[0]) | ||||
| 	} | ||||
| 
 | ||||
| 	return run(out, cmd) | ||||
| } | ||||
| 
 | ||||
| func runCompletionBash(out io.Writer, cmd *cobra.Command) error { | ||||
| 	return cmd.Root().GenBashCompletion(out) | ||||
| } | ||||
| 
 | ||||
| func runCompletionZsh(out io.Writer, cmd *cobra.Command) error { | ||||
| 	zshInitialization := ` | ||||
| __helm_bash_source() { | ||||
| 	alias shopt=':' | ||||
| 	alias _expand=_bash_expand | ||||
| 	alias _complete=_bash_comp | ||||
| 	emulate -L sh | ||||
| 	setopt kshglob noshglob braceexpand | ||||
| 	source "$@" | ||||
| } | ||||
| __helm_type() { | ||||
| 	# -t is not supported by zsh | ||||
| 	if [ "$1" == "-t" ]; then | ||||
| 		shift | ||||
| 		# fake Bash 4 to disable "complete -o nospace". Instead | ||||
| 		# "compopt +-o nospace" is used in the code to toggle trailing | ||||
| 		# spaces. We don't support that, but leave trailing spaces on | ||||
| 		# all the time | ||||
| 		if [ "$1" = "__helm_compopt" ]; then | ||||
| 			echo builtin | ||||
| 			return 0 | ||||
| 		fi | ||||
| 	fi | ||||
| 	type "$@" | ||||
| } | ||||
| __helm_compgen() { | ||||
| 	local completions w | ||||
| 	completions=( $(compgen "$@") ) || return $? | ||||
| 	# filter by given word as prefix | ||||
| 	while [[ "$1" = -* && "$1" != -- ]]; do | ||||
| 		shift | ||||
| 		shift | ||||
| 	done | ||||
| 	if [[ "$1" == -- ]]; then | ||||
| 		shift | ||||
| 	fi | ||||
| 	for w in "${completions[@]}"; do | ||||
| 		if [[ "${w}" = "$1"* ]]; then | ||||
| 			echo "${w}" | ||||
| 		fi | ||||
| 	done | ||||
| } | ||||
| __helm_compopt() { | ||||
| 	true # don't do anything. Not supported by bashcompinit in zsh | ||||
| } | ||||
| __helm_declare() { | ||||
| 	if [ "$1" == "-F" ]; then | ||||
| 		whence -w "$@" | ||||
| 	else | ||||
| 		builtin declare "$@" | ||||
| 	fi | ||||
| } | ||||
| __helm_ltrim_colon_completions() | ||||
| { | ||||
| 	if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then | ||||
| 		# Remove colon-word prefix from COMPREPLY items | ||||
| 		local colon_word=${1%${1##*:}} | ||||
| 		local i=${#COMPREPLY[*]} | ||||
| 		while [[ $((--i)) -ge 0 ]]; do | ||||
| 			COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"} | ||||
| 		done | ||||
| 	fi | ||||
| } | ||||
| __helm_get_comp_words_by_ref() { | ||||
| 	cur="${COMP_WORDS[COMP_CWORD]}" | ||||
| 	prev="${COMP_WORDS[${COMP_CWORD}-1]}" | ||||
| 	words=("${COMP_WORDS[@]}") | ||||
| 	cword=("${COMP_CWORD[@]}") | ||||
| } | ||||
| __helm_filedir() { | ||||
| 	local RET OLD_IFS w qw | ||||
| 	__debug "_filedir $@ cur=$cur" | ||||
| 	if [[ "$1" = \~* ]]; then | ||||
| 		# somehow does not work. Maybe, zsh does not call this at all | ||||
| 		eval echo "$1" | ||||
| 		return 0 | ||||
| 	fi | ||||
| 	OLD_IFS="$IFS" | ||||
| 	IFS=$'\n' | ||||
| 	if [ "$1" = "-d" ]; then | ||||
| 		shift | ||||
| 		RET=( $(compgen -d) ) | ||||
| 	else | ||||
| 		RET=( $(compgen -f) ) | ||||
| 	fi | ||||
| 	IFS="$OLD_IFS" | ||||
| 	IFS="," __debug "RET=${RET[@]} len=${#RET[@]}" | ||||
| 	for w in ${RET[@]}; do | ||||
| 		if [[ ! "${w}" = "${cur}"* ]]; then | ||||
| 			continue | ||||
| 		fi | ||||
| 		if eval "[[ \"\${w}\" = *.$1 || -d \"\${w}\" ]]"; then | ||||
| 			qw="$(__helm_quote "${w}")" | ||||
| 			if [ -d "${w}" ]; then | ||||
| 				COMPREPLY+=("${qw}/") | ||||
| 			else | ||||
| 				COMPREPLY+=("${qw}") | ||||
| 			fi | ||||
| 		fi | ||||
| 	done | ||||
| } | ||||
| __helm_quote() { | ||||
| 	if [[ $1 == \'* || $1 == \"* ]]; then | ||||
| 		# Leave out first character | ||||
| 		printf %q "${1:1}" | ||||
| 	else | ||||
| 		printf %q "$1" | ||||
| 	fi | ||||
| } | ||||
| autoload -U +X bashcompinit && bashcompinit | ||||
| # use word boundary patterns for BSD or GNU sed | ||||
| LWORD='[[:<:]]' | ||||
| RWORD='[[:>:]]' | ||||
| if sed --help 2>&1 | grep -q GNU; then | ||||
| 	LWORD='\<' | ||||
| 	RWORD='\>' | ||||
| fi | ||||
| __helm_convert_bash_to_zsh() { | ||||
| 	sed \ | ||||
| 	-e 's/declare -F/whence -w/' \ | ||||
| 	-e 's/_get_comp_words_by_ref "\$@"/_get_comp_words_by_ref "\$*"/' \ | ||||
| 	-e 's/local \([a-zA-Z0-9_]*\)=/local \1; \1=/' \ | ||||
| 	-e 's/flags+=("\(--.*\)=")/flags+=("\1"); two_word_flags+=("\1")/' \ | ||||
| 	-e 's/must_have_one_flag+=("\(--.*\)=")/must_have_one_flag+=("\1")/' \ | ||||
| 	-e "s/${LWORD}_filedir${RWORD}/__helm_filedir/g" \ | ||||
| 	-e "s/${LWORD}_get_comp_words_by_ref${RWORD}/__helm_get_comp_words_by_ref/g" \ | ||||
| 	-e "s/${LWORD}__ltrim_colon_completions${RWORD}/__helm_ltrim_colon_completions/g" \ | ||||
| 	-e "s/${LWORD}compgen${RWORD}/__helm_compgen/g" \ | ||||
| 	-e "s/${LWORD}compopt${RWORD}/__helm_compopt/g" \ | ||||
| 	-e "s/${LWORD}declare${RWORD}/__helm_declare/g" \ | ||||
| 	-e "s/\\\$(type${RWORD}/\$(__helm_type/g" \ | ||||
| 	<<'BASH_COMPLETION_EOF' | ||||
| ` | ||||
| 	out.Write([]byte(zshInitialization)) | ||||
| 
 | ||||
| 	buf := new(bytes.Buffer) | ||||
| 	cmd.Root().GenBashCompletion(buf) | ||||
| 	out.Write(buf.Bytes()) | ||||
| 
 | ||||
| 	zshTail := ` | ||||
| BASH_COMPLETION_EOF | ||||
| } | ||||
| __helm_bash_source <(__helm_convert_bash_to_zsh) | ||||
| ` | ||||
| 	out.Write([]byte(zshTail)) | ||||
| 	return nil | ||||
| } | ||||
|  |  | |||
|  | @ -87,7 +87,7 @@ func TestCreateStarterCmd(t *testing.T) { | |||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	old := helmpath.Home(environment.DefaultHelmHome()) | ||||
| 	old := helmpath.Home(environment.DefaultHelmHome) | ||||
| 	settings.Home = thome | ||||
| 	defer func() { | ||||
| 		settings.Home = old | ||||
|  |  | |||
|  | @ -57,7 +57,7 @@ func newDeleteCmd(c helm.Interface, out io.Writer) *cobra.Command { | |||
| 		SuggestFor: []string{"remove", "rm"}, | ||||
| 		Short:      "given a release name, delete the release from Kubernetes", | ||||
| 		Long:       deleteDesc, | ||||
| 		PersistentPreRunE: setupConnection, | ||||
| 		PreRunE:    setupConnection, | ||||
| 		RunE: func(cmd *cobra.Command, args []string) error { | ||||
| 			if len(args) == 0 { | ||||
| 				return errors.New("command 'delete' requires a release name") | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ import ( | |||
| 	"github.com/spf13/cobra" | ||||
| 
 | ||||
| 	"k8s.io/helm/pkg/downloader" | ||||
| 	"k8s.io/helm/pkg/getter/defaultgetters" | ||||
| 	"k8s.io/helm/pkg/getter" | ||||
| 	"k8s.io/helm/pkg/helm/helmpath" | ||||
| ) | ||||
| 
 | ||||
|  | @ -77,7 +77,7 @@ func (d *dependencyBuildCmd) run() error { | |||
| 		ChartPath: d.chartpath, | ||||
| 		HelmHome:  d.helmhome, | ||||
| 		Keyring:   d.keyring, | ||||
| 		Getters:   defaultgetters.Get(settings), | ||||
| 		Getters:   getter.All(settings), | ||||
| 	} | ||||
| 	if d.verify { | ||||
| 		man.Verify = downloader.VerifyIfPossible | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ import ( | |||
| 
 | ||||
| 	"github.com/spf13/cobra" | ||||
| 	"k8s.io/helm/pkg/downloader" | ||||
| 	"k8s.io/helm/pkg/getter/defaultgetters" | ||||
| 	"k8s.io/helm/pkg/getter" | ||||
| 	"k8s.io/helm/pkg/helm/helmpath" | ||||
| ) | ||||
| 
 | ||||
|  | @ -95,7 +95,7 @@ func (d *dependencyUpdateCmd) run() error { | |||
| 		HelmHome:   d.helmhome, | ||||
| 		Keyring:    d.keyring, | ||||
| 		SkipUpdate: d.skipRefresh, | ||||
| 		Getters:    defaultgetters.Get(settings), | ||||
| 		Getters:    getter.All(settings), | ||||
| 	} | ||||
| 	if d.verify { | ||||
| 		man.Verify = downloader.VerifyIfPossible | ||||
|  |  | |||
|  | @ -26,7 +26,8 @@ import ( | |||
| 	"github.com/spf13/cobra" | ||||
| 	"k8s.io/helm/pkg/chartutil" | ||||
| 	"k8s.io/helm/pkg/downloader" | ||||
| 	"k8s.io/helm/pkg/getter/defaultgetters" | ||||
| 	"k8s.io/helm/pkg/getter" | ||||
| 	"k8s.io/helm/pkg/repo" | ||||
| ) | ||||
| 
 | ||||
| const fetchDesc = ` | ||||
|  | @ -50,11 +51,18 @@ type fetchCmd struct { | |||
| 	chartRef string | ||||
| 	destdir  string | ||||
| 	version  string | ||||
| 	repoURL  string | ||||
| 
 | ||||
| 	verify      bool | ||||
| 	verifyLater bool | ||||
| 	keyring     string | ||||
| 
 | ||||
| 	certFile string | ||||
| 	keyFile  string | ||||
| 	caFile   string | ||||
| 
 | ||||
| 	devel bool | ||||
| 
 | ||||
| 	out io.Writer | ||||
| } | ||||
| 
 | ||||
|  | @ -67,8 +75,14 @@ func newFetchCmd(out io.Writer) *cobra.Command { | |||
| 		Long:  fetchDesc, | ||||
| 		RunE: func(cmd *cobra.Command, args []string) error { | ||||
| 			if len(args) == 0 { | ||||
| 				return fmt.Errorf("This command needs at least one argument, url or repo/name of the chart.") | ||||
| 				return fmt.Errorf("need at least one argument, url or repo/name of the chart") | ||||
| 			} | ||||
| 
 | ||||
| 			if fch.version == "" && fch.devel { | ||||
| 				debug("setting version to >0.0.0-a") | ||||
| 				fch.version = ">0.0.0-a" | ||||
| 			} | ||||
| 
 | ||||
| 			for i := 0; i < len(args); i++ { | ||||
| 				fch.chartRef = args[i] | ||||
| 				if err := fch.run(); err != nil { | ||||
|  | @ -87,6 +101,11 @@ func newFetchCmd(out io.Writer) *cobra.Command { | |||
| 	f.StringVar(&fch.version, "version", "", "specific version of a chart. Without this, the latest version is fetched") | ||||
| 	f.StringVar(&fch.keyring, "keyring", defaultKeyring(), "keyring containing public keys") | ||||
| 	f.StringVarP(&fch.destdir, "destination", "d", ".", "location to write the chart. If this and tardir are specified, tardir is appended to this") | ||||
| 	f.StringVar(&fch.repoURL, "repo", "", "chart repository url where to locate the requested chart") | ||||
| 	f.StringVar(&fch.certFile, "cert-file", "", "identify HTTPS client using this SSL certificate file") | ||||
| 	f.StringVar(&fch.keyFile, "key-file", "", "identify HTTPS client using this SSL key file") | ||||
| 	f.StringVar(&fch.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle") | ||||
| 	f.BoolVar(&fch.devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-a'. If --version is set, this is ignored.") | ||||
| 
 | ||||
| 	return cmd | ||||
| } | ||||
|  | @ -97,7 +116,7 @@ func (f *fetchCmd) run() error { | |||
| 		Out:      f.out, | ||||
| 		Keyring:  f.keyring, | ||||
| 		Verify:   downloader.VerifyNever, | ||||
| 		Getters:  defaultgetters.Get(settings), | ||||
| 		Getters:  getter.All(settings), | ||||
| 	} | ||||
| 
 | ||||
| 	if f.verify { | ||||
|  | @ -118,6 +137,14 @@ func (f *fetchCmd) run() error { | |||
| 		defer os.RemoveAll(dest) | ||||
| 	} | ||||
| 
 | ||||
| 	if f.repoURL != "" { | ||||
| 		chartURL, err := repo.FindChartInRepoURL(f.repoURL, f.chartRef, f.version, f.certFile, f.keyFile, f.caFile, getter.All(settings)) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		f.chartRef = chartURL | ||||
| 	} | ||||
| 
 | ||||
| 	saved, v, err := c.DownloadTo(f.chartRef, f.version, dest) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
|  |  | |||
|  | @ -34,12 +34,14 @@ func TestFetchCmd(t *testing.T) { | |||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	old := helmpath.Home(environment.DefaultHelmHome()) | ||||
| 	old := helmpath.Home(environment.DefaultHelmHome) | ||||
| 	settings.Home = hh | ||||
| 	defer func() { | ||||
| 		settings.Home = old | ||||
| 		os.RemoveAll(hh.String()) | ||||
| 	}() | ||||
| 	srv := repotest.NewServer(hh.String()) | ||||
| 	defer srv.Stop() | ||||
| 
 | ||||
| 	// all flags will get "--home=TMDIR -d outdir" appended.
 | ||||
| 	tests := []struct { | ||||
|  | @ -105,11 +107,34 @@ func TestFetchCmd(t *testing.T) { | |||
| 			expectDir:    true, | ||||
| 			expectVerify: true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:       "Chart fetch using repo URL", | ||||
| 			chart:      "signtest", | ||||
| 			expectFile: "./signtest-0.1.0.tgz", | ||||
| 			flags:      []string{"--repo", srv.URL()}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:       "Fail fetching non-existent chart on repo URL", | ||||
| 			chart:      "someChart", | ||||
| 			flags:      []string{"--repo", srv.URL()}, | ||||
| 			failExpect: "Failed to fetch chart", | ||||
| 			fail:       true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:       "Specific version chart fetch using repo URL", | ||||
| 			chart:      "signtest", | ||||
| 			expectFile: "./signtest-0.1.0.tgz", | ||||
| 			flags:      []string{"--repo", srv.URL(), "--version", "0.1.0"}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:       "Specific version chart fetch using repo URL", | ||||
| 			chart:      "signtest", | ||||
| 			flags:      []string{"--repo", srv.URL(), "--version", "0.2.0"}, | ||||
| 			failExpect: "Failed to fetch chart version", | ||||
| 			fail:       true, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	srv := repotest.NewServer(hh.String()) | ||||
| 	defer srv.Stop() | ||||
| 
 | ||||
| 	if _, err := srv.CopyCharts("testdata/testcharts/*.tgz*"); err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  |  | |||
|  | @ -57,7 +57,7 @@ func newGetCmd(client helm.Interface, out io.Writer) *cobra.Command { | |||
| 		Use:     "get [flags] RELEASE_NAME", | ||||
| 		Short:   "download a named release", | ||||
| 		Long:    getHelp, | ||||
| 		PersistentPreRunE: setupConnection, | ||||
| 		PreRunE: setupConnection, | ||||
| 		RunE: func(cmd *cobra.Command, args []string) error { | ||||
| 			if len(args) == 0 { | ||||
| 				return errReleaseRequired | ||||
|  |  | |||
|  | @ -19,7 +19,6 @@ package main // import "k8s.io/helm/cmd/helm" | |||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"log" | ||||
| 	"os" | ||||
|  | @ -33,30 +32,22 @@ import ( | |||
| 
 | ||||
| 	"k8s.io/helm/pkg/helm" | ||||
| 	helm_env "k8s.io/helm/pkg/helm/environment" | ||||
| 	"k8s.io/helm/pkg/helm/helmpath" | ||||
| 	"k8s.io/helm/pkg/helm/portforwarder" | ||||
| 	"k8s.io/helm/pkg/kube" | ||||
| 	tiller_env "k8s.io/helm/pkg/tiller/environment" | ||||
| 	"k8s.io/helm/pkg/tlsutil" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	localRepoIndexFilePath = "index.yaml" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	tlsCaCertFile string // path to TLS CA certificate file
 | ||||
| 	tlsCertFile   string // path to TLS certificate file
 | ||||
| 	tlsKeyFile    string // path to TLS key file
 | ||||
| 	tlsVerify     bool   // enable TLS and verify remote certificates
 | ||||
| 	tlsEnable     bool   // enable TLS
 | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	kubeContext  string | ||||
| 	settings    helm_env.EnvSettings | ||||
| 	// TODO refactor out this global var
 | ||||
| 	tillerTunnel *kube.Tunnel | ||||
| 	settings     helm_env.EnvSettings | ||||
| ) | ||||
| 
 | ||||
| var globalUsage = `The Kubernetes package manager | ||||
|  | @ -83,37 +74,58 @@ Environment: | |||
|   $KUBECONFIG         set an alternative Kubernetes configuration file (default "~/.kube/config") | ||||
| ` | ||||
| 
 | ||||
| func newRootCmd(out io.Writer) *cobra.Command { | ||||
| 	var helmHomeTemp string | ||||
| func setFlagFromEnv(name, envar string, cmd *cobra.Command) { | ||||
| 	if cmd.Flags().Changed(name) { | ||||
| 		return | ||||
| 	} | ||||
| 	if v, ok := os.LookupEnv(envar); ok { | ||||
| 		cmd.Flags().Set(name, v) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func setFlagsFromEnv(flags map[string]string, cmd *cobra.Command) { | ||||
| 	for name, envar := range flags { | ||||
| 		setFlagFromEnv(name, envar, cmd) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func addRootFlags(cmd *cobra.Command) { | ||||
| 	pf := cmd.PersistentFlags() | ||||
| 	pf.StringVar((*string)(&settings.Home), "home", helm_env.DefaultHelmHome, "location of your Helm config. Overrides $HELM_HOME") | ||||
| 	pf.StringVar(&settings.TillerHost, "host", "", "address of tiller. Overrides $HELM_HOST") | ||||
| 	pf.StringVar(&kubeContext, "kube-context", "", "name of the kubeconfig context to use") | ||||
| 	pf.BoolVar(&settings.Debug, "debug", false, "enable verbose output") | ||||
| 	pf.StringVar(&settings.TillerNamespace, "tiller-namespace", tiller_env.DefaultTillerNamespace, "namespace of tiller") | ||||
| } | ||||
| 
 | ||||
| func initRootFlags(cmd *cobra.Command) { | ||||
| 	setFlagsFromEnv(map[string]string{ | ||||
| 		"debug":            helm_env.DebugEnvVar, | ||||
| 		"home":             helm_env.HomeEnvVar, | ||||
| 		"host":             helm_env.HostEnvVar, | ||||
| 		"tiller-namespace": tiller_env.TillerNamespaceEnvVar, | ||||
| 	}, cmd.Root()) | ||||
| 
 | ||||
| 	tlsCaCertFile = os.ExpandEnv(tlsCaCertFile) | ||||
| 	tlsCertFile = os.ExpandEnv(tlsCertFile) | ||||
| 	tlsKeyFile = os.ExpandEnv(tlsKeyFile) | ||||
| } | ||||
| 
 | ||||
| func newRootCmd() *cobra.Command { | ||||
| 	cmd := &cobra.Command{ | ||||
| 		Use:          "helm", | ||||
| 		Short:        "The Helm package manager for Kubernetes.", | ||||
| 		Long:         globalUsage, | ||||
| 		SilenceUsage: true, | ||||
| 		PersistentPreRun: func(cmd *cobra.Command, args []string) { | ||||
| 			tlsCaCertFile = os.ExpandEnv(tlsCaCertFile) | ||||
| 			tlsCertFile = os.ExpandEnv(tlsCertFile) | ||||
| 			tlsKeyFile = os.ExpandEnv(tlsKeyFile) | ||||
| 		PersistentPreRun: func(cmd *cobra.Command, _ []string) { | ||||
| 			initRootFlags(cmd) | ||||
| 		}, | ||||
| 		PersistentPostRun: func(cmd *cobra.Command, args []string) { | ||||
| 		PersistentPostRun: func(*cobra.Command, []string) { | ||||
| 			teardown() | ||||
| 		}, | ||||
| 	} | ||||
| 	p := cmd.PersistentFlags() | ||||
| 	p.StringVar(&helmHomeTemp, "home", helm_env.DefaultHelmHome(), "location of your Helm config. Overrides $HELM_HOME") | ||||
| 	settings.Home = helmpath.Home(helmHomeTemp) | ||||
| 	p.StringVar(&settings.TillerHost, "host", helm_env.DefaultHelmHost(), "address of tiller. Overrides $HELM_HOST") | ||||
| 	p.StringVar(&kubeContext, "kube-context", "", "name of the kubeconfig context to use") | ||||
| 	p.BoolVar(&settings.Debug, "debug", false, "enable verbose output") | ||||
| 	p.StringVar(&settings.TillerNamespace, "tiller-namespace", tiller_env.GetTillerNamespace(), "namespace of tiller") | ||||
| 
 | ||||
| 	if os.Getenv(helm_env.PluginDisableEnvVar) != "1" { | ||||
| 		settings.PlugDirs = os.Getenv(helm_env.PluginEnvVar) | ||||
| 		if settings.PlugDirs == "" { | ||||
| 			settings.PlugDirs = settings.Home.Plugins() | ||||
| 		} | ||||
| 	} | ||||
| 	addRootFlags(cmd) | ||||
| 	out := cmd.OutOrStdout() | ||||
| 
 | ||||
| 	cmd.AddCommand( | ||||
| 		// chart commands
 | ||||
|  | @ -166,7 +178,7 @@ func init() { | |||
| } | ||||
| 
 | ||||
| func main() { | ||||
| 	cmd := newRootCmd(os.Stdout) | ||||
| 	cmd := newRootCmd() | ||||
| 	if err := cmd.Execute(); err != nil { | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
|  |  | |||
|  | @ -23,7 +23,9 @@ import ( | |||
| 	"io/ioutil" | ||||
| 	"math/rand" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"regexp" | ||||
| 	"sync" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/golang/protobuf/ptypes/timestamp" | ||||
|  | @ -123,6 +125,7 @@ func releaseMock(opts *releaseOptions) *release.Release { | |||
| 
 | ||||
| type fakeReleaseClient struct { | ||||
| 	rels      []*release.Release | ||||
| 	responses map[string]release.TestRun_Status | ||||
| 	err       error | ||||
| } | ||||
| 
 | ||||
|  | @ -198,7 +201,27 @@ func (c *fakeReleaseClient) ReleaseHistory(rlsName string, opts ...helm.HistoryO | |||
| } | ||||
| 
 | ||||
| func (c *fakeReleaseClient) RunReleaseTest(rlsName string, opts ...helm.ReleaseTestOption) (<-chan *rls.TestReleaseResponse, <-chan error) { | ||||
| 	return nil, nil | ||||
| 
 | ||||
| 	results := make(chan *rls.TestReleaseResponse) | ||||
| 	errc := make(chan error, 1) | ||||
| 
 | ||||
| 	go func() { | ||||
| 		var wg sync.WaitGroup | ||||
| 		for m, s := range c.responses { | ||||
| 			wg.Add(1) | ||||
| 
 | ||||
| 			go func(msg string, status release.TestRun_Status) { | ||||
| 				defer wg.Done() | ||||
| 				results <- &rls.TestReleaseResponse{Msg: msg, Status: status} | ||||
| 			}(m, s) | ||||
| 		} | ||||
| 
 | ||||
| 		wg.Wait() | ||||
| 		close(results) | ||||
| 		close(errc) | ||||
| 	}() | ||||
| 
 | ||||
| 	return results, errc | ||||
| } | ||||
| 
 | ||||
| func (c *fakeReleaseClient) Option(opt ...helm.Option) helm.Interface { | ||||
|  | @ -299,7 +322,7 @@ func ensureTestHome(home helmpath.Home, t *testing.T) error { | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	localRepoIndexFile := home.LocalRepository(localRepoIndexFilePath) | ||||
| 	localRepoIndexFile := home.LocalRepository(localRepositoryIndexFile) | ||||
| 	if fi, err := os.Stat(localRepoIndexFile); err != nil { | ||||
| 		i := repo.NewIndexFile() | ||||
| 		if err := i.WriteFile(localRepoIndexFile, 0644); err != nil { | ||||
|  | @ -315,3 +338,79 @@ func ensureTestHome(home helmpath.Home, t *testing.T) error { | |||
| 	t.Logf("$HELM_HOME has been configured at %s.\n", settings.Home.String()) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func TestRootCmd(t *testing.T) { | ||||
| 	oldhome := os.Getenv("HELM_HOME") | ||||
| 	defer os.Setenv("HELM_HOME", oldhome) | ||||
| 
 | ||||
| 	tests := []struct { | ||||
| 		name   string | ||||
| 		args   []string | ||||
| 		envars map[string]string | ||||
| 		home   string | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name: "defaults", | ||||
| 			args: []string{"home"}, | ||||
| 			home: filepath.Join(os.Getenv("HOME"), "/.helm"), | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "with --home set", | ||||
| 			args: []string{"--home", "/foo"}, | ||||
| 			home: "/foo", | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "subcommands with --home set", | ||||
| 			args: []string{"home", "--home", "/foo"}, | ||||
| 			home: "/foo", | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:   "with $HELM_HOME set", | ||||
| 			args:   []string{"home"}, | ||||
| 			envars: map[string]string{"HELM_HOME": "/bar"}, | ||||
| 			home:   "/bar", | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:   "subcommands with $HELM_HOME set", | ||||
| 			args:   []string{"home"}, | ||||
| 			envars: map[string]string{"HELM_HOME": "/bar"}, | ||||
| 			home:   "/bar", | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:   "with $HELM_HOME and --home set", | ||||
| 			args:   []string{"home", "--home", "/foo"}, | ||||
| 			envars: map[string]string{"HELM_HOME": "/bar"}, | ||||
| 			home:   "/foo", | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	// ensure not set locally
 | ||||
| 	os.Unsetenv("HELM_HOME") | ||||
| 
 | ||||
| 	for _, tt := range tests { | ||||
| 		t.Run(tt.name, func(t *testing.T) { | ||||
| 			defer os.Unsetenv("HELM_HOME") | ||||
| 
 | ||||
| 			for k, v := range tt.envars { | ||||
| 				os.Setenv(k, v) | ||||
| 			} | ||||
| 
 | ||||
| 			cmd := newRootCmd() | ||||
| 			cmd.SetOutput(ioutil.Discard) | ||||
| 			cmd.SetArgs(tt.args) | ||||
| 			cmd.Run = func(*cobra.Command, []string) {} | ||||
| 			if err := cmd.Execute(); err != nil { | ||||
| 				t.Errorf("unexpected error: %s", err) | ||||
| 			} | ||||
| 
 | ||||
| 			if settings.Home.String() != tt.home { | ||||
| 				t.Errorf("expected home %q, got %q", tt.home, settings.Home) | ||||
| 			} | ||||
| 			homeFlag := cmd.Flag("home").Value.String() | ||||
| 			homeFlag = os.ExpandEnv(homeFlag) | ||||
| 			if homeFlag != tt.home { | ||||
| 				t.Errorf("expected home %q, got %q", tt.home, homeFlag) | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -60,7 +60,7 @@ func newHistoryCmd(c helm.Interface, w io.Writer) *cobra.Command { | |||
| 		Long:    historyHelp, | ||||
| 		Short:   "fetch release history", | ||||
| 		Aliases: []string{"hist"}, | ||||
| 		PersistentPreRunE: setupConnection, | ||||
| 		PreRunE: setupConnection, | ||||
| 		RunE: func(cmd *cobra.Command, args []string) error { | ||||
| 			switch { | ||||
| 			case len(args) == 0: | ||||
|  |  | |||
|  | @ -35,7 +35,7 @@ func newHomeCmd(out io.Writer) *cobra.Command { | |||
| 		Long:  longHomeHelp, | ||||
| 		Run: func(cmd *cobra.Command, args []string) { | ||||
| 			h := settings.Home | ||||
| 			fmt.Fprintf(out, "%s\n", h) | ||||
| 			fmt.Fprintln(out, h) | ||||
| 			if settings.Debug { | ||||
| 				fmt.Fprintf(out, "Repository: %s\n", h.Repository()) | ||||
| 				fmt.Fprintf(out, "RepositoryFile: %s\n", h.RepositoryFile()) | ||||
|  | @ -47,6 +47,5 @@ func newHomeCmd(out io.Writer) *cobra.Command { | |||
| 			} | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	return cmd | ||||
| } | ||||
|  |  | |||
|  | @ -27,7 +27,7 @@ import ( | |||
| 	"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" | ||||
| 
 | ||||
| 	"k8s.io/helm/cmd/helm/installer" | ||||
| 	"k8s.io/helm/pkg/getter/defaultgetters" | ||||
| 	"k8s.io/helm/pkg/getter" | ||||
| 	"k8s.io/helm/pkg/helm/helmpath" | ||||
| 	"k8s.io/helm/pkg/repo" | ||||
| ) | ||||
|  | @ -56,6 +56,7 @@ To dump a manifest containing the Tiller deployment YAML, combine the | |||
| const ( | ||||
| 	stableRepository         = "stable" | ||||
| 	localRepository          = "local" | ||||
| 	localRepositoryIndexFile = "index.yaml" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
|  | @ -77,6 +78,7 @@ type initCmd struct { | |||
| 	home           helmpath.Home | ||||
| 	opts           installer.Options | ||||
| 	kubeClient     internalclientset.Interface | ||||
| 	serviceAccount string | ||||
| } | ||||
| 
 | ||||
| func newInitCmd(out io.Writer) *cobra.Command { | ||||
|  | @ -116,6 +118,7 @@ func newInitCmd(out io.Writer) *cobra.Command { | |||
| 	f.StringVar(&localRepositoryURL, "local-repo-url", localRepositoryURL, "URL for local repository") | ||||
| 
 | ||||
| 	f.BoolVar(&i.opts.EnableHostNetwork, "net-host", false, "install tiller with net=host") | ||||
| 	f.StringVar(&i.serviceAccount, "service-account", "", "name of service account") | ||||
| 
 | ||||
| 	return cmd | ||||
| } | ||||
|  | @ -154,6 +157,7 @@ func (i *initCmd) run() error { | |||
| 	i.opts.Namespace = i.namespace | ||||
| 	i.opts.UseCanary = i.canary | ||||
| 	i.opts.ImageSpec = i.image | ||||
| 	i.opts.ServiceAccount = i.serviceAccount | ||||
| 
 | ||||
| 	if settings.Debug { | ||||
| 		writeYAMLManifest := func(apiVersion, kind, body string, first, last bool) error { | ||||
|  | @ -293,7 +297,7 @@ func ensureDefaultRepos(home helmpath.Home, out io.Writer, skipRefresh bool) err | |||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		lr, err := initLocalRepo(home.LocalRepository(localRepoIndexFilePath), home.CacheIndex("local")) | ||||
| 		lr, err := initLocalRepo(home.LocalRepository(localRepositoryIndexFile), home.CacheIndex("local")) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | @ -314,7 +318,7 @@ func initStableRepo(cacheFile string, skipRefresh bool) (*repo.Entry, error) { | |||
| 		URL:   stableRepositoryURL, | ||||
| 		Cache: cacheFile, | ||||
| 	} | ||||
| 	r, err := repo.NewChartRepository(&c, defaultgetters.Get(settings)) | ||||
| 	r, err := repo.NewChartRepository(&c, getter.All(settings)) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  |  | |||
|  | @ -214,7 +214,7 @@ func TestEnsureHome(t *testing.T) { | |||
| 		t.Errorf("%s should not be a directory", fi) | ||||
| 	} | ||||
| 
 | ||||
| 	if fi, err := os.Stat(hh.LocalRepository(localRepoIndexFilePath)); err != nil { | ||||
| 	if fi, err := os.Stat(hh.LocalRepository(localRepositoryIndexFile)); err != nil { | ||||
| 		t.Errorf("%s", err) | ||||
| 	} else if fi.IsDir() { | ||||
| 		t.Errorf("%s should not be a directory", fi) | ||||
|  |  | |||
|  | @ -50,6 +50,11 @@ type inspectCmd struct { | |||
| 	keyring   string | ||||
| 	out       io.Writer | ||||
| 	version   string | ||||
| 	repoURL   string | ||||
| 
 | ||||
| 	certFile string | ||||
| 	keyFile  string | ||||
| 	caFile   string | ||||
| } | ||||
| 
 | ||||
| const ( | ||||
|  | @ -72,7 +77,8 @@ func newInspectCmd(out io.Writer) *cobra.Command { | |||
| 			if err := checkArgsLength(len(args), "chart name"); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			cp, err := locateChartPath(args[0], insp.version, insp.verify, insp.keyring) | ||||
| 			cp, err := locateChartPath(insp.repoURL, args[0], insp.version, insp.verify, insp.keyring, | ||||
| 				insp.certFile, insp.keyFile, insp.caFile) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
|  | @ -90,7 +96,8 @@ func newInspectCmd(out io.Writer) *cobra.Command { | |||
| 			if err := checkArgsLength(len(args), "chart name"); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			cp, err := locateChartPath(args[0], insp.version, insp.verify, insp.keyring) | ||||
| 			cp, err := locateChartPath(insp.repoURL, args[0], insp.version, insp.verify, insp.keyring, | ||||
| 				insp.certFile, insp.keyFile, insp.caFile) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
|  | @ -108,7 +115,8 @@ func newInspectCmd(out io.Writer) *cobra.Command { | |||
| 			if err := checkArgsLength(len(args), "chart name"); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			cp, err := locateChartPath(args[0], insp.version, insp.verify, insp.keyring) | ||||
| 			cp, err := locateChartPath(insp.repoURL, args[0], insp.version, insp.verify, insp.keyring, | ||||
| 				insp.certFile, insp.keyFile, insp.caFile) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
|  | @ -136,6 +144,30 @@ func newInspectCmd(out io.Writer) *cobra.Command { | |||
| 	valuesSubCmd.Flags().StringVar(&insp.version, verflag, "", verdesc) | ||||
| 	chartSubCmd.Flags().StringVar(&insp.version, verflag, "", verdesc) | ||||
| 
 | ||||
| 	repoURL := "repo" | ||||
| 	repoURLdesc := "chart repository url where to locate the requested chart" | ||||
| 	inspectCommand.Flags().StringVar(&insp.repoURL, repoURL, "", repoURLdesc) | ||||
| 	valuesSubCmd.Flags().StringVar(&insp.repoURL, repoURL, "", repoURLdesc) | ||||
| 	chartSubCmd.Flags().StringVar(&insp.repoURL, repoURL, "", repoURLdesc) | ||||
| 
 | ||||
| 	certFile := "cert-file" | ||||
| 	certFiledesc := "verify certificates of HTTPS-enabled servers using this CA bundle" | ||||
| 	inspectCommand.Flags().StringVar(&insp.certFile, certFile, "", certFiledesc) | ||||
| 	valuesSubCmd.Flags().StringVar(&insp.certFile, certFile, "", certFiledesc) | ||||
| 	chartSubCmd.Flags().StringVar(&insp.certFile, certFile, "", certFiledesc) | ||||
| 
 | ||||
| 	keyFile := "key-file" | ||||
| 	keyFiledesc := "identify HTTPS client using this SSL key file" | ||||
| 	inspectCommand.Flags().StringVar(&insp.keyFile, keyFile, "", keyFiledesc) | ||||
| 	valuesSubCmd.Flags().StringVar(&insp.keyFile, keyFile, "", keyFiledesc) | ||||
| 	chartSubCmd.Flags().StringVar(&insp.keyFile, keyFile, "", keyFiledesc) | ||||
| 
 | ||||
| 	caFile := "ca-file" | ||||
| 	caFiledesc := "chart repository url where to locate the requested chart" | ||||
| 	inspectCommand.Flags().StringVar(&insp.caFile, caFile, "", caFiledesc) | ||||
| 	valuesSubCmd.Flags().StringVar(&insp.caFile, caFile, "", caFiledesc) | ||||
| 	chartSubCmd.Flags().StringVar(&insp.caFile, caFile, "", caFiledesc) | ||||
| 
 | ||||
| 	inspectCommand.AddCommand(valuesSubCmd) | ||||
| 	inspectCommand.AddCommand(chartSubCmd) | ||||
| 
 | ||||
|  |  | |||
|  | @ -34,11 +34,12 @@ import ( | |||
| 
 | ||||
| 	"k8s.io/helm/pkg/chartutil" | ||||
| 	"k8s.io/helm/pkg/downloader" | ||||
| 	"k8s.io/helm/pkg/getter/defaultgetters" | ||||
| 	"k8s.io/helm/pkg/getter" | ||||
| 	"k8s.io/helm/pkg/helm" | ||||
| 	"k8s.io/helm/pkg/kube" | ||||
| 	"k8s.io/helm/pkg/proto/hapi/chart" | ||||
| 	"k8s.io/helm/pkg/proto/hapi/release" | ||||
| 	"k8s.io/helm/pkg/repo" | ||||
| 	"k8s.io/helm/pkg/strvals" | ||||
| ) | ||||
| 
 | ||||
|  | @ -115,6 +116,12 @@ type installCmd struct { | |||
| 	version      string | ||||
| 	timeout      int64 | ||||
| 	wait         bool | ||||
| 	repoURL      string | ||||
| 	devel        bool | ||||
| 
 | ||||
| 	certFile string | ||||
| 	keyFile  string | ||||
| 	caFile   string | ||||
| } | ||||
| 
 | ||||
| type valueFiles []string | ||||
|  | @ -144,12 +151,20 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command { | |||
| 		Use:     "install [CHART]", | ||||
| 		Short:   "install a chart archive", | ||||
| 		Long:    installDesc, | ||||
| 		PersistentPreRunE: setupConnection, | ||||
| 		PreRunE: setupConnection, | ||||
| 		RunE: func(cmd *cobra.Command, args []string) error { | ||||
| 			if err := checkArgsLength(len(args), "chart name"); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			cp, err := locateChartPath(args[0], inst.version, inst.verify, inst.keyring) | ||||
| 
 | ||||
| 			debug("Original chart version: %q", inst.version) | ||||
| 			if inst.version == "" && inst.devel { | ||||
| 				debug("setting version to >0.0.0-a") | ||||
| 				inst.version = ">0.0.0-a" | ||||
| 			} | ||||
| 
 | ||||
| 			cp, err := locateChartPath(inst.repoURL, args[0], inst.version, inst.verify, inst.keyring, | ||||
| 				inst.certFile, inst.keyFile, inst.caFile) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
|  | @ -173,6 +188,11 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command { | |||
| 	f.StringVar(&inst.version, "version", "", "specify the exact chart version to install. If this is not specified, the latest version is installed") | ||||
| 	f.Int64Var(&inst.timeout, "timeout", 300, "time in seconds to wait for any individual kubernetes operation (like Jobs for hooks)") | ||||
| 	f.BoolVar(&inst.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(&inst.repoURL, "repo", "", "chart repository url where to locate the requested chart") | ||||
| 	f.StringVar(&inst.certFile, "cert-file", "", "identify HTTPS client using this SSL certificate file") | ||||
| 	f.StringVar(&inst.keyFile, "key-file", "", "identify HTTPS client using this SSL key file") | ||||
| 	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-a'. If --version is set, this is ignored.") | ||||
| 
 | ||||
| 	return cmd | ||||
| } | ||||
|  | @ -206,7 +226,14 @@ func (i *installCmd) run() error { | |||
| 	} | ||||
| 
 | ||||
| 	if req, err := chartutil.LoadRequirements(chartRequested); err == nil { | ||||
| 		checkDependencies(chartRequested, req, i.out) | ||||
| 		// If checkDependencies returns an error, we have unfullfilled dependencies.
 | ||||
| 		// As of Helm 2.4.0, this is treated as a stopping condition:
 | ||||
| 		// https://github.com/kubernetes/helm/issues/2209
 | ||||
| 		if err := checkDependencies(chartRequested, req, i.out); err != nil { | ||||
| 			return prettyError(err) | ||||
| 		} | ||||
| 	} else if err != chartutil.ErrRequirementsNotFound { | ||||
| 		return fmt.Errorf("cannot load requirements: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	res, err := i.client.InstallReleaseFromChart( | ||||
|  | @ -326,7 +353,8 @@ func (i *installCmd) printRelease(rel *release.Release) { | |||
| // - URL
 | ||||
| //
 | ||||
| // If 'verify' is true, this will attempt to also verify the chart.
 | ||||
| func locateChartPath(name, version string, verify bool, keyring string) (string, error) { | ||||
| func locateChartPath(repoURL, name, version string, verify bool, keyring, | ||||
| 	certFile, keyFile, caFile string) (string, error) { | ||||
| 	name = strings.TrimSpace(name) | ||||
| 	version = strings.TrimSpace(version) | ||||
| 	if fi, err := os.Stat(name); err == nil { | ||||
|  | @ -357,11 +385,19 @@ func locateChartPath(name, version string, verify bool, keyring string) (string, | |||
| 		HelmHome: settings.Home, | ||||
| 		Out:      os.Stdout, | ||||
| 		Keyring:  keyring, | ||||
| 		Getters:  defaultgetters.Get(settings), | ||||
| 		Getters:  getter.All(settings), | ||||
| 	} | ||||
| 	if verify { | ||||
| 		dl.Verify = downloader.VerifyAlways | ||||
| 	} | ||||
| 	if repoURL != "" { | ||||
| 		chartURL, err := repo.FindChartInRepoURL(repoURL, name, version, | ||||
| 			certFile, keyFile, caFile, getter.All(settings)) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 		name = chartURL | ||||
| 	} | ||||
| 
 | ||||
| 	filename, _, err := dl.DownloadTo(name, version, ".") | ||||
| 	if err == nil { | ||||
|  | @ -398,7 +434,9 @@ func defaultNamespace() string { | |||
| 	return "default" | ||||
| } | ||||
| 
 | ||||
| func checkDependencies(ch *chart.Chart, reqs *chartutil.Requirements, out io.Writer) { | ||||
| func checkDependencies(ch *chart.Chart, reqs *chartutil.Requirements, out io.Writer) error { | ||||
| 	missing := []string{} | ||||
| 
 | ||||
| 	deps := ch.GetDependencies() | ||||
| 	for _, r := range reqs.Dependencies { | ||||
| 		found := false | ||||
|  | @ -409,7 +447,12 @@ func checkDependencies(ch *chart.Chart, reqs *chartutil.Requirements, out io.Wri | |||
| 			} | ||||
| 		} | ||||
| 		if !found { | ||||
| 			fmt.Fprintf(out, "Warning: %s is in requirements.yaml but not in the charts/ directory!\n", r.Name) | ||||
| 			missing = append(missing, r.Name) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if len(missing) > 0 { | ||||
| 		return fmt.Errorf("found in requirements.yaml, but missing in charts/ directory: %s", strings.Join(missing, ", ")) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  |  | |||
|  | @ -136,7 +136,13 @@ func TestInstall(t *testing.T) { | |||
| 		{ | ||||
| 			name: "install chart with missing dependencies", | ||||
| 			args: []string{"testdata/testcharts/chart-missing-deps"}, | ||||
| 			expected: "Warning: reqsubchart2 is in requirements.yaml but not in the charts/ directory!", | ||||
| 			err:  true, | ||||
| 		}, | ||||
| 		// Install, chart with bad requirements.yaml in /charts
 | ||||
| 		{ | ||||
| 			name: "install chart with bad requirements.yaml", | ||||
| 			args: []string{"testdata/testcharts/chart-bad-requirements"}, | ||||
| 			err:  true, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -58,6 +58,7 @@ func Upgrade(client internalclientset.Interface, opts *Options) error { | |||
| 	} | ||||
| 	obj.Spec.Template.Spec.Containers[0].Image = opts.selectImage() | ||||
| 	obj.Spec.Template.Spec.Containers[0].ImagePullPolicy = opts.pullPolicy() | ||||
| 	obj.Spec.Template.Spec.ServiceAccountName = opts.ServiceAccount | ||||
| 	if _, err := client.Extensions().Deployments(opts.Namespace).Update(obj); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | @ -131,6 +132,7 @@ func generateDeployment(opts *Options) *extensions.Deployment { | |||
| 					Labels: labels, | ||||
| 				}, | ||||
| 				Spec: api.PodSpec{ | ||||
| 					ServiceAccountName: opts.ServiceAccount, | ||||
| 					Containers: []api.Container{ | ||||
| 						{ | ||||
| 							Name:            "tiller", | ||||
|  | @ -164,6 +166,9 @@ func generateDeployment(opts *Options) *extensions.Deployment { | |||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 					NodeSelector: map[string]string{ | ||||
| 						"beta.kubernetes.io/os": "linux", | ||||
| 					}, | ||||
| 					SecurityContext: &api.PodSecurityContext{ | ||||
| 						HostNetwork: opts.EnableHostNetwork, | ||||
| 					}, | ||||
|  |  | |||
|  | @ -70,6 +70,34 @@ func TestDeploymentManifest(t *testing.T) { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestDeploymentManifestForServiceAccount(t *testing.T) { | ||||
| 	tests := []struct { | ||||
| 		name            string | ||||
| 		image           string | ||||
| 		canary          bool | ||||
| 		expect          string | ||||
| 		imagePullPolicy api.PullPolicy | ||||
| 		serviceAccount  string | ||||
| 	}{ | ||||
| 		{"withSA", "", false, "gcr.io/kubernetes-helm/tiller:latest", "IfNotPresent", "service-account"}, | ||||
| 		{"withoutSA", "", false, "gcr.io/kubernetes-helm/tiller:latest", "IfNotPresent", ""}, | ||||
| 	} | ||||
| 	for _, tt := range tests { | ||||
| 		o, err := DeploymentManifest(&Options{Namespace: api.NamespaceDefault, ImageSpec: tt.image, UseCanary: tt.canary, ServiceAccount: tt.serviceAccount}) | ||||
| 		if err != nil { | ||||
| 			t.Fatalf("%s: error %q", tt.name, err) | ||||
| 		} | ||||
| 
 | ||||
| 		var d extensions.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) { | ||||
| 	tests := []struct { | ||||
| 		opts   Options | ||||
|  | @ -301,10 +329,11 @@ 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{ | ||||
| 		Namespace:      api.NamespaceDefault, | ||||
| 		ImageSpec:      "imageToReplace", | ||||
| 		ServiceAccount: "serviceAccountToReplace", | ||||
| 		UseCanary:      false, | ||||
| 	}) | ||||
| 	existingService := service(api.NamespaceDefault) | ||||
|  | @ -319,13 +348,17 @@ func TestUpgrade(t *testing.T) { | |||
| 		if i != image { | ||||
| 			t.Errorf("expected image = '%s', got '%s'", image, i) | ||||
| 		} | ||||
| 		sa := obj.Spec.Template.Spec.ServiceAccountName | ||||
| 		if sa != serviceAccount { | ||||
| 			t.Errorf("expected serviceAccountName = '%s', got '%s'", serviceAccount, sa) | ||||
| 		} | ||||
| 		return true, obj, nil | ||||
| 	}) | ||||
| 	fc.AddReactor("get", "services", func(action testcore.Action) (bool, runtime.Object, error) { | ||||
| 		return true, existingService, nil | ||||
| 	}) | ||||
| 
 | ||||
| 	opts := &Options{Namespace: api.NamespaceDefault, ImageSpec: image} | ||||
| 	opts := &Options{Namespace: api.NamespaceDefault, ImageSpec: image, ServiceAccount: serviceAccount} | ||||
| 	if err := Upgrade(fc, opts); err != nil { | ||||
| 		t.Errorf("unexpected error: %#+v", err) | ||||
| 	} | ||||
|  |  | |||
|  | @ -43,6 +43,9 @@ type Options struct { | |||
| 	// Namespace is the kubernetes namespace to use to deploy tiller.
 | ||||
| 	Namespace string | ||||
| 
 | ||||
| 	// ServiceAccount is the Kubernetes service account to add to tiller
 | ||||
| 	ServiceAccount string | ||||
| 
 | ||||
| 	// ImageSpec indentifies the image tiller will use when deployed.
 | ||||
| 	//
 | ||||
| 	// Valid if and only if UseCanary is false.
 | ||||
|  |  | |||
|  | @ -86,7 +86,7 @@ func newListCmd(client helm.Interface, out io.Writer) *cobra.Command { | |||
| 		Short:   "list releases", | ||||
| 		Long:    listHelp, | ||||
| 		Aliases: []string{"ls"}, | ||||
| 		PersistentPreRunE: setupConnection, | ||||
| 		PreRunE: setupConnection, | ||||
| 		RunE: func(cmd *cobra.Command, args []string) error { | ||||
| 			if len(args) > 0 { | ||||
| 				list.filter = strings.Join(args, " ") | ||||
|  |  | |||
|  | @ -25,19 +25,10 @@ import ( | |||
| 
 | ||||
| 	"github.com/spf13/cobra" | ||||
| 
 | ||||
| 	"k8s.io/helm/pkg/helm/helmpath" | ||||
| 	helm_env "k8s.io/helm/pkg/helm/environment" | ||||
| 	"k8s.io/helm/pkg/plugin" | ||||
| ) | ||||
| 
 | ||||
| const pluginEnvVar = "HELM_PLUGIN" | ||||
| 
 | ||||
| func pluginDirs(home helmpath.Home) string { | ||||
| 	if dirs := os.Getenv(pluginEnvVar); dirs != "" { | ||||
| 		return dirs | ||||
| 	} | ||||
| 	return home.Plugins() | ||||
| } | ||||
| 
 | ||||
| // loadPlugins loads plugins into the command list.
 | ||||
| //
 | ||||
| // This follows a different pattern than the other commands because it has
 | ||||
|  | @ -46,16 +37,25 @@ func pluginDirs(home helmpath.Home) string { | |||
| func loadPlugins(baseCmd *cobra.Command, out io.Writer) { | ||||
| 
 | ||||
| 	// If HELM_NO_PLUGINS is set to 1, do not load plugins.
 | ||||
| 	if settings.PlugDirs == "" { | ||||
| 	if os.Getenv(helm_env.PluginDisableEnvVar) == "1" { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	found, err := findPlugins(settings.PlugDirs) | ||||
| 	found, err := findPlugins(settings.PluginDirs()) | ||||
| 	if err != nil { | ||||
| 		fmt.Fprintf(os.Stderr, "failed to load plugins: %s", err) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	processParent := func(cmd *cobra.Command, args []string) ([]string, error) { | ||||
| 		k, u := manuallyProcessArgs(args) | ||||
| 		if err := cmd.Parent().ParseFlags(k); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		initRootFlags(cmd) | ||||
| 		return u, nil | ||||
| 	} | ||||
| 
 | ||||
| 	// Now we create commands for all of these.
 | ||||
| 	for _, plug := range found { | ||||
| 		plug := plug | ||||
|  | @ -69,9 +69,8 @@ func loadPlugins(baseCmd *cobra.Command, out io.Writer) { | |||
| 			Short: md.Usage, | ||||
| 			Long:  md.Description, | ||||
| 			RunE: func(cmd *cobra.Command, args []string) error { | ||||
| 
 | ||||
| 				k, u := manuallyProcessArgs(args) | ||||
| 				if err := cmd.Parent().ParseFlags(k); err != nil { | ||||
| 				u, err := processParent(cmd, args) | ||||
| 				if err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 
 | ||||
|  | @ -99,10 +98,9 @@ func loadPlugins(baseCmd *cobra.Command, out io.Writer) { | |||
| 		} | ||||
| 
 | ||||
| 		if md.UseTunnel { | ||||
| 			c.PersistentPreRunE = func(cmd *cobra.Command, args []string) error { | ||||
| 			c.PreRunE = func(cmd *cobra.Command, args []string) error { | ||||
| 				// Parse the parent flag, but not the local flags.
 | ||||
| 				k, _ := manuallyProcessArgs(args) | ||||
| 				if err := c.Parent().ParseFlags(k); err != nil { | ||||
| 				if _, err := processParent(cmd, args); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 				return setupConnection(cmd, args) | ||||
|  |  | |||
|  | @ -30,6 +30,8 @@ import ( | |||
| 	"golang.org/x/crypto/ssh/terminal" | ||||
| 
 | ||||
| 	"k8s.io/helm/pkg/chartutil" | ||||
| 	"k8s.io/helm/pkg/downloader" | ||||
| 	"k8s.io/helm/pkg/getter" | ||||
| 	"k8s.io/helm/pkg/helm/helmpath" | ||||
| 	"k8s.io/helm/pkg/proto/hapi/chart" | ||||
| 	"k8s.io/helm/pkg/provenance" | ||||
|  | @ -55,6 +57,7 @@ type packageCmd struct { | |||
| 	keyring          string | ||||
| 	version          string | ||||
| 	destination      string | ||||
| 	dependencyUpdate bool | ||||
| 
 | ||||
| 	out  io.Writer | ||||
| 	home helmpath.Home | ||||
|  | @ -72,7 +75,7 @@ func newPackageCmd(out io.Writer) *cobra.Command { | |||
| 		RunE: func(cmd *cobra.Command, args []string) error { | ||||
| 			pkg.home = settings.Home | ||||
| 			if len(args) == 0 { | ||||
| 				return fmt.Errorf("This command needs at least one argument, the path to the chart.") | ||||
| 				return fmt.Errorf("need at least one argument, the path to the chart") | ||||
| 			} | ||||
| 			if pkg.sign { | ||||
| 				if pkg.key == "" { | ||||
|  | @ -99,6 +102,7 @@ func newPackageCmd(out io.Writer) *cobra.Command { | |||
| 	f.StringVar(&pkg.keyring, "keyring", defaultKeyring(), "location of a public keyring") | ||||
| 	f.StringVar(&pkg.version, "version", "", "set the version on the chart to this semver version") | ||||
| 	f.StringVarP(&pkg.destination, "destination", "d", ".", "location to write the chart.") | ||||
| 	f.BoolVarP(&pkg.dependencyUpdate, "dependency-update", "u", false, `update dependencies from "requirements.yaml" to dir "charts/" before packaging`) | ||||
| 
 | ||||
| 	return cmd | ||||
| } | ||||
|  | @ -109,6 +113,21 @@ func (p *packageCmd) run(cmd *cobra.Command, args []string) error { | |||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if p.dependencyUpdate { | ||||
| 		downloadManager := &downloader.Manager{ | ||||
| 			Out:       p.out, | ||||
| 			ChartPath: path, | ||||
| 			HelmHome:  settings.Home, | ||||
| 			Keyring:   p.keyring, | ||||
| 			Getters:   getter.All(settings), | ||||
| 			Debug:     settings.Debug, | ||||
| 		} | ||||
| 
 | ||||
| 		if err := downloadManager.Update(); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	ch, err := chartutil.LoadDir(path) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
|  | @ -127,7 +146,13 @@ func (p *packageCmd) run(cmd *cobra.Command, args []string) error { | |||
| 	} | ||||
| 
 | ||||
| 	if reqs, err := chartutil.LoadRequirements(ch); err == nil { | ||||
| 		checkDependencies(ch, reqs, p.out) | ||||
| 		if err := checkDependencies(ch, reqs, p.out); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} else { | ||||
| 		if err != chartutil.ErrRequirementsNotFound { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	var dest string | ||||
|  | @ -144,7 +169,9 @@ func (p *packageCmd) run(cmd *cobra.Command, args []string) error { | |||
| 
 | ||||
| 	name, err := chartutil.Save(ch, dest) | ||||
| 	if err == nil { | ||||
| 		debug("Saved %s to current directory\n", name) | ||||
| 		fmt.Fprintf(p.out, "Successfully packaged chart and saved it to: %s\n", name) | ||||
| 	} else { | ||||
| 		return fmt.Errorf("Failed to save: %s", err) | ||||
| 	} | ||||
| 
 | ||||
| 	// Save to $HELM_HOME/local directory. This is second, because we don't want
 | ||||
|  | @ -154,7 +181,7 @@ func (p *packageCmd) run(cmd *cobra.Command, args []string) error { | |||
| 		if err := repo.AddChartToLocalRepo(ch, lr); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		debug("Saved %s to %s\n", name, lr) | ||||
| 		debug("Successfully saved %s to %s\n", name, lr) | ||||
| 	} | ||||
| 
 | ||||
| 	if p.sign { | ||||
|  |  | |||
|  | @ -64,7 +64,7 @@ func TestPackage(t *testing.T) { | |||
| 			name:   "package without chart path", | ||||
| 			args:   []string{}, | ||||
| 			flags:  map[string]string{}, | ||||
| 			expect: "This command needs at least one argument, the path to the chart.", | ||||
| 			expect: "need at least one argument, the path to the chart", | ||||
| 			err:    true, | ||||
| 		}, | ||||
| 		{ | ||||
|  | @ -118,8 +118,8 @@ func TestPackage(t *testing.T) { | |||
| 		{ | ||||
| 			name:    "package testdata/testcharts/chart-missing-deps", | ||||
| 			args:    []string{"testdata/testcharts/chart-missing-deps"}, | ||||
| 			expect:  "Warning: reqsubchart2 is in requirements.yaml but not in the charts/ directory!\n", | ||||
| 			hasfile: "chart-missing-deps-0.1.0.tgz", | ||||
| 			err:     true, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -41,6 +41,7 @@ func newPluginCmd(out io.Writer) *cobra.Command { | |||
| 		newPluginInstallCmd(out), | ||||
| 		newPluginListCmd(out), | ||||
| 		newPluginRemoveCmd(out), | ||||
| 		newPluginUpdateCmd(out), | ||||
| 	) | ||||
| 	return cmd | ||||
| } | ||||
|  |  | |||
|  | @ -44,11 +44,8 @@ func newPluginListCmd(out io.Writer) *cobra.Command { | |||
| } | ||||
| 
 | ||||
| func (pcmd *pluginListCmd) run() error { | ||||
| 	plugdirs := pluginDirs(pcmd.home) | ||||
| 
 | ||||
| 	debug("pluginDirs: %s", plugdirs) | ||||
| 
 | ||||
| 	plugins, err := findPlugins(plugdirs) | ||||
| 	debug("pluginDirs: %s", settings.PluginDirs()) | ||||
| 	plugins, err := findPlugins(settings.PluginDirs()) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  |  | |||
|  | @ -16,9 +16,11 @@ limitations under the License. | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"k8s.io/helm/pkg/helm/helmpath" | ||||
| 	"k8s.io/helm/pkg/plugin" | ||||
|  | @ -48,8 +50,8 @@ func newPluginRemoveCmd(out io.Writer) *cobra.Command { | |||
| } | ||||
| 
 | ||||
| func (pcmd *pluginRemoveCmd) complete(args []string) error { | ||||
| 	if err := checkArgsLength(len(args), "plugin"); err != nil { | ||||
| 		return err | ||||
| 	if len(args) == 0 { | ||||
| 		return errors.New("please provide plugin name to remove") | ||||
| 	} | ||||
| 	pcmd.names = args | ||||
| 	pcmd.home = settings.Home | ||||
|  | @ -57,20 +59,25 @@ func (pcmd *pluginRemoveCmd) complete(args []string) error { | |||
| } | ||||
| 
 | ||||
| func (pcmd *pluginRemoveCmd) run() error { | ||||
| 	plugdirs := pluginDirs(pcmd.home) | ||||
| 	debug("loading installed plugins from %s", plugdirs) | ||||
| 	plugins, err := findPlugins(plugdirs) | ||||
| 	debug("loading installed plugins from %s", settings.PluginDirs()) | ||||
| 	plugins, err := findPlugins(settings.PluginDirs()) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	var errorPlugins []string | ||||
| 	for _, name := range pcmd.names { | ||||
| 		if found := findPlugin(plugins, name); found != nil { | ||||
| 			if err := removePlugin(found, pcmd.home); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 				errorPlugins = append(errorPlugins, fmt.Sprintf("Failed to remove plugin %s, got error (%v)", name, err)) | ||||
| 			} else { | ||||
| 				fmt.Fprintf(pcmd.out, "Removed plugin: %s\n", name) | ||||
| 			} | ||||
| 		} else { | ||||
| 			errorPlugins = append(errorPlugins, fmt.Sprintf("Plugin: %s not found", name)) | ||||
| 		} | ||||
| 	} | ||||
| 	if len(errorPlugins) > 0 { | ||||
| 		return fmt.Errorf(strings.Join(errorPlugins, "\n")) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  |  | |||
|  | @ -23,6 +23,7 @@ import ( | |||
| 	"strings" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	helm_env "k8s.io/helm/pkg/helm/environment" | ||||
| 	"k8s.io/helm/pkg/helm/helmpath" | ||||
| 	"k8s.io/helm/pkg/plugin" | ||||
| 
 | ||||
|  | @ -71,7 +72,6 @@ func TestLoadPlugins(t *testing.T) { | |||
| 		settings.Home = old | ||||
| 	}() | ||||
| 	hh := settings.Home | ||||
| 	settings.PlugDirs = hh.Plugins() | ||||
| 
 | ||||
| 	out := bytes.NewBuffer(nil) | ||||
| 	cmd := &cobra.Command{} | ||||
|  | @ -139,12 +139,11 @@ func TestLoadPlugins(t *testing.T) { | |||
| func TestLoadPlugins_HelmNoPlugins(t *testing.T) { | ||||
| 	// Set helm home to point to testdata
 | ||||
| 	old := settings.Home | ||||
| 	oldPlugDirs := settings.PlugDirs | ||||
| 	settings.Home = "testdata/helmhome" | ||||
| 	settings.PlugDirs = "" | ||||
| 	os.Setenv(helm_env.PluginDisableEnvVar, "1") | ||||
| 	defer func() { | ||||
| 		settings.Home = old | ||||
| 		settings.PlugDirs = oldPlugDirs | ||||
| 		os.Unsetenv(helm_env.PluginDisableEnvVar) | ||||
| 	}() | ||||
| 
 | ||||
| 	out := bytes.NewBuffer(nil) | ||||
|  | @ -161,7 +160,6 @@ func TestSetupEnv(t *testing.T) { | |||
| 	name := "pequod" | ||||
| 	settings.Home = helmpath.Home("testdata/helmhome") | ||||
| 	base := filepath.Join(settings.Home.Plugins(), name) | ||||
| 	settings.PlugDirs = settings.Home.Plugins() | ||||
| 	settings.Debug = true | ||||
| 	defer func() { | ||||
| 		settings.Debug = false | ||||
|  |  | |||
|  | @ -0,0 +1,113 @@ | |||
| /* | ||||
| Copyright 2017 The Kubernetes Authors All rights reserved. | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
| 
 | ||||
| http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| 
 | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
| 
 | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"k8s.io/helm/pkg/helm/helmpath" | ||||
| 	"k8s.io/helm/pkg/plugin" | ||||
| 	"k8s.io/helm/pkg/plugin/installer" | ||||
| 
 | ||||
| 	"github.com/spf13/cobra" | ||||
| ) | ||||
| 
 | ||||
| type pluginUpdateCmd struct { | ||||
| 	names []string | ||||
| 	home  helmpath.Home | ||||
| 	out   io.Writer | ||||
| } | ||||
| 
 | ||||
| func newPluginUpdateCmd(out io.Writer) *cobra.Command { | ||||
| 	pcmd := &pluginUpdateCmd{out: out} | ||||
| 	cmd := &cobra.Command{ | ||||
| 		Use:   "update <plugin>...", | ||||
| 		Short: "update one or more Helm plugins", | ||||
| 		PreRunE: func(cmd *cobra.Command, args []string) error { | ||||
| 			return pcmd.complete(args) | ||||
| 		}, | ||||
| 		RunE: func(cmd *cobra.Command, args []string) error { | ||||
| 			return pcmd.run() | ||||
| 		}, | ||||
| 	} | ||||
| 	return cmd | ||||
| } | ||||
| 
 | ||||
| func (pcmd *pluginUpdateCmd) complete(args []string) error { | ||||
| 	if len(args) == 0 { | ||||
| 		return errors.New("please provide plugin name to update") | ||||
| 	} | ||||
| 	pcmd.names = args | ||||
| 	pcmd.home = settings.Home | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (pcmd *pluginUpdateCmd) run() error { | ||||
| 	installer.Debug = settings.Debug | ||||
| 	debug("loading installed plugins from %s", settings.PluginDirs()) | ||||
| 	plugins, err := findPlugins(settings.PluginDirs()) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	var errorPlugins []string | ||||
| 
 | ||||
| 	for _, name := range pcmd.names { | ||||
| 		if found := findPlugin(plugins, name); found != nil { | ||||
| 			if err := updatePlugin(found, pcmd.home); err != nil { | ||||
| 				errorPlugins = append(errorPlugins, fmt.Sprintf("Failed to update plugin %s, got error (%v)", name, err)) | ||||
| 			} else { | ||||
| 				fmt.Fprintf(pcmd.out, "Updated plugin: %s\n", name) | ||||
| 			} | ||||
| 		} else { | ||||
| 			errorPlugins = append(errorPlugins, fmt.Sprintf("Plugin: %s not found", name)) | ||||
| 		} | ||||
| 	} | ||||
| 	if len(errorPlugins) > 0 { | ||||
| 		return fmt.Errorf(strings.Join(errorPlugins, "\n")) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func updatePlugin(p *plugin.Plugin, home helmpath.Home) error { | ||||
| 	exactLocation, err := filepath.EvalSymlinks(p.Dir) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	absExactLocation, err := filepath.Abs(exactLocation) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	i, err := installer.FindSource(absExactLocation, home) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err := installer.Update(i); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	debug("loading plugin from %s", i.Path()) | ||||
| 	updatedPlugin, err := plugin.LoadDir(i.Path()) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	return runHook(updatedPlugin, plugin.Update, home) | ||||
| } | ||||
|  | @ -23,6 +23,7 @@ import ( | |||
| 	"github.com/spf13/cobra" | ||||
| 
 | ||||
| 	"k8s.io/helm/pkg/helm" | ||||
| 	"k8s.io/helm/pkg/proto/hapi/release" | ||||
| ) | ||||
| 
 | ||||
| const releaseTestDesc = ` | ||||
|  | @ -50,7 +51,7 @@ func newReleaseTestCmd(c helm.Interface, out io.Writer) *cobra.Command { | |||
| 		Use:     "test [RELEASE]", | ||||
| 		Short:   "test a release", | ||||
| 		Long:    releaseTestDesc, | ||||
| 		PersistentPreRunE: setupConnection, | ||||
| 		PreRunE: setupConnection, | ||||
| 		RunE: func(cmd *cobra.Command, args []string) error { | ||||
| 			if err := checkArgsLength(len(args), "release name"); err != nil { | ||||
| 				return err | ||||
|  | @ -75,16 +76,35 @@ func (t *releaseTestCmd) run() (err error) { | |||
| 		helm.ReleaseTestTimeout(t.timeout), | ||||
| 		helm.ReleaseTestCleanup(t.cleanup), | ||||
| 	) | ||||
| 	testErr := &testErr{} | ||||
| 
 | ||||
| 	for { | ||||
| 		select { | ||||
| 		case err := <-errc: | ||||
| 			if prettyError(err) == nil && testErr.failed > 0 { | ||||
| 				return testErr.Error() | ||||
| 			} | ||||
| 			return prettyError(err) | ||||
| 		case res, ok := <-c: | ||||
| 			if !ok { | ||||
| 				break | ||||
| 			} | ||||
| 
 | ||||
| 			if res.Status == release.TestRun_FAILURE { | ||||
| 				testErr.failed++ | ||||
| 			} | ||||
| 
 | ||||
| 			fmt.Fprintf(t.out, res.Msg+"\n") | ||||
| 
 | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| type testErr struct { | ||||
| 	failed int | ||||
| } | ||||
| 
 | ||||
| func (err *testErr) Error() error { | ||||
| 	return fmt.Errorf("%v test(s) failed", err.failed) | ||||
| } | ||||
|  |  | |||
|  | @ -0,0 +1,105 @@ | |||
| /* | ||||
| Copyright 2016 The Kubernetes Authors All rights reserved. | ||||
| 
 | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
| 
 | ||||
|     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| 
 | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
| 
 | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"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 | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name:      "basic test", | ||||
| 			args:      []string{"example-release"}, | ||||
| 			flags:     []string{}, | ||||
| 			responses: map[string]release.TestRun_Status{"PASSED: green lights everywhere": release.TestRun_SUCCESS}, | ||||
| 			fail:      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, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:      "test unknown", | ||||
| 			args:      []string{"example-unknown"}, | ||||
| 			flags:     []string{}, | ||||
| 			responses: map[string]release.TestRun_Status{"UNKNOWN: yellow lights everywhere": release.TestRun_UNKNOWN}, | ||||
| 			fail:      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, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:      "test running", | ||||
| 			args:      []string{"example-running"}, | ||||
| 			flags:     []string{}, | ||||
| 			responses: map[string]release.TestRun_Status{"RUNNING: things are happpeningggg": release.TestRun_RUNNING}, | ||||
| 			fail:      false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:  "multiple tests example", | ||||
| 			args:  []string{"example-suite"}, | ||||
| 			flags: []string{}, | ||||
| 			responses: map[string]release.TestRun_Status{ | ||||
| 				"RUNNING: things are happpeningggg":           release.TestRun_RUNNING, | ||||
| 				"PASSED: party time":                          release.TestRun_SUCCESS, | ||||
| 				"RUNNING: things are happening again":         release.TestRun_RUNNING, | ||||
| 				"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, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	for _, tt := range tests { | ||||
| 		c := &fakeReleaseClient{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) | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| } | ||||
|  | @ -22,7 +22,7 @@ import ( | |||
| 
 | ||||
| 	"github.com/spf13/cobra" | ||||
| 
 | ||||
| 	"k8s.io/helm/pkg/getter/defaultgetters" | ||||
| 	"k8s.io/helm/pkg/getter" | ||||
| 	"k8s.io/helm/pkg/helm/helmpath" | ||||
| 	"k8s.io/helm/pkg/repo" | ||||
| ) | ||||
|  | @ -85,7 +85,7 @@ func addRepository(name, url string, home helmpath.Home, certFile, keyFile, caFi | |||
| 	} | ||||
| 
 | ||||
| 	if noUpdate && f.Has(name) { | ||||
| 		return fmt.Errorf("The repository name you provided (%s) already exists. Please specify a different name.", name) | ||||
| 		return fmt.Errorf("repository name (%s) already exists, please specify a different name", name) | ||||
| 	} | ||||
| 
 | ||||
| 	cif := home.CacheIndex(name) | ||||
|  | @ -98,7 +98,7 @@ func addRepository(name, url string, home helmpath.Home, certFile, keyFile, caFi | |||
| 		CAFile:   caFile, | ||||
| 	} | ||||
| 
 | ||||
| 	r, err := repo.NewChartRepository(&c, defaultgetters.Get(settings)) | ||||
| 	r, err := repo.NewChartRepository(&c, getter.All(settings)) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  |  | |||
|  | @ -24,7 +24,7 @@ import ( | |||
| 
 | ||||
| 	"github.com/spf13/cobra" | ||||
| 
 | ||||
| 	"k8s.io/helm/pkg/getter/defaultgetters" | ||||
| 	"k8s.io/helm/pkg/getter" | ||||
| 	"k8s.io/helm/pkg/helm/helmpath" | ||||
| 	"k8s.io/helm/pkg/repo" | ||||
| ) | ||||
|  | @ -55,7 +55,7 @@ func newRepoUpdateCmd(out io.Writer) *cobra.Command { | |||
| 	cmd := &cobra.Command{ | ||||
| 		Use:     "update", | ||||
| 		Aliases: []string{"up"}, | ||||
| 		Short:   "update information on available charts in the chart repositories", | ||||
| 		Short:   "update information of available charts locally from chart repositories", | ||||
| 		Long:    updateDesc, | ||||
| 		RunE: func(cmd *cobra.Command, args []string) error { | ||||
| 			u.home = settings.Home | ||||
|  | @ -76,7 +76,7 @@ func (u *repoUpdateCmd) run() error { | |||
| 	} | ||||
| 	var repos []*repo.ChartRepository | ||||
| 	for _, cfg := range f.Repositories { | ||||
| 		r, err := repo.NewChartRepository(cfg, defaultgetters.Get(settings)) | ||||
| 		r, err := repo.NewChartRepository(cfg, getter.All(settings)) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  |  | |||
|  | @ -23,7 +23,7 @@ import ( | |||
| 	"strings" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"k8s.io/helm/pkg/getter/defaultgetters" | ||||
| 	"k8s.io/helm/pkg/getter" | ||||
| 	"k8s.io/helm/pkg/helm/helmpath" | ||||
| 	"k8s.io/helm/pkg/repo" | ||||
| 	"k8s.io/helm/pkg/repo/repotest" | ||||
|  | @ -85,7 +85,7 @@ func TestUpdateCharts(t *testing.T) { | |||
| 		Name:  "charts", | ||||
| 		URL:   ts.URL(), | ||||
| 		Cache: hh.CacheIndex("charts"), | ||||
| 	}, defaultgetters.Get(settings)) | ||||
| 	}, getter.All(settings)) | ||||
| 	if err != nil { | ||||
| 		t.Error(err) | ||||
| 	} | ||||
|  |  | |||
|  | @ -57,7 +57,12 @@ func newResetCmd(client helm.Interface, out io.Writer) *cobra.Command { | |||
| 		Use:   "reset", | ||||
| 		Short: "uninstalls Tiller from a cluster", | ||||
| 		Long:  resetDesc, | ||||
| 		PersistentPreRunE: setupConnection, | ||||
| 		PreRunE: func(cmd *cobra.Command, args []string) error { | ||||
| 			if err := setupConnection(cmd, args); !d.force && err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			return nil | ||||
| 		}, | ||||
| 		RunE: func(cmd *cobra.Command, args []string) error { | ||||
| 			if len(args) != 0 { | ||||
| 				return errors.New("This command does not accept arguments") | ||||
|  | @ -72,7 +77,7 @@ func newResetCmd(client helm.Interface, out io.Writer) *cobra.Command { | |||
| 	} | ||||
| 
 | ||||
| 	f := cmd.Flags() | ||||
| 	f.BoolVarP(&d.force, "force", "f", false, "forces Tiller uninstall even if there are releases installed") | ||||
| 	f.BoolVarP(&d.force, "force", "f", false, "forces Tiller uninstall even if there are releases installed, or if tiller is not in ready state") | ||||
| 	f.BoolVar(&d.removeHelmHome, "remove-helm-home", false, "if set deletes $HELM_HOME") | ||||
| 
 | ||||
| 	return cmd | ||||
|  | @ -91,12 +96,12 @@ func (d *resetCmd) run() error { | |||
| 	res, err := d.client.ListReleases( | ||||
| 		helm.ReleaseListStatuses([]release.Status_Code{release.Status_DEPLOYED}), | ||||
| 	) | ||||
| 	if err != nil { | ||||
| 	if !d.force && err != nil { | ||||
| 		return prettyError(err) | ||||
| 	} | ||||
| 
 | ||||
| 	if len(res.Releases) > 0 && !d.force { | ||||
| 		return fmt.Errorf("There are still %d deployed releases (Tip: use --force).", len(res.Releases)) | ||||
| 	if !d.force && res != nil && len(res.Releases) > 0 { | ||||
| 		return fmt.Errorf("there are still %d deployed releases (Tip: use --force)", len(res.Releases)) | ||||
| 	} | ||||
| 
 | ||||
| 	if err := installer.Uninstall(d.kubeClient, &installer.Options{Namespace: d.namespace}); err != nil { | ||||
|  |  | |||
|  | @ -120,7 +120,7 @@ func TestReset_deployedReleases(t *testing.T) { | |||
| 		namespace:  api.NamespaceDefault, | ||||
| 	} | ||||
| 	err = cmd.run() | ||||
| 	expected := "There are still 1 deployed releases (Tip: use --force)" | ||||
| 	expected := "there are still 1 deployed releases (Tip: use --force)" | ||||
| 	if !strings.Contains(err.Error(), expected) { | ||||
| 		t.Errorf("unexpected error: %v", err) | ||||
| 	} | ||||
|  |  | |||
|  | @ -39,6 +39,7 @@ type rollbackCmd struct { | |||
| 	revision     int32 | ||||
| 	dryRun       bool | ||||
| 	recreate     bool | ||||
| 	force        bool | ||||
| 	disableHooks bool | ||||
| 	out          io.Writer | ||||
| 	client       helm.Interface | ||||
|  | @ -56,7 +57,7 @@ func newRollbackCmd(c helm.Interface, out io.Writer) *cobra.Command { | |||
| 		Use:     "rollback [flags] [RELEASE] [REVISION]", | ||||
| 		Short:   "roll back a release to a previous revision", | ||||
| 		Long:    rollbackDesc, | ||||
| 		PersistentPreRunE: setupConnection, | ||||
| 		PreRunE: setupConnection, | ||||
| 		RunE: func(cmd *cobra.Command, args []string) error { | ||||
| 			if err := checkArgsLength(len(args), "release name", "revision number"); err != nil { | ||||
| 				return err | ||||
|  | @ -78,6 +79,7 @@ func newRollbackCmd(c helm.Interface, out io.Writer) *cobra.Command { | |||
| 	f := cmd.Flags() | ||||
| 	f.BoolVar(&rollback.dryRun, "dry-run", false, "simulate a rollback") | ||||
| 	f.BoolVar(&rollback.recreate, "recreate-pods", false, "performs pods restart for the resource if applicable") | ||||
| 	f.BoolVar(&rollback.force, "force", false, "force resource update through delete/recreate if needed") | ||||
| 	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") | ||||
|  | @ -90,6 +92,7 @@ func (r *rollbackCmd) run() error { | |||
| 		r.name, | ||||
| 		helm.RollbackDryRun(r.dryRun), | ||||
| 		helm.RollbackRecreate(r.recreate), | ||||
| 		helm.RollbackForce(r.force), | ||||
| 		helm.RollbackDisableHooks(r.disableHooks), | ||||
| 		helm.RollbackVersion(r.revision), | ||||
| 		helm.RollbackTimeout(r.timeout), | ||||
|  |  | |||
|  | @ -55,19 +55,29 @@ func newServeCmd(out io.Writer) *cobra.Command { | |||
| 		Use:   "serve", | ||||
| 		Short: "start a local http web server", | ||||
| 		Long:  serveDesc, | ||||
| 		PreRunE: func(cmd *cobra.Command, args []string) error { | ||||
| 			return srv.complete(args) | ||||
| 		}, | ||||
| 		RunE: func(cmd *cobra.Command, args []string) error { | ||||
| 			return srv.run() | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	f := cmd.Flags() | ||||
| 	f.StringVar(&srv.repoPath, "repo-path", settings.Home.LocalRepository(), "local directory path from which to serve charts") | ||||
| 	f.StringVar(&srv.repoPath, "repo-path", "", "local directory path from which to serve charts") | ||||
| 	f.StringVar(&srv.address, "address", "127.0.0.1:8879", "address to listen on") | ||||
| 	f.StringVar(&srv.url, "url", "", "external URL of chart repository") | ||||
| 
 | ||||
| 	return cmd | ||||
| } | ||||
| 
 | ||||
| func (s *serveCmd) complete(args []string) error { | ||||
| 	if s.repoPath == "" { | ||||
| 		s.repoPath = settings.Home.LocalRepository() | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (s *serveCmd) run() error { | ||||
| 	repoPath, err := filepath.Abs(s.repoPath) | ||||
| 	if err != nil { | ||||
|  |  | |||
|  | @ -60,7 +60,7 @@ func newStatusCmd(client helm.Interface, out io.Writer) *cobra.Command { | |||
| 		Use:     "status [flags] RELEASE_NAME", | ||||
| 		Short:   "displays the status of the named release", | ||||
| 		Long:    statusHelp, | ||||
| 		PersistentPreRunE: setupConnection, | ||||
| 		PreRunE: setupConnection, | ||||
| 		RunE: func(cmd *cobra.Command, args []string) error { | ||||
| 			if len(args) == 0 { | ||||
| 				return errReleaseRequired | ||||
|  |  | |||
|  | @ -0,0 +1,21 @@ | |||
| # Patterns to ignore when building packages. | ||||
| # This supports shell glob matching, relative path matching, and | ||||
| # negation (prefixed with !). Only one pattern per line. | ||||
| .DS_Store | ||||
| # Common VCS dirs | ||||
| .git/ | ||||
| .gitignore | ||||
| .bzr/ | ||||
| .bzrignore | ||||
| .hg/ | ||||
| .hgignore | ||||
| .svn/ | ||||
| # Common backup files | ||||
| *.swp | ||||
| *.bak | ||||
| *.tmp | ||||
| *~ | ||||
| # Various IDEs | ||||
| .project | ||||
| .idea/ | ||||
| *.tmproj | ||||
|  | @ -0,0 +1,3 @@ | |||
| description: A Helm chart for Kubernetes | ||||
| name: chart-missing-deps | ||||
| version: 0.1.0 | ||||
							
								
								
									
										21
									
								
								cmd/helm/testdata/testcharts/chart-bad-requirements/charts/reqsubchart/.helmignore
								
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										21
									
								
								cmd/helm/testdata/testcharts/chart-bad-requirements/charts/reqsubchart/.helmignore
								
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,21 @@ | |||
| # Patterns to ignore when building packages. | ||||
| # This supports shell glob matching, relative path matching, and | ||||
| # negation (prefixed with !). Only one pattern per line. | ||||
| .DS_Store | ||||
| # Common VCS dirs | ||||
| .git/ | ||||
| .gitignore | ||||
| .bzr/ | ||||
| .bzrignore | ||||
| .hg/ | ||||
| .hgignore | ||||
| .svn/ | ||||
| # Common backup files | ||||
| *.swp | ||||
| *.bak | ||||
| *.tmp | ||||
| *~ | ||||
| # Various IDEs | ||||
| .project | ||||
| .idea/ | ||||
| *.tmproj | ||||
							
								
								
									
										3
									
								
								cmd/helm/testdata/testcharts/chart-bad-requirements/charts/reqsubchart/Chart.yaml
								
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										3
									
								
								cmd/helm/testdata/testcharts/chart-bad-requirements/charts/reqsubchart/Chart.yaml
								
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,3 @@ | |||
| description: A Helm chart for Kubernetes | ||||
| name: reqsubchart | ||||
| version: 0.1.0 | ||||
							
								
								
									
										4
									
								
								cmd/helm/testdata/testcharts/chart-bad-requirements/charts/reqsubchart/values.yaml
								
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										4
									
								
								cmd/helm/testdata/testcharts/chart-bad-requirements/charts/reqsubchart/values.yaml
								
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,4 @@ | |||
| # Default values for reqsubchart. | ||||
| # This is a YAML-formatted file. | ||||
| # Declare name/value pairs to be passed into your templates. | ||||
| # name: value | ||||
|  | @ -0,0 +1,4 @@ | |||
| dependencies: | ||||
|   - name: reqsubchart | ||||
|   version: 0.1.0 | ||||
|   repository: "https://example.com/charts" | ||||
|  | @ -0,0 +1,4 @@ | |||
| # Default values for reqtest. | ||||
| # This is a YAML-formatted file. | ||||
| # Declare name/value pairs to be passed into your templates. | ||||
| # name: value | ||||
|  | @ -62,6 +62,7 @@ type upgradeCmd struct { | |||
| 	client       helm.Interface | ||||
| 	dryRun       bool | ||||
| 	recreate     bool | ||||
| 	force        bool | ||||
| 	disableHooks bool | ||||
| 	valueFiles   valueFiles | ||||
| 	values       []string | ||||
|  | @ -74,6 +75,12 @@ type upgradeCmd struct { | |||
| 	resetValues  bool | ||||
| 	reuseValues  bool | ||||
| 	wait         bool | ||||
| 	repoURL      string | ||||
| 	devel        bool | ||||
| 
 | ||||
| 	certFile string | ||||
| 	keyFile  string | ||||
| 	caFile   string | ||||
| } | ||||
| 
 | ||||
| func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command { | ||||
|  | @ -87,12 +94,17 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command { | |||
| 		Use:     "upgrade [RELEASE] [CHART]", | ||||
| 		Short:   "upgrade a release", | ||||
| 		Long:    upgradeDesc, | ||||
| 		PersistentPreRunE: setupConnection, | ||||
| 		PreRunE: setupConnection, | ||||
| 		RunE: func(cmd *cobra.Command, args []string) error { | ||||
| 			if err := checkArgsLength(len(args), "release name", "chart path"); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 
 | ||||
| 			if upgrade.version == "" && upgrade.devel { | ||||
| 				debug("setting version to >0.0.0-a") | ||||
| 				upgrade.version = ">0.0.0-a" | ||||
| 			} | ||||
| 
 | ||||
| 			upgrade.release = args[0] | ||||
| 			upgrade.chart = args[1] | ||||
| 			upgrade.client = ensureHelmClient(upgrade.client) | ||||
|  | @ -105,6 +117,7 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command { | |||
| 	f.VarP(&upgrade.valueFiles, "values", "f", "specify values in a YAML file (can specify multiple)") | ||||
| 	f.BoolVar(&upgrade.dryRun, "dry-run", false, "simulate an upgrade") | ||||
| 	f.BoolVar(&upgrade.recreate, "recreate-pods", false, "performs pods restart for the resource if applicable") | ||||
| 	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.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") | ||||
|  | @ -117,6 +130,11 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command { | |||
| 	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.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.certFile, "cert-file", "", "identify HTTPS client using this SSL certificate file") | ||||
| 	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-a'. If --version is set, this is ignored.") | ||||
| 
 | ||||
| 	f.MarkDeprecated("disable-hooks", "use --no-hooks instead") | ||||
| 
 | ||||
|  | @ -124,7 +142,7 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command { | |||
| } | ||||
| 
 | ||||
| func (u *upgradeCmd) run() error { | ||||
| 	chartPath, err := locateChartPath(u.chart, u.version, u.verify, u.keyring) | ||||
| 	chartPath, err := locateChartPath(u.repoURL, u.chart, u.version, u.verify, u.keyring, u.certFile, u.keyFile, u.caFile) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | @ -166,8 +184,14 @@ func (u *upgradeCmd) run() error { | |||
| 	// Check chart requirements to make sure all dependencies are present in /charts
 | ||||
| 	if ch, err := chartutil.Load(chartPath); err == nil { | ||||
| 		if req, err := chartutil.LoadRequirements(ch); err == nil { | ||||
| 			checkDependencies(ch, req, u.out) | ||||
| 			if err := checkDependencies(ch, req, u.out); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} else if err != chartutil.ErrRequirementsNotFound { | ||||
| 			return fmt.Errorf("cannot load requirements: %v", err) | ||||
| 		} | ||||
| 	} else { | ||||
| 		return prettyError(err) | ||||
| 	} | ||||
| 
 | ||||
| 	resp, err := u.client.UpdateRelease( | ||||
|  | @ -176,6 +200,7 @@ func (u *upgradeCmd) run() error { | |||
| 		helm.UpdateValueOverrides(rawVals), | ||||
| 		helm.UpgradeDryRun(u.dryRun), | ||||
| 		helm.UpgradeRecreate(u.recreate), | ||||
| 		helm.UpgradeForce(u.force), | ||||
| 		helm.UpgradeDisableHooks(u.disableHooks), | ||||
| 		helm.UpgradeTimeout(u.timeout), | ||||
| 		helm.ResetValues(u.resetValues), | ||||
|  |  | |||
|  | @ -82,6 +82,7 @@ func TestUpgradeCmd(t *testing.T) { | |||
| 
 | ||||
| 	originalDepsPath := filepath.Join("testdata/testcharts/reqtest") | ||||
| 	missingDepsPath := filepath.Join("testdata/testcharts/chart-missing-deps") | ||||
| 	badDepsPath := filepath.Join("testdata/testcharts/chart-bad-requirements") | ||||
| 	var ch3 *chart.Chart | ||||
| 	ch3, err = chartutil.Load(originalDepsPath) | ||||
| 	if err != nil { | ||||
|  | @ -141,7 +142,13 @@ func TestUpgradeCmd(t *testing.T) { | |||
| 			name: "upgrade a release with missing dependencies", | ||||
| 			args: []string{"bonkers-bunny", missingDepsPath}, | ||||
| 			resp: releaseMock(&releaseOptions{name: "bonkers-bunny", version: 1, chart: ch3}), | ||||
| 			expected: "Warning: reqsubchart2 is in requirements.yaml but not in the charts/ directory!", | ||||
| 			err:  true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "upgrade a release with bad dependencies", | ||||
| 			args: []string{"bonkers-bunny", badDepsPath}, | ||||
| 			resp: releaseMock(&releaseOptions{name: "bonkers-bunny", version: 1, chart: ch3}), | ||||
| 			err:  true, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,139 @@ | |||
| /* | ||||
| Copyright 2017 The Kubernetes Authors All rights reserved. | ||||
| 
 | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
| 
 | ||||
|     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| 
 | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
| 
 | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"net" | ||||
| 
 | ||||
| 	"golang.org/x/net/context" | ||||
| 	"google.golang.org/grpc" | ||||
| 	"google.golang.org/grpc/grpclog" | ||||
| 	"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" | ||||
| 
 | ||||
| 	"k8s.io/helm/pkg/kube" | ||||
| 	rudderAPI "k8s.io/helm/pkg/proto/hapi/rudder" | ||||
| 	"k8s.io/helm/pkg/rudder" | ||||
| 	"k8s.io/helm/pkg/tiller" | ||||
| 	"k8s.io/helm/pkg/version" | ||||
| ) | ||||
| 
 | ||||
| var kubeClient *kube.Client | ||||
| var clientset internalclientset.Interface | ||||
| 
 | ||||
| func main() { | ||||
| 	var err error | ||||
| 	kubeClient = kube.New(nil) | ||||
| 	clientset, err = kubeClient.ClientSet() | ||||
| 	if err != nil { | ||||
| 		grpclog.Fatalf("Cannot initialize Kubernetes connection: %s", err) | ||||
| 	} | ||||
| 
 | ||||
| 	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", rudder.GrpcPort)) | ||||
| 	if err != nil { | ||||
| 		grpclog.Fatalf("failed to listen: %v", err) | ||||
| 	} | ||||
| 	grpcServer := grpc.NewServer() | ||||
| 	rudderAPI.RegisterReleaseModuleServiceServer(grpcServer, &ReleaseModuleServiceServer{}) | ||||
| 
 | ||||
| 	grpclog.Print("Server starting") | ||||
| 	grpcServer.Serve(lis) | ||||
| 	grpclog.Print("Server started") | ||||
| } | ||||
| 
 | ||||
| // ReleaseModuleServiceServer provides implementation for rudderAPI.ReleaseModuleServiceServer
 | ||||
| type ReleaseModuleServiceServer struct{} | ||||
| 
 | ||||
| // Version returns Rudder version based on helm version
 | ||||
| func (r *ReleaseModuleServiceServer) Version(ctx context.Context, in *rudderAPI.VersionReleaseRequest) (*rudderAPI.VersionReleaseResponse, error) { | ||||
| 	grpclog.Print("version") | ||||
| 	return &rudderAPI.VersionReleaseResponse{ | ||||
| 		Name:    "helm-rudder-native", | ||||
| 		Version: version.Version, | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| // InstallRelease creates a release using kubeClient.Create
 | ||||
| func (r *ReleaseModuleServiceServer) InstallRelease(ctx context.Context, in *rudderAPI.InstallReleaseRequest) (*rudderAPI.InstallReleaseResponse, error) { | ||||
| 	grpclog.Print("install") | ||||
| 	b := bytes.NewBufferString(in.Release.Manifest) | ||||
| 	err := kubeClient.Create(in.Release.Namespace, b, 500, false) | ||||
| 	if err != nil { | ||||
| 		grpclog.Printf("error when creating release: %v", err) | ||||
| 	} | ||||
| 	return &rudderAPI.InstallReleaseResponse{}, err | ||||
| } | ||||
| 
 | ||||
| // DeleteRelease deletes a provided release
 | ||||
| func (r *ReleaseModuleServiceServer) DeleteRelease(ctx context.Context, in *rudderAPI.DeleteReleaseRequest) (*rudderAPI.DeleteReleaseResponse, error) { | ||||
| 	grpclog.Print("delete") | ||||
| 
 | ||||
| 	resp := &rudderAPI.DeleteReleaseResponse{} | ||||
| 	rel := in.Release | ||||
| 	vs, err := tiller.GetVersionSet(clientset.Discovery()) | ||||
| 	if err != nil { | ||||
| 		return resp, fmt.Errorf("Could not get apiVersions from Kubernetes: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	kept, errs := tiller.DeleteRelease(rel, vs, kubeClient) | ||||
| 	rel.Manifest = kept | ||||
| 
 | ||||
| 	allErrors := "" | ||||
| 	for _, e := range errs { | ||||
| 		allErrors = allErrors + "\n" + e.Error() | ||||
| 	} | ||||
| 
 | ||||
| 	if len(allErrors) > 0 { | ||||
| 		err = fmt.Errorf(allErrors) | ||||
| 	} | ||||
| 
 | ||||
| 	return &rudderAPI.DeleteReleaseResponse{ | ||||
| 		Release: rel, | ||||
| 	}, err | ||||
| } | ||||
| 
 | ||||
| // RollbackRelease rolls back the release
 | ||||
| func (r *ReleaseModuleServiceServer) RollbackRelease(ctx context.Context, in *rudderAPI.RollbackReleaseRequest) (*rudderAPI.RollbackReleaseResponse, error) { | ||||
| 	grpclog.Print("rollback") | ||||
| 	c := bytes.NewBufferString(in.Current.Manifest) | ||||
| 	t := bytes.NewBufferString(in.Target.Manifest) | ||||
| 	err := kubeClient.Update(in.Target.Namespace, c, t, in.Force, in.Recreate, in.Timeout, in.Wait) | ||||
| 	return &rudderAPI.RollbackReleaseResponse{}, err | ||||
| } | ||||
| 
 | ||||
| // UpgradeRelease upgrades manifests using kubernetes client
 | ||||
| func (r *ReleaseModuleServiceServer) UpgradeRelease(ctx context.Context, in *rudderAPI.UpgradeReleaseRequest) (*rudderAPI.UpgradeReleaseResponse, error) { | ||||
| 	grpclog.Print("upgrade") | ||||
| 	c := bytes.NewBufferString(in.Current.Manifest) | ||||
| 	t := bytes.NewBufferString(in.Target.Manifest) | ||||
| 	err := kubeClient.Update(in.Target.Namespace, c, t, in.Force, in.Recreate, in.Timeout, in.Wait) | ||||
| 	// upgrade response object should be changed to include status
 | ||||
| 	return &rudderAPI.UpgradeReleaseResponse{}, err | ||||
| } | ||||
| 
 | ||||
| // ReleaseStatus retrieves release status
 | ||||
| func (r *ReleaseModuleServiceServer) ReleaseStatus(ctx context.Context, in *rudderAPI.ReleaseStatusRequest) (*rudderAPI.ReleaseStatusResponse, error) { | ||||
| 	grpclog.Print("status") | ||||
| 
 | ||||
| 	resp, err := kubeClient.Get(in.Release.Namespace, bytes.NewBufferString(in.Release.Manifest)) | ||||
| 	in.Release.Info.Status.Resources = resp | ||||
| 	return &rudderAPI.ReleaseStatusResponse{ | ||||
| 		Release: in.Release, | ||||
| 		Info:    in.Release.Info, | ||||
| 	}, err | ||||
| } | ||||
|  | @ -29,6 +29,7 @@ import ( | |||
| 
 | ||||
| 	goprom "github.com/grpc-ecosystem/go-grpc-prometheus" | ||||
| 	"github.com/spf13/cobra" | ||||
| 	"github.com/spf13/pflag" | ||||
| 
 | ||||
| 	"google.golang.org/grpc" | ||||
| 	"google.golang.org/grpc/credentials" | ||||
|  | @ -69,12 +70,15 @@ var rootServer *grpc.Server | |||
| // Any changes to env should be done before rootServer.Serve() is called.
 | ||||
| var env = environment.New() | ||||
| 
 | ||||
| var logger *log.Logger | ||||
| 
 | ||||
| var ( | ||||
| 	grpcAddr             = ":44134" | ||||
| 	probeAddr            = ":44135" | ||||
| 	traceAddr            = ":44136" | ||||
| 	enableTracing        = false | ||||
| 	store                = storageConfigMap | ||||
| 	remoteReleaseModules = false | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
|  | @ -92,63 +96,83 @@ Tiller is the server for Helm. It provides in-cluster resource management. | |||
| By default, Tiller listens for gRPC connections on port 44134. | ||||
| ` | ||||
| 
 | ||||
| var rootCommand = &cobra.Command{ | ||||
| func addFlags(flags *pflag.FlagSet) { | ||||
| 	flags.StringVarP(&grpcAddr, "listen", "l", ":44134", "address:port to listen on") | ||||
| 	flags.StringVar(&store, "storage", storageConfigMap, "storage driver to use. One of 'configmap' or 'memory'") | ||||
| 	flags.BoolVar(&enableTracing, "trace", false, "enable rpc tracing") | ||||
| 	flags.BoolVar(&remoteReleaseModules, "experimental-release", false, "enable experimental release modules") | ||||
| 
 | ||||
| 	flags.BoolVar(&tlsEnable, "tls", tlsEnableEnvVarDefault(), "enable TLS") | ||||
| 	flags.BoolVar(&tlsVerify, "tls-verify", tlsVerifyEnvVarDefault(), "enable TLS and verify remote certificate") | ||||
| 	flags.StringVar(&keyFile, "tls-key", tlsDefaultsFromEnv("tls-key"), "path to TLS private key file") | ||||
| 	flags.StringVar(&certFile, "tls-cert", tlsDefaultsFromEnv("tls-cert"), "path to TLS certificate file") | ||||
| 	flags.StringVar(&caCertFile, "tls-ca-cert", tlsDefaultsFromEnv("tls-ca-cert"), "trust certificates signed by this CA") | ||||
| } | ||||
| 
 | ||||
| func initLog() { | ||||
| 	if enableTracing { | ||||
| 		log.SetFlags(log.Lshortfile) | ||||
| 	} | ||||
| 	logger = newLogger("main") | ||||
| } | ||||
| 
 | ||||
| func main() { | ||||
| 	root := &cobra.Command{ | ||||
| 		Use:   "tiller", | ||||
| 		Short: "The Kubernetes Helm server.", | ||||
| 		Long:  globalUsage, | ||||
| 		Run:   start, | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	log.SetFlags(log.Flags() | log.Lshortfile) | ||||
| } | ||||
| 
 | ||||
| func main() { | ||||
| 	p := rootCommand.PersistentFlags() | ||||
| 	p.StringVarP(&grpcAddr, "listen", "l", ":44134", "address:port to listen on") | ||||
| 	p.StringVar(&store, "storage", storageConfigMap, "storage driver to use. One of 'configmap' or 'memory'") | ||||
| 	p.BoolVar(&enableTracing, "trace", false, "enable rpc tracing") | ||||
| 
 | ||||
| 	p.BoolVar(&tlsEnable, "tls", tlsEnableEnvVarDefault(), "enable TLS") | ||||
| 	p.BoolVar(&tlsVerify, "tls-verify", tlsVerifyEnvVarDefault(), "enable TLS and verify remote certificate") | ||||
| 	p.StringVar(&keyFile, "tls-key", tlsDefaultsFromEnv("tls-key"), "path to TLS private key file") | ||||
| 	p.StringVar(&certFile, "tls-cert", tlsDefaultsFromEnv("tls-cert"), "path to TLS certificate file") | ||||
| 	p.StringVar(&caCertFile, "tls-ca-cert", tlsDefaultsFromEnv("tls-ca-cert"), "trust certificates signed by this CA") | ||||
| 
 | ||||
| 	if err := rootCommand.Execute(); err != nil { | ||||
| 		fmt.Fprint(os.Stderr, err) | ||||
| 		os.Exit(1) | ||||
| 		PreRun: func(_ *cobra.Command, _ []string) { | ||||
| 			initLog() | ||||
| 		}, | ||||
| 	} | ||||
| 	addFlags(root.Flags()) | ||||
| 
 | ||||
| 	if err := root.Execute(); err != nil { | ||||
| 		logger.Fatal(err) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func newLogger(prefix string) *log.Logger { | ||||
| 	if len(prefix) > 0 { | ||||
| 		prefix = fmt.Sprintf("[%s] ", prefix) | ||||
| 	} | ||||
| 	return log.New(os.Stderr, prefix, log.Flags()) | ||||
| } | ||||
| 
 | ||||
| func start(c *cobra.Command, args []string) { | ||||
| 	clientset, err := kube.New(nil).ClientSet() | ||||
| 	if err != nil { | ||||
| 		fmt.Fprintf(os.Stderr, "Cannot initialize Kubernetes connection: %s\n", err) | ||||
| 		os.Exit(1) | ||||
| 		logger.Fatalf("Cannot initialize Kubernetes connection: %s", err) | ||||
| 	} | ||||
| 
 | ||||
| 	switch store { | ||||
| 	case storageMemory: | ||||
| 		env.Releases = storage.Init(driver.NewMemory()) | ||||
| 	case storageConfigMap: | ||||
| 		env.Releases = storage.Init(driver.NewConfigMaps(clientset.Core().ConfigMaps(namespace()))) | ||||
| 		cfgmaps := driver.NewConfigMaps(clientset.Core().ConfigMaps(namespace())) | ||||
| 		cfgmaps.Log = newLogger("storage/driver").Printf | ||||
| 
 | ||||
| 		env.Releases = storage.Init(cfgmaps) | ||||
| 		env.Releases.Log = newLogger("storage").Printf | ||||
| 	} | ||||
| 
 | ||||
| 	kubeClient := kube.New(nil) | ||||
| 	kubeClient.Log = newLogger("kube").Printf | ||||
| 	env.KubeClient = kubeClient | ||||
| 
 | ||||
| 	if tlsEnable || tlsVerify { | ||||
| 		opts := tlsutil.Options{CertFile: certFile, KeyFile: keyFile} | ||||
| 		if tlsVerify { | ||||
| 			opts.CaCertFile = caCertFile | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	var opts []grpc.ServerOption | ||||
| 	if tlsEnable || tlsVerify { | ||||
| 		cfg, err := tlsutil.ServerConfig(tlsOptions()) | ||||
| 		if err != nil { | ||||
| 			fmt.Fprintf(os.Stderr, "Could not create server TLS configuration: %v\n", err) | ||||
| 			os.Exit(1) | ||||
| 			logger.Fatalf("Could not create server TLS configuration: %v", err) | ||||
| 		} | ||||
| 		opts = append(opts, grpc.Creds(credentials.NewTLS(cfg))) | ||||
| 	} | ||||
|  | @ -157,14 +181,13 @@ func start(c *cobra.Command, args []string) { | |||
| 
 | ||||
| 	lstn, err := net.Listen("tcp", grpcAddr) | ||||
| 	if err != nil { | ||||
| 		fmt.Fprintf(os.Stderr, "Server died: %s\n", err) | ||||
| 		os.Exit(1) | ||||
| 		logger.Fatalf("Server died: %s", err) | ||||
| 	} | ||||
| 
 | ||||
| 	fmt.Printf("Starting Tiller %s (tls=%t)\n", version.GetVersion(), tlsEnable || tlsVerify) | ||||
| 	fmt.Printf("GRPC listening on %s\n", grpcAddr) | ||||
| 	fmt.Printf("Probes listening on %s\n", probeAddr) | ||||
| 	fmt.Printf("Storage driver is %s\n", env.Releases.Name()) | ||||
| 	logger.Printf("Starting Tiller %s (tls=%t)", version.GetVersion(), tlsEnable || tlsVerify) | ||||
| 	logger.Printf("GRPC listening on %s", grpcAddr) | ||||
| 	logger.Printf("Probes listening on %s", probeAddr) | ||||
| 	logger.Printf("Storage driver is %s", env.Releases.Name()) | ||||
| 
 | ||||
| 	if enableTracing { | ||||
| 		startTracing(traceAddr) | ||||
|  | @ -173,7 +196,8 @@ func start(c *cobra.Command, args []string) { | |||
| 	srvErrCh := make(chan error) | ||||
| 	probeErrCh := make(chan error) | ||||
| 	go func() { | ||||
| 		svc := tiller.NewReleaseServer(env, clientset) | ||||
| 		svc := tiller.NewReleaseServer(env, clientset, remoteReleaseModules) | ||||
| 		svc.Log = newLogger("tiller").Printf | ||||
| 		services.RegisterReleaseServiceServer(rootServer, svc) | ||||
| 		if err := rootServer.Serve(lstn); err != nil { | ||||
| 			srvErrCh <- err | ||||
|  | @ -194,10 +218,9 @@ func start(c *cobra.Command, args []string) { | |||
| 
 | ||||
| 	select { | ||||
| 	case err := <-srvErrCh: | ||||
| 		fmt.Fprintf(os.Stderr, "Server died: %s\n", err) | ||||
| 		os.Exit(1) | ||||
| 		logger.Fatalf("Server died: %s", err) | ||||
| 	case err := <-probeErrCh: | ||||
| 		fmt.Fprintf(os.Stderr, "Probes server died: %s\n", err) | ||||
| 		logger.Printf("Probes server died: %s", err) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -17,8 +17,6 @@ limitations under the License. | |||
| package main // import "k8s.io/helm/cmd/tiller"
 | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"log" | ||||
| 	"net/http" | ||||
| 
 | ||||
| 	_ "net/http/pprof" | ||||
|  | @ -27,7 +25,7 @@ import ( | |||
| ) | ||||
| 
 | ||||
| func startTracing(addr string) { | ||||
| 	fmt.Printf("Tracing server is listening on %s\n", addr) | ||||
| 	logger.Printf("Tracing server is listening on %s\n", addr) | ||||
| 	grpc.EnableTracing = true | ||||
| 
 | ||||
| 	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { | ||||
|  | @ -41,7 +39,7 @@ func startTracing(addr string) { | |||
| 
 | ||||
| 	go func() { | ||||
| 		if err := http.ListenAndServe(addr, nil); err != nil { | ||||
| 			log.Printf("tracing error: %s", err) | ||||
| 			logger.Printf("tracing error: %s", err) | ||||
| 		} | ||||
| 	}() | ||||
| } | ||||
|  |  | |||
|  | @ -0,0 +1,17 @@ | |||
| # Chart Repositories: Frequently Asked Questions | ||||
| 
 | ||||
| This section tracks some of the more frequently encountered issues with using chart repositories. | ||||
| 
 | ||||
| **We'd love your help** making this document better. To add, correct, or remove | ||||
| information, [file an issue](https://github.com/kubernetes/helm/issues) or | ||||
| send us a pull request. | ||||
| 
 | ||||
| ## Fetching | ||||
| 
 | ||||
| **Q: Why do I get a `unsupported protocol scheme ""` error when trying to fetch a chart from my custom repo?** | ||||
| 
 | ||||
| A: (Helm < 2.5.0) This is likely caused by you creating your chart repo index without specifying the `--url` flag. | ||||
| Try recreating your `index.yaml` file with a command like `heml repo index --url http://my-repo/charts .`, | ||||
| and then re-uploading it to your custom charts repo. | ||||
| 
 | ||||
| This behavior was changed in Helm 2.5.0. | ||||
|  | @ -170,7 +170,7 @@ data: | |||
|   {{- end}} | ||||
| ``` | ||||
| 
 | ||||
| Just for the same of making this point clear, let's adjust the above, and substitute an `*` for each whitespace that will be deleted following this rule. an `*` at the end of the line indicates a newline character that would be removed | ||||
| Just for the sake of making this point clear, let's adjust the above, and substitute an `*` for each whitespace that will be deleted following this rule. an `*` at the end of the line indicates a newline character that would be removed | ||||
| 
 | ||||
| ```yaml | ||||
| apiVersion: v1 | ||||
|  |  | |||
|  | @ -170,87 +170,6 @@ metadata: | |||
| 
 | ||||
| Now `{{ .Chart.Name }}` resolves to `mychart`, and `{{ .Chart.Version }}` resolves to `0.1.0`. | ||||
| 
 | ||||
| ## Creating override-able sections with `block` | ||||
| 
 | ||||
| Say we want to create a template in our `_helpers.tpl` file, but then override part of its behavior in our template. This is what blocks are for. Sometimes we don't want to just insert a template with `template`, but we want to sketch out a default and let another template override our default. This makes it possible for one chart to define a base template, but allow another chart to strategically override some of its behavior. | ||||
| 
 | ||||
| Blocks are declared like this: | ||||
| 
 | ||||
| ```yaml | ||||
| {{ block "NAME" PIPELINE }} | ||||
| {{ end }} | ||||
| ``` | ||||
| 
 | ||||
| Here, "NAME" is the name that a `define` block can use to override it, and PIPELINE is the pipeline that will set the scope. So let's rewrite our `labels:` section to use this strategy. We'll create a basic labels section in our `_helpers.tpl` file, but add some extra labels in the `configmap.yaml` template. | ||||
| 
 | ||||
| Let's start with `_helpers.tpl`: | ||||
| 
 | ||||
| ```yaml | ||||
| {{- define "my_labels" }} | ||||
|   labels: | ||||
|     chart: {{ .Chart.Name }} | ||||
|     version: {{ .Chart.Version }} | ||||
|     {{ block "my_extra_labels" . }}extras: false{{ end }} | ||||
| {{- end }} | ||||
| ``` | ||||
| 
 | ||||
| Inside of our `my_labels` template, we now declare a block called `my_extra_labels`. By default, this section will have one extra label: `extras: false`. If we were to execute this using the same `configmap.yaml` file from last time, we'd get this: | ||||
| 
 | ||||
| ```yaml | ||||
| # Source: mychart/templates/configmap.yaml | ||||
| apiVersion: v1 | ||||
| kind: ConfigMap | ||||
| metadata: | ||||
|   name: tinseled-womba-configmap | ||||
|   labels: | ||||
|     chart: mychart | ||||
|     version: 0.1.0 | ||||
|     extras: false | ||||
| data: | ||||
|   myvalue: "Hello World" | ||||
|   drink: "coffee" | ||||
|   food: "pizza" | ||||
| ``` | ||||
| 
 | ||||
| But inside of our `configmap.yaml` template, we can override `my_extra_labels`: | ||||
| 
 | ||||
| ```yaml | ||||
| {{- define "my_extra_labels" }}chart: {{ .Chart.Name }}{{ end -}} | ||||
| apiVersion: v1 | ||||
| kind: ConfigMap | ||||
| metadata: | ||||
|   name: {{ .Release.Name }}-configmap | ||||
|   {{- template "my_labels" . }} | ||||
| data: | ||||
|   myvalue: "Hello World" | ||||
|   {{- range $key, $val := .Values.favorite }} | ||||
|   {{ $key }}: {{ $val | quote }} | ||||
|   {{- end }} | ||||
| ``` | ||||
| 
 | ||||
| On the first line, we redefine `my_extra_labels` to include `chart: {{ .Chart.Name }}`. If we | ||||
| run this, we will get: | ||||
| 
 | ||||
| ```yaml | ||||
| # Source: mychart/templates/configmap.yaml | ||||
| apiVersion: v1 | ||||
| kind: ConfigMap | ||||
| metadata: | ||||
|   name: ignorant-scorp-configmap | ||||
|   labels: | ||||
|     chart: mychart | ||||
|     version: 0.1.0 | ||||
|     chart: mychart | ||||
| data: | ||||
|   myvalue: "Hello World" | ||||
|   drink: "coffee" | ||||
|   food: "pizza" | ||||
| ``` | ||||
| 
 | ||||
| Gone is the `extras: false` section, since that part of the template is now overridden by our new template, which placed `chart: mychart` into the output. | ||||
| 
 | ||||
| Blocks are not frequently used in Helm charts. But they do provide one mechanism for creating "abstract" charts, and then selectively overriding parts of the abstract template with concrete implementations. | ||||
| 
 | ||||
| ## The `include` function | ||||
| 
 | ||||
| Say we've defined a simple template that looks like this: | ||||
|  |  | |||
|  | @ -175,57 +175,33 @@ Globals are useful for passing information like this, though it does take some p | |||
| 
 | ||||
| ## Sharing Templates with Subcharts | ||||
| 
 | ||||
| Parent charts and subcharts can share templates. This can become very powerful when coupled with `block`s. For example, we can define a `block` in the `subchart` ConfigMap like this: | ||||
| Parent charts and subcharts can share templates. Any defined block in any chart is | ||||
| available to other charts. | ||||
| 
 | ||||
| ```yaml | ||||
| apiVersion: v1 | ||||
| kind: ConfigMap | ||||
| metadata: | ||||
|   name: {{ .Release.Name }}-cfgmap2 | ||||
|   {{block "labels" . }}from: mysubchart{{ end }} | ||||
| data: | ||||
|   dessert: {{ .Values.dessert }} | ||||
|   salad: {{ .Values.global.salad }} | ||||
| ``` | ||||
| 
 | ||||
| Running this would produce: | ||||
| 
 | ||||
| ```yaml | ||||
| # Source: mychart/charts/mysubchart/templates/configmap.yaml | ||||
| apiVersion: v1 | ||||
| kind: ConfigMap | ||||
| metadata: | ||||
|   name: gaudy-mastiff-cfgmap2 | ||||
|   from: mysubchart | ||||
| data: | ||||
|   dessert: ice cream | ||||
|   salad: caesar | ||||
| ``` | ||||
| 
 | ||||
| Note that the `from:` line says `mysubchart`. In a previous section, we created `mychart/templates/_helpers.tpl`. Let's define a new named template there called `labels` to match the declaration on the block above. | ||||
| For example, we can define a simple template like this: | ||||
| 
 | ||||
| ```yaml | ||||
| {{- define "labels" }}from: mychart{{ end }} | ||||
| ``` | ||||
| 
 | ||||
| Recall how the labels on templates are _globally shared_. That means that if we create a block named `labels` in one chart, and then define an override named `labels` in another chart, the override will be applied. | ||||
| Recall how the labels on templates are _globally shared_. Thus, the `labels` chart | ||||
| can be included from any other chart. | ||||
| 
 | ||||
| Now if we do a `helm install --dry-run --debug mychart`, it will override the block: | ||||
| While chart developers have a choice between `include` and `template`, one advantage | ||||
| of using `include` is that `include` can dynamically reference templates: | ||||
| 
 | ||||
| ```yaml | ||||
| # Source: mychart/charts/mysubchart/templates/configmap.yaml | ||||
| apiVersion: v1 | ||||
| kind: ConfigMap | ||||
| metadata: | ||||
|   name: nasal-cheetah-cfgmap2 | ||||
|   from: mychart | ||||
| data: | ||||
|   dessert: ice cream | ||||
|   salad: caesar | ||||
| {{ include $mytemplate }} | ||||
| ``` | ||||
| 
 | ||||
| Now `from:` is set to `mychart` because the block was overridden. | ||||
| The above will dereference `$mytemplate`. The `template` function, in contrast, | ||||
| will only accept a string literal. | ||||
| 
 | ||||
| Using this method, you can write flexible "base" charts that can be added as subcharts to many different charts, and which will support selective overriding using blocks. | ||||
| ## Avoid Using Blocks | ||||
| 
 | ||||
| This section of the guide has focused on subcharts. We've seen how to inherit values, how to use global values, and how to override templates with blocks. In the next section we will turn to debugging, and learn how to catch errors in templates. | ||||
| 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 | ||||
| are provided, the one selected is unpredictable. | ||||
| 
 | ||||
| The suggestion is to instead use `include`. | ||||
|  |  | |||
|  | @ -1,8 +1,8 @@ | |||
| # Chart Tests | ||||
| 
 | ||||
| A chart contains a number of Kubernetes resources and components that work together. As a chart author, you may want to write some tests that validate that your charts works as expected when it is installed. These tests also help the chart consumer understand what your chart is supposed to do. | ||||
| A chart contains a number of Kubernetes resources and components that work together. As a chart author, you may want to write some tests that validate that your chart works as expected when it is installed. These tests also help the chart consumer understand what your chart is supposed to do. | ||||
| 
 | ||||
| A **test** in a helm chart lives under the `templates/` directory and is a pod definition that specifies a container with a given command to run. The container should exist successfully (exit 0) for a test to be considered a success. The pod definiton must contain one of the helm test hook annotations: `helm.sh/hooks: test-success` or `helm.sh/hooks: test-failure`. | ||||
| A **test** in a helm chart lives under the `templates/` directory and is a pod definition that specifies a container with a given command to run. The container should exit successfully (exit 0) for a test to be considered a success. The pod definiton must contain one of the helm test hook annotations: `helm.sh/hooks: test-success` or `helm.sh/hooks: test-failure`. | ||||
| 
 | ||||
| Example tests: | ||||
| - Validate that your configuration from the values.yaml file was properly injected. | ||||
|  | @ -17,12 +17,12 @@ You can run the pre-defined tests in Helm on a release using the command `helm t | |||
| 
 | ||||
| In Helm, there are two test hooks: `test-success` and `test-failure` | ||||
| 
 | ||||
| `test-success` indiciates that test pod should complete successfully. In other words, the containers in the pod should exit 0. | ||||
| `test-failure` is a way to assert that a test pod should not complete successfully. If the containers in the pod do not exit 0, that indiciates success. | ||||
| `test-success` indicates that test pod should complete successfully. In other words, the containers in the pod should exit 0. | ||||
| `test-failure` is a way to assert that a test pod should not complete successfully. If the containers in the pod do not exit 0, that indicates success. | ||||
| 
 | ||||
| ## Example Test | ||||
| 
 | ||||
| Here is an example of a helm test pod definition in an example maraidb chart: | ||||
| Here is an example of a helm test pod definition in an example mariadb chart: | ||||
| 
 | ||||
| ``` | ||||
| mariadb/ | ||||
|  |  | |||
|  | @ -229,6 +229,43 @@ Managing charts with `requirements.yaml` is a good way to easily keep | |||
| charts updated, and also share requirements information throughout a | ||||
| team. | ||||
| 
 | ||||
| #### Alias field in requirements.yaml | ||||
| 
 | ||||
| In addition to the other fields above, each requirements entry may contain | ||||
| the optional field `alias`. | ||||
| 
 | ||||
| Adding an alias for a dependency chart would put | ||||
| a chart in dependencies using alias as name of new dependency. | ||||
| 
 | ||||
| One can use `alias` in cases where they need to access a chart | ||||
| with other name(s). | ||||
| 
 | ||||
| ```` | ||||
| # parentchart/requirements.yaml | ||||
| dependencies: | ||||
|       - name: subchart | ||||
|         repository: http://localhost:10191 | ||||
|         version: 0.1.0 | ||||
|         alias: new-subchart-1 | ||||
|       - name: subchart | ||||
|         repository: http://localhost:10191 | ||||
|         version: 0.1.0 | ||||
|         alias: new-subchart-2 | ||||
|       - name: subchart | ||||
|         repository: http://localhost:10191 | ||||
|         version: 0.1.0 | ||||
| ```` | ||||
| 
 | ||||
| In the above example we will get 3 depenendencies in all for `parentchart` | ||||
| ``` | ||||
| subchart | ||||
| new-subchart-1 | ||||
| new-subchart-2 | ||||
| ``` | ||||
| 
 | ||||
| Manual way of achieving this is copy/pasting same chart in | ||||
| `charts/` directory multiple times with different name. | ||||
| 
 | ||||
| #### Tags and Condition fields in requirements.yaml | ||||
| 
 | ||||
| In addition to the other fields above, each requirements entry may contain | ||||
|  | @ -687,17 +724,6 @@ parent chart. | |||
| 
 | ||||
| Also, global variables of parent charts take precedence over the global variables from subcharts. | ||||
| 
 | ||||
| _Global sections are restricted to only simple key/value pairs. They do | ||||
| not support nesting._ | ||||
| 
 | ||||
| For example, the following is **illegal** and will not work: | ||||
| 
 | ||||
| ```yaml | ||||
| global: | ||||
|   foo:  # It is illegal to nest an object inside of global. | ||||
|     bar: baz | ||||
| ``` | ||||
| 
 | ||||
| ### References | ||||
| 
 | ||||
| When it comes to writing templates and values files, there are several | ||||
|  |  | |||
|  | @ -79,8 +79,13 @@ Helm client will pause while the Job is run. | |||
| 
 | ||||
| For all other kinds, as soon as Kubernetes marks the resource as loaded | ||||
| (added or updated), the resource is considered "Ready". When many | ||||
| resources are declared in a hook, the resources are executed serially, | ||||
| but the order of their execution is not guaranteed. | ||||
| resources are declared in a hook, the resources are executed serially. If they | ||||
| have hook weights (see below), they are executed in weighted order. Otherwise, | ||||
| ordering is not guaranteed. (In Helm 2.3.0 and after, they are sorted | ||||
| alphabetically. That behavior, though, is not considered binding and could change | ||||
| in the future.) It is considered good practice to add a hook weight, and set it | ||||
| to `0` if weight is not important. | ||||
| 
 | ||||
| 
 | ||||
| ### Hook resources are unmanaged | ||||
| 
 | ||||
|  | @ -150,19 +155,20 @@ One resource can implement multiple hooks: | |||
| 
 | ||||
| Similarly, there is no limit to the number of different resources that | ||||
| may implement a given hook. For example, one could declare both a secret | ||||
| and a config map as a pre-install hook. It is important to keep in mind, | ||||
| though, that there are no ordering guarantees about hooks. | ||||
| and a config map as a pre-install hook. | ||||
| 
 | ||||
| When subcharts declare hooks, those are also evaluated. There is no way | ||||
| for a top-level chart to disable the hooks declared by subcharts. And | ||||
| again, there is no guaranteed ordering. | ||||
| for a top-level chart to disable the hooks declared by subcharts. | ||||
| 
 | ||||
| It is also possible to define a weight for a hook which will help build a deterministic executing order. Weights are defined using the following annotation: | ||||
| It is also possible to define a weight for a hook which will help build a | ||||
| deterministic executing order. Weights are defined using the following annotation: | ||||
| 
 | ||||
| ``` | ||||
|   annotations: | ||||
|     "helm.sh/hook-weight": "5" | ||||
| ``` | ||||
| 
 | ||||
| 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.  | ||||
| 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.  | ||||
| 
 | ||||
|  |  | |||
|  | @ -78,7 +78,7 @@ Go provides a way for setting template options to control behavior | |||
| when a map is indexed with a key that's not present in the map. This | ||||
| is typically set with template.Options("missingkey=option"), where option | ||||
| can be default, zero, or error. While setting this option to error will | ||||
| stop execution with an arror, this would apply to every missing key in the | ||||
| stop execution with an error, this would apply to every missing key in the | ||||
| map. There may be situations where a chart developer wants to enforce this | ||||
| behavior for select values in the values.yml file. | ||||
| 
 | ||||
|  |  | |||
|  | @ -174,6 +174,7 @@ Common commit types: | |||
| - feat: Add a new feature | ||||
| - docs: Change documentation | ||||
| - test: Improve testing | ||||
| - ref: refactor existing code | ||||
| 
 | ||||
| Common scopes: | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| #Alpine: A simple Helm chart | ||||
| # Alpine: A simple Helm chart | ||||
| 
 | ||||
| Run a single pod of Alpine Linux. | ||||
| 
 | ||||
|  |  | |||
|  | @ -33,14 +33,14 @@ Environment: | |||
| 
 | ||||
| ``` | ||||
|       --debug                     enable verbose output | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "~/.helm") | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") | ||||
|       --host string               address of tiller. Overrides $HELM_HOST | ||||
|       --kube-context string       name of the kubeconfig context to use | ||||
|       --tiller-namespace string   namespace of tiller (default "kube-system") | ||||
| ``` | ||||
| 
 | ||||
| ### SEE ALSO | ||||
| * [helm completion](helm_completion.md)	 - Generate bash autocompletions script | ||||
| * [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 | ||||
| * [helm dependency](helm_dependency.md)	 - manage a chart's dependencies | ||||
|  | @ -66,4 +66,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 16-Apr-2017 | ||||
| ###### Auto generated by spf13/cobra on 29-May-2017 | ||||
|  |  | |||
|  | @ -1,31 +1,31 @@ | |||
| ## helm completion | ||||
| 
 | ||||
| Generate bash autocompletions script | ||||
| Generate autocompletions script for the specified shell (bash or zsh) | ||||
| 
 | ||||
| ### Synopsis | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| Generate bash autocompletions script for Helm. | ||||
| Generate autocompletions script for Helm for the specified shell (bash or zsh). | ||||
| 
 | ||||
| This command can generate shell autocompletions. | ||||
| This command can generate shell autocompletions. e.g. | ||||
| 
 | ||||
| 	$ helm completion | ||||
| 	$ helm completion bash | ||||
| 
 | ||||
| Can be sourced as such | ||||
| 
 | ||||
| 	$ source <(helm completion) | ||||
| 	$ source <(helm completion bash) | ||||
| 
 | ||||
| 
 | ||||
| ``` | ||||
| helm completion | ||||
| helm completion SHELL | ||||
| ``` | ||||
| 
 | ||||
| ### Options inherited from parent commands | ||||
| 
 | ||||
| ``` | ||||
|       --debug                     enable verbose output | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "~/.helm") | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") | ||||
|       --host string               address of tiller. Overrides $HELM_HOST | ||||
|       --kube-context string       name of the kubeconfig context to use | ||||
|       --tiller-namespace string   namespace of tiller (default "kube-system") | ||||
|  | @ -34,4 +34,4 @@ helm completion | |||
| ### SEE ALSO | ||||
| * [helm](helm.md)	 - The Helm package manager for Kubernetes. | ||||
| 
 | ||||
| ###### Auto generated by spf13/cobra on 16-Apr-2017 | ||||
| ###### Auto generated by spf13/cobra on 29-May-2017 | ||||
|  |  | |||
|  | @ -44,7 +44,7 @@ helm create NAME | |||
| 
 | ||||
| ``` | ||||
|       --debug                     enable verbose output | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "~/.helm") | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") | ||||
|       --host string               address of tiller. Overrides $HELM_HOST | ||||
|       --kube-context string       name of the kubeconfig context to use | ||||
|       --tiller-namespace string   namespace of tiller (default "kube-system") | ||||
|  | @ -53,4 +53,4 @@ helm create NAME | |||
| ### SEE ALSO | ||||
| * [helm](helm.md)	 - The Helm package manager for Kubernetes. | ||||
| 
 | ||||
| ###### Auto generated by spf13/cobra on 16-Apr-2017 | ||||
| ###### Auto generated by spf13/cobra on 29-May-2017 | ||||
|  |  | |||
|  | @ -35,7 +35,7 @@ helm delete [flags] RELEASE_NAME [...] | |||
| 
 | ||||
| ``` | ||||
|       --debug                     enable verbose output | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "~/.helm") | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") | ||||
|       --host string               address of tiller. Overrides $HELM_HOST | ||||
|       --kube-context string       name of the kubeconfig context to use | ||||
|       --tiller-namespace string   namespace of tiller (default "kube-system") | ||||
|  | @ -44,4 +44,4 @@ helm delete [flags] RELEASE_NAME [...] | |||
| ### SEE ALSO | ||||
| * [helm](helm.md)	 - The Helm package manager for Kubernetes. | ||||
| 
 | ||||
| ###### Auto generated by spf13/cobra on 16-Apr-2017 | ||||
| ###### Auto generated by spf13/cobra on 29-May-2017 | ||||
|  |  | |||
|  | @ -58,7 +58,7 @@ for this case. | |||
| 
 | ||||
| ``` | ||||
|       --debug                     enable verbose output | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "~/.helm") | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") | ||||
|       --host string               address of tiller. Overrides $HELM_HOST | ||||
|       --kube-context string       name of the kubeconfig context to use | ||||
|       --tiller-namespace string   namespace of tiller (default "kube-system") | ||||
|  | @ -70,4 +70,4 @@ for this case. | |||
| * [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 16-Apr-2017 | ||||
| ###### Auto generated by spf13/cobra on 29-May-2017 | ||||
|  |  | |||
|  | @ -31,7 +31,7 @@ helm dependency build [flags] CHART | |||
| 
 | ||||
| ``` | ||||
|       --debug                     enable verbose output | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "~/.helm") | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") | ||||
|       --host string               address of tiller. Overrides $HELM_HOST | ||||
|       --kube-context string       name of the kubeconfig context to use | ||||
|       --tiller-namespace string   namespace of tiller (default "kube-system") | ||||
|  | @ -40,4 +40,4 @@ helm dependency build [flags] CHART | |||
| ### SEE ALSO | ||||
| * [helm dependency](helm_dependency.md)	 - manage a chart's dependencies | ||||
| 
 | ||||
| ###### Auto generated by spf13/cobra on 16-Apr-2017 | ||||
| ###### Auto generated by spf13/cobra on 29-May-2017 | ||||
|  |  | |||
|  | @ -23,7 +23,7 @@ helm dependency list [flags] CHART | |||
| 
 | ||||
| ``` | ||||
|       --debug                     enable verbose output | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "~/.helm") | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") | ||||
|       --host string               address of tiller. Overrides $HELM_HOST | ||||
|       --kube-context string       name of the kubeconfig context to use | ||||
|       --tiller-namespace string   namespace of tiller (default "kube-system") | ||||
|  | @ -32,4 +32,4 @@ helm dependency list [flags] CHART | |||
| ### SEE ALSO | ||||
| * [helm dependency](helm_dependency.md)	 - manage a chart's dependencies | ||||
| 
 | ||||
| ###### Auto generated by spf13/cobra on 16-Apr-2017 | ||||
| ###### Auto generated by spf13/cobra on 29-May-2017 | ||||
|  |  | |||
|  | @ -36,7 +36,7 @@ helm dependency update [flags] CHART | |||
| 
 | ||||
| ``` | ||||
|       --debug                     enable verbose output | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "~/.helm") | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") | ||||
|       --host string               address of tiller. Overrides $HELM_HOST | ||||
|       --kube-context string       name of the kubeconfig context to use | ||||
|       --tiller-namespace string   namespace of tiller (default "kube-system") | ||||
|  | @ -45,4 +45,4 @@ helm dependency update [flags] CHART | |||
| ### SEE ALSO | ||||
| * [helm dependency](helm_dependency.md)	 - manage a chart's dependencies | ||||
| 
 | ||||
| ###### Auto generated by spf13/cobra on 16-Apr-2017 | ||||
| ###### Auto generated by spf13/cobra on 29-May-2017 | ||||
|  |  | |||
|  | @ -27,9 +27,14 @@ helm fetch [flags] [chart URL | repo/chartname] [...] | |||
| ### Options | ||||
| 
 | ||||
| ``` | ||||
|       --ca-file string       verify certificates of HTTPS-enabled servers using this CA bundle | ||||
|       --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-a'. If --version is set, this is ignored. | ||||
|       --key-file string      identify HTTPS client using this SSL key file | ||||
|       --keyring string       keyring containing public keys (default "~/.gnupg/pubring.gpg") | ||||
|       --prov                 fetch the provenance file, but don't perform verification | ||||
|       --repo string          chart repository url where to locate the requested chart | ||||
|       --untar                if set to true, will untar the chart after downloading it | ||||
|       --untardir string      if untar is specified, this flag specifies the name of the directory into which the chart is expanded (default ".") | ||||
|       --verify               verify the package against its signature | ||||
|  | @ -40,7 +45,7 @@ helm fetch [flags] [chart URL | repo/chartname] [...] | |||
| 
 | ||||
| ``` | ||||
|       --debug                     enable verbose output | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "~/.helm") | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") | ||||
|       --host string               address of tiller. Overrides $HELM_HOST | ||||
|       --kube-context string       name of the kubeconfig context to use | ||||
|       --tiller-namespace string   namespace of tiller (default "kube-system") | ||||
|  | @ -49,4 +54,4 @@ helm fetch [flags] [chart URL | repo/chartname] [...] | |||
| ### SEE ALSO | ||||
| * [helm](helm.md)	 - The Helm package manager for Kubernetes. | ||||
| 
 | ||||
| ###### Auto generated by spf13/cobra on 16-Apr-2017 | ||||
| ###### Auto generated by spf13/cobra on 29-May-2017 | ||||
|  |  | |||
|  | @ -37,7 +37,7 @@ helm get [flags] RELEASE_NAME | |||
| 
 | ||||
| ``` | ||||
|       --debug                     enable verbose output | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "~/.helm") | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") | ||||
|       --host string               address of tiller. Overrides $HELM_HOST | ||||
|       --kube-context string       name of the kubeconfig context to use | ||||
|       --tiller-namespace string   namespace of tiller (default "kube-system") | ||||
|  | @ -49,4 +49,4 @@ helm get [flags] RELEASE_NAME | |||
| * [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 16-Apr-2017 | ||||
| ###### Auto generated by spf13/cobra on 29-May-2017 | ||||
|  |  | |||
|  | @ -25,7 +25,7 @@ helm get hooks [flags] RELEASE_NAME | |||
| 
 | ||||
| ``` | ||||
|       --debug                     enable verbose output | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "~/.helm") | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") | ||||
|       --host string               address of tiller. Overrides $HELM_HOST | ||||
|       --kube-context string       name of the kubeconfig context to use | ||||
|       --tiller-namespace string   namespace of tiller (default "kube-system") | ||||
|  | @ -34,4 +34,4 @@ helm get hooks [flags] RELEASE_NAME | |||
| ### SEE ALSO | ||||
| * [helm get](helm_get.md)	 - download a named release | ||||
| 
 | ||||
| ###### Auto generated by spf13/cobra on 16-Apr-2017 | ||||
| ###### Auto generated by spf13/cobra on 29-May-2017 | ||||
|  |  | |||
|  | @ -27,7 +27,7 @@ helm get manifest [flags] RELEASE_NAME | |||
| 
 | ||||
| ``` | ||||
|       --debug                     enable verbose output | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "~/.helm") | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") | ||||
|       --host string               address of tiller. Overrides $HELM_HOST | ||||
|       --kube-context string       name of the kubeconfig context to use | ||||
|       --tiller-namespace string   namespace of tiller (default "kube-system") | ||||
|  | @ -36,4 +36,4 @@ helm get manifest [flags] RELEASE_NAME | |||
| ### SEE ALSO | ||||
| * [helm get](helm_get.md)	 - download a named release | ||||
| 
 | ||||
| ###### Auto generated by spf13/cobra on 16-Apr-2017 | ||||
| ###### Auto generated by spf13/cobra on 29-May-2017 | ||||
|  |  | |||
|  | @ -24,7 +24,7 @@ helm get values [flags] RELEASE_NAME | |||
| 
 | ||||
| ``` | ||||
|       --debug                     enable verbose output | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "~/.helm") | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") | ||||
|       --host string               address of tiller. Overrides $HELM_HOST | ||||
|       --kube-context string       name of the kubeconfig context to use | ||||
|       --tiller-namespace string   namespace of tiller (default "kube-system") | ||||
|  | @ -33,4 +33,4 @@ helm get values [flags] RELEASE_NAME | |||
| ### SEE ALSO | ||||
| * [helm get](helm_get.md)	 - download a named release | ||||
| 
 | ||||
| ###### Auto generated by spf13/cobra on 16-Apr-2017 | ||||
| ###### Auto generated by spf13/cobra on 29-May-2017 | ||||
|  |  | |||
|  | @ -40,7 +40,7 @@ helm history [flags] RELEASE_NAME | |||
| 
 | ||||
| ``` | ||||
|       --debug                     enable verbose output | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "~/.helm") | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") | ||||
|       --host string               address of tiller. Overrides $HELM_HOST | ||||
|       --kube-context string       name of the kubeconfig context to use | ||||
|       --tiller-namespace string   namespace of tiller (default "kube-system") | ||||
|  | @ -49,4 +49,4 @@ helm history [flags] RELEASE_NAME | |||
| ### SEE ALSO | ||||
| * [helm](helm.md)	 - The Helm package manager for Kubernetes. | ||||
| 
 | ||||
| ###### Auto generated by spf13/cobra on 16-Apr-2017 | ||||
| ###### Auto generated by spf13/cobra on 29-May-2017 | ||||
|  |  | |||
|  | @ -18,7 +18,7 @@ helm home | |||
| 
 | ||||
| ``` | ||||
|       --debug                     enable verbose output | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "~/.helm") | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") | ||||
|       --host string               address of tiller. Overrides $HELM_HOST | ||||
|       --kube-context string       name of the kubeconfig context to use | ||||
|       --tiller-namespace string   namespace of tiller (default "kube-system") | ||||
|  | @ -27,4 +27,4 @@ helm home | |||
| ### SEE ALSO | ||||
| * [helm](helm.md)	 - The Helm package manager for Kubernetes. | ||||
| 
 | ||||
| ###### Auto generated by spf13/cobra on 16-Apr-2017 | ||||
| ###### Auto generated by spf13/cobra on 29-May-2017 | ||||
|  |  | |||
|  | @ -38,6 +38,7 @@ helm init | |||
|       --dry-run                  do not install local or remote | ||||
|       --local-repo-url string    URL for local repository (default "http://127.0.0.1:8879/charts") | ||||
|       --net-host                 install tiller with net=host | ||||
|       --service-account string   name of service account | ||||
|       --skip-refresh             do not refresh (download) the local repository cache | ||||
|       --stable-repo-url string   URL for stable repository (default "https://kubernetes-charts.storage.googleapis.com") | ||||
|   -i, --tiller-image string      override tiller image | ||||
|  | @ -53,7 +54,7 @@ helm init | |||
| 
 | ||||
| ``` | ||||
|       --debug                     enable verbose output | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "~/.helm") | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") | ||||
|       --host string               address of tiller. Overrides $HELM_HOST | ||||
|       --kube-context string       name of the kubeconfig context to use | ||||
|       --tiller-namespace string   namespace of tiller (default "kube-system") | ||||
|  | @ -62,4 +63,4 @@ helm init | |||
| ### SEE ALSO | ||||
| * [helm](helm.md)	 - The Helm package manager for Kubernetes. | ||||
| 
 | ||||
| ###### Auto generated by spf13/cobra on 18-Apr-2017 | ||||
| ###### Auto generated by spf13/cobra on 29-May-2017 | ||||
|  |  | |||
|  | @ -19,7 +19,11 @@ helm inspect [CHART] | |||
| ### Options | ||||
| 
 | ||||
| ``` | ||||
|       --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 | ||||
|       --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 | ||||
|       --verify             verify the provenance data for this chart | ||||
|       --version string     version of the chart. By default, the newest chart is shown | ||||
| ``` | ||||
|  | @ -28,7 +32,7 @@ helm inspect [CHART] | |||
| 
 | ||||
| ``` | ||||
|       --debug                     enable verbose output | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "~/.helm") | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") | ||||
|       --host string               address of tiller. Overrides $HELM_HOST | ||||
|       --kube-context string       name of the kubeconfig context to use | ||||
|       --tiller-namespace string   namespace of tiller (default "kube-system") | ||||
|  | @ -39,4 +43,4 @@ helm inspect [CHART] | |||
| * [helm inspect chart](helm_inspect_chart.md)	 - shows inspect chart | ||||
| * [helm inspect values](helm_inspect_values.md)	 - shows inspect values | ||||
| 
 | ||||
| ###### Auto generated by spf13/cobra on 16-Apr-2017 | ||||
| ###### Auto generated by spf13/cobra on 29-May-2017 | ||||
|  |  | |||
|  | @ -17,7 +17,11 @@ helm inspect chart [CHART] | |||
| ### Options | ||||
| 
 | ||||
| ``` | ||||
|       --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 | ||||
|       --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 | ||||
|       --verify             verify the provenance data for this chart | ||||
|       --version string     version of the chart. By default, the newest chart is shown | ||||
| ``` | ||||
|  | @ -26,7 +30,7 @@ helm inspect chart [CHART] | |||
| 
 | ||||
| ``` | ||||
|       --debug                     enable verbose output | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "~/.helm") | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") | ||||
|       --host string               address of tiller. Overrides $HELM_HOST | ||||
|       --kube-context string       name of the kubeconfig context to use | ||||
|       --tiller-namespace string   namespace of tiller (default "kube-system") | ||||
|  | @ -35,4 +39,4 @@ helm inspect chart [CHART] | |||
| ### SEE ALSO | ||||
| * [helm inspect](helm_inspect.md)	 - inspect a chart | ||||
| 
 | ||||
| ###### Auto generated by spf13/cobra on 16-Apr-2017 | ||||
| ###### Auto generated by spf13/cobra on 29-May-2017 | ||||
|  |  | |||
|  | @ -17,7 +17,11 @@ helm inspect values [CHART] | |||
| ### Options | ||||
| 
 | ||||
| ``` | ||||
|       --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 | ||||
|       --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 | ||||
|       --verify             verify the provenance data for this chart | ||||
|       --version string     version of the chart. By default, the newest chart is shown | ||||
| ``` | ||||
|  | @ -26,7 +30,7 @@ helm inspect values [CHART] | |||
| 
 | ||||
| ``` | ||||
|       --debug                     enable verbose output | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "~/.helm") | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") | ||||
|       --host string               address of tiller. Overrides $HELM_HOST | ||||
|       --kube-context string       name of the kubeconfig context to use | ||||
|       --tiller-namespace string   namespace of tiller (default "kube-system") | ||||
|  | @ -35,4 +39,4 @@ helm inspect values [CHART] | |||
| ### SEE ALSO | ||||
| * [helm inspect](helm_inspect.md)	 - inspect a chart | ||||
| 
 | ||||
| ###### Auto generated by spf13/cobra on 16-Apr-2017 | ||||
| ###### Auto generated by spf13/cobra on 29-May-2017 | ||||
|  |  | |||
|  | @ -68,13 +68,18 @@ helm install [CHART] | |||
| ### Options | ||||
| 
 | ||||
| ``` | ||||
|       --ca-file string         verify certificates of HTTPS-enabled servers using this CA bundle | ||||
|       --cert-file string       identify HTTPS client using this SSL certificate file | ||||
|       --devel                  use development versions, too. Equivalent to version '>0.0.0-a'. If --version is set, this is ignored. | ||||
|       --dry-run                simulate an 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 | ||||
|       --no-hooks               prevent hooks from running during install | ||||
|       --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) | ||||
|       --timeout int            time in seconds to wait for any individual kubernetes operation (like Jobs for hooks) (default 300) | ||||
|       --tls                    enable TLS for request | ||||
|  | @ -92,7 +97,7 @@ helm install [CHART] | |||
| 
 | ||||
| ``` | ||||
|       --debug                     enable verbose output | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "~/.helm") | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") | ||||
|       --host string               address of tiller. Overrides $HELM_HOST | ||||
|       --kube-context string       name of the kubeconfig context to use | ||||
|       --tiller-namespace string   namespace of tiller (default "kube-system") | ||||
|  | @ -101,4 +106,4 @@ helm install [CHART] | |||
| ### SEE ALSO | ||||
| * [helm](helm.md)	 - The Helm package manager for Kubernetes. | ||||
| 
 | ||||
| ###### Auto generated by spf13/cobra on 16-Apr-2017 | ||||
| ###### Auto generated by spf13/cobra on 29-May-2017 | ||||
|  |  | |||
|  | @ -28,7 +28,7 @@ helm lint [flags] PATH | |||
| 
 | ||||
| ``` | ||||
|       --debug                     enable verbose output | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "~/.helm") | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") | ||||
|       --host string               address of tiller. Overrides $HELM_HOST | ||||
|       --kube-context string       name of the kubeconfig context to use | ||||
|       --tiller-namespace string   namespace of tiller (default "kube-system") | ||||
|  | @ -37,4 +37,4 @@ helm lint [flags] PATH | |||
| ### SEE ALSO | ||||
| * [helm](helm.md)	 - The Helm package manager for Kubernetes. | ||||
| 
 | ||||
| ###### Auto generated by spf13/cobra on 16-Apr-2017 | ||||
| ###### Auto generated by spf13/cobra on 29-May-2017 | ||||
|  |  | |||
|  | @ -61,7 +61,7 @@ helm list [flags] [FILTER] | |||
| 
 | ||||
| ``` | ||||
|       --debug                     enable verbose output | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "~/.helm") | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") | ||||
|       --host string               address of tiller. Overrides $HELM_HOST | ||||
|       --kube-context string       name of the kubeconfig context to use | ||||
|       --tiller-namespace string   namespace of tiller (default "kube-system") | ||||
|  | @ -70,4 +70,4 @@ helm list [flags] [FILTER] | |||
| ### SEE ALSO | ||||
| * [helm](helm.md)	 - The Helm package manager for Kubernetes. | ||||
| 
 | ||||
| ###### Auto generated by spf13/cobra on 16-Apr-2017 | ||||
| ###### Auto generated by spf13/cobra on 29-May-2017 | ||||
|  |  | |||
|  | @ -23,6 +23,7 @@ helm package [flags] [CHART_PATH] [...] | |||
| ### Options | ||||
| 
 | ||||
| ``` | ||||
|   -u, --dependency-update    update dependencies from "requirements.yaml" to dir "charts/" before packaging | ||||
|   -d, --destination string   location to write the chart. (default ".") | ||||
|       --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") | ||||
|  | @ -35,7 +36,7 @@ helm package [flags] [CHART_PATH] [...] | |||
| 
 | ||||
| ``` | ||||
|       --debug                     enable verbose output | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "~/.helm") | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") | ||||
|       --host string               address of tiller. Overrides $HELM_HOST | ||||
|       --kube-context string       name of the kubeconfig context to use | ||||
|       --tiller-namespace string   namespace of tiller (default "kube-system") | ||||
|  | @ -44,4 +45,4 @@ helm package [flags] [CHART_PATH] [...] | |||
| ### SEE ALSO | ||||
| * [helm](helm.md)	 - The Helm package manager for Kubernetes. | ||||
| 
 | ||||
| ###### Auto generated by spf13/cobra on 16-Apr-2017 | ||||
| ###### Auto generated by spf13/cobra on 5-Jun-2017 | ||||
|  |  | |||
|  | @ -13,7 +13,7 @@ Manage client-side Helm plugins. | |||
| 
 | ||||
| ``` | ||||
|       --debug                     enable verbose output | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "~/.helm") | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") | ||||
|       --host string               address of tiller. Overrides $HELM_HOST | ||||
|       --kube-context string       name of the kubeconfig context to use | ||||
|       --tiller-namespace string   namespace of tiller (default "kube-system") | ||||
|  | @ -24,5 +24,6 @@ Manage client-side Helm plugins. | |||
| * [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 16-Apr-2017 | ||||
| ###### Auto generated by spf13/cobra on 29-May-2017 | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ helm plugin install [options] <path|url>... | |||
| 
 | ||||
| ``` | ||||
|       --debug                     enable verbose output | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "~/.helm") | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") | ||||
|       --host string               address of tiller. Overrides $HELM_HOST | ||||
|       --kube-context string       name of the kubeconfig context to use | ||||
|       --tiller-namespace string   namespace of tiller (default "kube-system") | ||||
|  | @ -30,4 +30,4 @@ helm plugin install [options] <path|url>... | |||
| ### SEE ALSO | ||||
| * [helm plugin](helm_plugin.md)	 - add, list, or remove Helm plugins | ||||
| 
 | ||||
| ###### Auto generated by spf13/cobra on 16-Apr-2017 | ||||
| ###### Auto generated by spf13/cobra on 29-May-2017 | ||||
|  |  | |||
|  | @ -15,7 +15,7 @@ helm plugin list | |||
| 
 | ||||
| ``` | ||||
|       --debug                     enable verbose output | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "~/.helm") | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") | ||||
|       --host string               address of tiller. Overrides $HELM_HOST | ||||
|       --kube-context string       name of the kubeconfig context to use | ||||
|       --tiller-namespace string   namespace of tiller (default "kube-system") | ||||
|  | @ -24,4 +24,4 @@ helm plugin list | |||
| ### SEE ALSO | ||||
| * [helm plugin](helm_plugin.md)	 - add, list, or remove Helm plugins | ||||
| 
 | ||||
| ###### Auto generated by spf13/cobra on 16-Apr-2017 | ||||
| ###### Auto generated by spf13/cobra on 29-May-2017 | ||||
|  |  | |||
|  | @ -15,7 +15,7 @@ helm plugin remove <plugin>... | |||
| 
 | ||||
| ``` | ||||
|       --debug                     enable verbose output | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "~/.helm") | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") | ||||
|       --host string               address of tiller. Overrides $HELM_HOST | ||||
|       --kube-context string       name of the kubeconfig context to use | ||||
|       --tiller-namespace string   namespace of tiller (default "kube-system") | ||||
|  | @ -24,4 +24,4 @@ helm plugin remove <plugin>... | |||
| ### SEE ALSO | ||||
| * [helm plugin](helm_plugin.md)	 - add, list, or remove Helm plugins | ||||
| 
 | ||||
| ###### Auto generated by spf13/cobra on 16-Apr-2017 | ||||
| ###### Auto generated by spf13/cobra on 29-May-2017 | ||||
|  |  | |||
|  | @ -0,0 +1,27 @@ | |||
| ## helm plugin update | ||||
| 
 | ||||
| update one or more Helm plugins | ||||
| 
 | ||||
| ### Synopsis | ||||
| 
 | ||||
| 
 | ||||
| update one or more Helm plugins | ||||
| 
 | ||||
| ``` | ||||
| helm plugin update <plugin>... | ||||
| ``` | ||||
| 
 | ||||
| ### Options inherited from parent commands | ||||
| 
 | ||||
| ``` | ||||
|       --debug                     enable verbose output | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") | ||||
|       --host string               address of tiller. Overrides $HELM_HOST | ||||
|       --kube-context string       name of the kubeconfig context to use | ||||
|       --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 29-May-2017 | ||||
|  | @ -17,7 +17,7 @@ Example usage: | |||
| 
 | ||||
| ``` | ||||
|       --debug                     enable verbose output | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "~/.helm") | ||||
|       --home string               location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") | ||||
|       --host string               address of tiller. Overrides $HELM_HOST | ||||
|       --kube-context string       name of the kubeconfig context to use | ||||
|       --tiller-namespace string   namespace of tiller (default "kube-system") | ||||
|  | @ -29,6 +29,6 @@ Example usage: | |||
| * [helm repo index](helm_repo_index.md)	 - generate an index file given a directory containing packaged charts | ||||
| * [helm repo list](helm_repo_list.md)	 - list chart repositories | ||||
| * [helm repo remove](helm_repo_remove.md)	 - remove a chart repository | ||||
| * [helm repo update](helm_repo_update.md)	 - update information on available charts in the chart repositories | ||||
| * [helm repo update](helm_repo_update.md)	 - update information of available charts locally from chart repositories | ||||
| 
 | ||||
| ###### Auto generated by spf13/cobra on 16-Apr-2017 | ||||
| ###### Auto generated by spf13/cobra on 29-May-2017 | ||||
|  |  | |||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue