Merge branch 'master' into master

pull/2350/head
Lukas Eichler 8 years ago committed by GitHub
commit 39db9ec6e8

1
.gitignore vendored

@ -6,6 +6,7 @@ _dist/
_proto/*.pb.go
bin/
rootfs/tiller
rootfs/rudder
vendor/
*.exe
.idea/

@ -1,12 +0,0 @@
language: go
go:
- '1.7.x'
go_import_path: k8s.io/helm
before_install:
- make bootstrap
script:
- make test

@ -1,9 +1,10 @@
DOCKER_REGISTRY ?= gcr.io
IMAGE_PREFIX ?= kubernetes-helm
SHORT_NAME ?= tiller
TARGETS = darwin/amd64 linux/amd64 linux/386 linux/arm linux/arm64 linux/ppc64le windows/amd64
DIST_DIRS = find * -type d -exec
APP = helm
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
# go option
GO ?= go
@ -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)
`
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",
Short: "Generate bash autocompletions script",
Long: completionDesc,
Hidden: false,
RunE: func(cmd *cobra.Command, _ []string) error {
return cmd.Root().GenBashCompletion(out)
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

@ -52,12 +52,12 @@ func newDeleteCmd(c helm.Interface, out io.Writer) *cobra.Command {
}
cmd := &cobra.Command{
Use: "delete [flags] RELEASE_NAME [...]",
Aliases: []string{"del"},
SuggestFor: []string{"remove", "rm"},
Short: "given a release name, delete the release from Kubernetes",
Long: deleteDesc,
PersistentPreRunE: setupConnection,
Use: "delete [flags] RELEASE_NAME [...]",
Aliases: []string{"del"},
SuggestFor: []string{"remove", "rm"},
Short: "given a release name, delete the release from Kubernetes",
Long: deleteDesc,
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)
}

@ -54,10 +54,10 @@ func newGetCmd(client helm.Interface, out io.Writer) *cobra.Command {
}
cmd := &cobra.Command{
Use: "get [flags] RELEASE_NAME",
Short: "download a named release",
Long: getHelp,
PersistentPreRunE: setupConnection,
Use: "get [flags] RELEASE_NAME",
Short: "download a named release",
Long: getHelp,
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
kubeContext string
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"
@ -122,8 +124,9 @@ func releaseMock(opts *releaseOptions) *release.Release {
}
type fakeReleaseClient struct {
rels []*release.Release
err error
rels []*release.Release
responses map[string]release.TestRun_Status
err error
}
var _ helm.Interface = &fakeReleaseClient{}
@ -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)
}
})
}
}

@ -56,11 +56,11 @@ func newHistoryCmd(c helm.Interface, w io.Writer) *cobra.Command {
his := &historyCmd{out: w, helmc: c}
cmd := &cobra.Command{
Use: "history [flags] RELEASE_NAME",
Long: historyHelp,
Short: "fetch release history",
Aliases: []string{"hist"},
PersistentPreRunE: setupConnection,
Use: "history [flags] RELEASE_NAME",
Long: historyHelp,
Short: "fetch release history",
Aliases: []string{"hist"},
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"
)
@ -54,8 +54,9 @@ To dump a manifest containing the Tiller deployment YAML, combine the
`
const (
stableRepository = "stable"
localRepository = "local"
stableRepository = "stable"
localRepository = "local"
localRepositoryIndexFile = "index.yaml"
)
var (
@ -66,17 +67,18 @@ var (
)
type initCmd struct {
image string
clientOnly bool
canary bool
upgrade bool
namespace string
dryRun bool
skipRefresh bool
out io.Writer
home helmpath.Home
opts installer.Options
kubeClient internalclientset.Interface
image string
clientOnly bool
canary bool
upgrade bool
namespace string
dryRun bool
skipRefresh bool
out io.Writer
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
@ -141,15 +148,23 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command {
}
cmd := &cobra.Command{
Use: "install [CHART]",
Short: "install a chart archive",
Long: installDesc,
PersistentPreRunE: setupConnection,
Use: "install [CHART]",
Short: "install a chart archive",
Long: installDesc,
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
}

@ -134,9 +134,15 @@ func TestInstall(t *testing.T) {
},
// Install, chart with missing dependencies in /charts
{
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!",
name: "install chart with missing dependencies",
args: []string{"testdata/testcharts/chart-missing-deps"},
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,11 +329,12 @@ 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",
UseCanary: false,
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.

@ -82,11 +82,11 @@ func newListCmd(client helm.Interface, out io.Writer) *cobra.Command {
}
cmd := &cobra.Command{
Use: "list [flags] [FILTER]",
Short: "list releases",
Long: listHelp,
Aliases: []string{"ls"},
PersistentPreRunE: setupConnection,
Use: "list [flags] [FILTER]",
Short: "list releases",
Long: listHelp,
Aliases: []string{"ls"},
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"
@ -48,13 +50,14 @@ Versioned chart archives are used by Helm package repositories.
`
type packageCmd struct {
save bool
sign bool
path string
key string
keyring string
version string
destination string
save bool
sign bool
path string
key string
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,21 +59,26 @@ 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)
}
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 = `
@ -47,10 +48,10 @@ func newReleaseTestCmd(c helm.Interface, out io.Writer) *cobra.Command {
}
cmd := &cobra.Command{
Use: "test [RELEASE]",
Short: "test a release",
Long: releaseTestDesc,
PersistentPreRunE: setupConnection,
Use: "test [RELEASE]",
Short: "test a release",
Long: releaseTestDesc,
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)
}

@ -54,10 +54,15 @@ func newResetCmd(client helm.Interface, out io.Writer) *cobra.Command {
}
cmd := &cobra.Command{
Use: "reset",
Short: "uninstalls Tiller from a cluster",
Long: resetDesc,
PersistentPreRunE: setupConnection,
Use: "reset",
Short: "uninstalls Tiller from a cluster",
Long: resetDesc,
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
@ -53,10 +54,10 @@ func newRollbackCmd(c helm.Interface, out io.Writer) *cobra.Command {
}
cmd := &cobra.Command{
Use: "rollback [flags] [RELEASE] [REVISION]",
Short: "roll back a release to a previous revision",
Long: rollbackDesc,
PersistentPreRunE: setupConnection,
Use: "rollback [flags] [RELEASE] [REVISION]",
Short: "roll back a release to a previous revision",
Long: rollbackDesc,
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 {

@ -57,10 +57,10 @@ func newStatusCmd(client helm.Interface, out io.Writer) *cobra.Command {
}
cmd := &cobra.Command{
Use: "status [flags] RELEASE_NAME",
Short: "displays the status of the named release",
Long: statusHelp,
PersistentPreRunE: setupConnection,
Use: "status [flags] RELEASE_NAME",
Short: "displays the status of the named release",
Long: statusHelp,
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

@ -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: reqsubchart
version: 0.1.0

@ -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 {
@ -84,15 +91,20 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command {
}
cmd := &cobra.Command{
Use: "upgrade [RELEASE] [CHART]",
Short: "upgrade a release",
Long: upgradeDesc,
PersistentPreRunE: setupConnection,
Use: "upgrade [RELEASE] [CHART]",
Short: "upgrade a release",
Long: upgradeDesc,
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 {
@ -138,10 +139,16 @@ func TestUpgradeCmd(t *testing.T) {
expected: "Release \"crazy-bunny\" has been upgraded. Happy Helming!\n",
},
{
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!",
name: "upgrade a release with missing dependencies",
args: []string{"bonkers-bunny", missingDepsPath},
resp: releaseMock(&releaseOptions{name: "bonkers-bunny", version: 1, chart: ch3}),
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
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{
Use: "tiller",
Short: "The Kubernetes Helm server.",
Long: globalUsage,
Run: start,
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 init() {
log.SetFlags(log.Flags() | log.Lshortfile)
func initLog() {
if enableTracing {
log.SetFlags(log.Lshortfile)
}
logger = newLogger("main")
}
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)
root := &cobra.Command{
Use: "tiller",
Short: "The Kubernetes Helm server.",
Long: globalUsage,
Run: start,
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.
## Avoid Using Blocks
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.
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.
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 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,16 +19,20 @@ helm inspect [CHART]
### Options
```
--keyring string path to the keyring containing public verification keys (default "~/.gnupg/pubring.gpg")
--verify verify the provenance data for this chart
--version string version of the chart. By default, the newest chart is shown
--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
```
### 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")
@ -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,16 +17,20 @@ helm inspect chart [CHART]
### Options
```
--keyring string path to the keyring containing public verification keys (default "~/.gnupg/pubring.gpg")
--verify verify the provenance data for this chart
--version string version of the chart. By default, the newest chart is shown
--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
```
### 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")
@ -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,16 +17,20 @@ helm inspect values [CHART]
### Options
```
--keyring string path to the keyring containing public verification keys (default "~/.gnupg/pubring.gpg")
--verify verify the provenance data for this chart
--version string version of the chart. By default, the newest chart is shown
--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
```
### 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")
@ -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…
Cancel
Save