Updated from master

pull/2342/head
John Welsh 9 years ago
commit 50e95be68e

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

@ -104,6 +104,7 @@ coverage:
HAS_GLIDE := $(shell command -v glide;) HAS_GLIDE := $(shell command -v glide;)
HAS_GOX := $(shell command -v gox;) HAS_GOX := $(shell command -v gox;)
HAS_GIT := $(shell command -v git;) HAS_GIT := $(shell command -v git;)
HAS_HG := $(shell command -v hg;)
.PHONY: bootstrap .PHONY: bootstrap
bootstrap: bootstrap:
@ -116,6 +117,9 @@ endif
ifndef HAS_GIT ifndef HAS_GIT
$(error You must install Git) $(error You must install Git)
endif
ifndef HAS_HG
$(error You must install Mercurial)
endif endif
glide install --strip-vendor glide install --strip-vendor
go build -o bin/protoc-gen-go ./vendor/github.com/golang/protobuf/protoc-gen-go go build -o bin/protoc-gen-go ./vendor/github.com/golang/protobuf/protoc-gen-go

@ -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: 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) - [OSX](https://kubernetes-helm.storage.googleapis.com/helm-v2.4.1-darwin-amd64.tar.gz)
- [Linux](https://kubernetes-helm.storage.googleapis.com/helm-v2.3.0-linux-amd64.tar.gz) - [Linux](https://kubernetes-helm.storage.googleapis.com/helm-v2.4.1-linux-amd64.tar.gz)
- [Linux 32-bit](https://kubernetes-helm.storage.googleapis.com/helm-v2.3.0-linux-386.tar.gz) - [Linux 32-bit](https://kubernetes-helm.storage.googleapis.com/helm-v2.4.1-linux-386.tar.gz)
Unpack the `helm` binary and add it to your PATH and you are good to go! 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`. 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, See the [installation guide](docs/install.md) for more options,
including installing pre-releases. including installing pre-releases.
## Docs ## Docs
Get started with the [Quick Start guide](docs/quickstart.md) or plunge into the [complete documentation](docs/index.md) Get started with the [Quick Start guide](docs/quickstart.md) or plunge into the [complete documentation](docs/index.md)

@ -29,15 +29,19 @@ google_deps = Mgoogle/protobuf/timestamp.proto=github.com/golang/protobuf/ptype
.PHONY: all .PHONY: all
all: chart release services version all: chart release services version
.PHONY: chart
chart: chart:
PATH=../bin:$(PATH) protoc --$(target)_out=plugins=$(plugins),$(google_deps),$(chart_ias):$(dst) $(chart_pbs) PATH=../bin:$(PATH) protoc --$(target)_out=plugins=$(plugins),$(google_deps),$(chart_ias):$(dst) $(chart_pbs)
.PHONY: release
release: release:
PATH=../bin:$(PATH) protoc --$(target)_out=plugins=$(plugins),$(google_deps),$(chart_ias),$(version_ias):$(dst) $(release_pbs) PATH=../bin:$(PATH) protoc --$(target)_out=plugins=$(plugins),$(google_deps),$(chart_ias),$(version_ias):$(dst) $(release_pbs)
.PHONY: services
services: services:
PATH=../bin:$(PATH) protoc --$(target)_out=plugins=$(plugins),$(google_deps),$(chart_ias),$(version_ias),$(release_ias):$(dst) $(services_pbs) PATH=../bin:$(PATH) protoc --$(target)_out=plugins=$(plugins),$(google_deps),$(chart_ias),$(version_ias),$(release_ias):$(dst) $(services_pbs)
.PHONY: version
version: version:
PATH=../bin:$(PATH) protoc --$(target)_out=plugins=$(plugins),$(google_deps):$(dst) $(version_pbs) PATH=../bin:$(PATH) protoc --$(target)_out=plugins=$(plugins),$(google_deps):$(dst) $(version_pbs)

@ -3,7 +3,7 @@ machine:
- curl -sSL https://s3.amazonaws.com/circle-downloads/install-circleci-docker.sh | bash -s -- 1.10.0 - curl -sSL https://s3.amazonaws.com/circle-downloads/install-circleci-docker.sh | bash -s -- 1.10.0
environment: environment:
GOVERSION: "1.7.5" GOVERSION: "1.8.1"
GOPATH: "${HOME}/.go_workspace" GOPATH: "${HOME}/.go_workspace"
WORKDIR: "${GOPATH}/src/k8s.io/helm" WORKDIR: "${GOPATH}/src/k8s.io/helm"
PROJECT_NAME: "kubernetes-helm" PROJECT_NAME: "kubernetes-helm"

@ -16,32 +16,214 @@ limitations under the License.
package main package main
import ( import (
"bytes"
"fmt"
"io" "io"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
const completionDesc = ` 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 Can be sourced as such
$ source <(helm completion) $ source <(helm completion bash)
` `
var (
completion_shells = map[string]func(out io.Writer, cmd *cobra.Command) error{
"bash": runCompletionBash,
"zsh": runCompletionZsh,
}
)
func newCompletionCmd(out io.Writer) *cobra.Command { func newCompletionCmd(out io.Writer) *cobra.Command {
shells := []string{}
for s := range completion_shells {
shells = append(shells, s)
}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "completion", Use: "completion SHELL",
Short: "Generate bash autocompletions script", Short: "Generate autocompletions script for the specified shell (bash or zsh)",
Long: completionDesc, Long: completionDesc,
Hidden: false, RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(cmd *cobra.Command, _ []string) error { return RunCompletion(out, cmd, args)
return cmd.Root().GenBashCompletion(out)
}, },
ValidArgs: shells,
} }
return cmd 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 := completion_shells[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 {
zsh_initialization := `
__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(zsh_initialization))
buf := new(bytes.Buffer)
cmd.Root().GenBashCompletion(buf)
out.Write(buf.Bytes())
zsh_tail := `
BASH_COMPLETION_EOF
}
__helm_bash_source <(__helm_convert_bash_to_zsh)
`
out.Write([]byte(zsh_tail))
return nil
}

@ -21,7 +21,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/helm/pkg/downloader" "k8s.io/helm/pkg/downloader"
"k8s.io/helm/pkg/getter/defaultgetters" "k8s.io/helm/pkg/getter"
"k8s.io/helm/pkg/helm/helmpath" "k8s.io/helm/pkg/helm/helmpath"
) )
@ -77,7 +77,7 @@ func (d *dependencyBuildCmd) run() error {
ChartPath: d.chartpath, ChartPath: d.chartpath,
HelmHome: d.helmhome, HelmHome: d.helmhome,
Keyring: d.keyring, Keyring: d.keyring,
Getters: defaultgetters.Get(settings), Getters: getter.All(settings),
} }
if d.verify { if d.verify {
man.Verify = downloader.VerifyIfPossible man.Verify = downloader.VerifyIfPossible

@ -21,7 +21,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/helm/pkg/downloader" "k8s.io/helm/pkg/downloader"
"k8s.io/helm/pkg/getter/defaultgetters" "k8s.io/helm/pkg/getter"
"k8s.io/helm/pkg/helm/helmpath" "k8s.io/helm/pkg/helm/helmpath"
) )
@ -95,7 +95,7 @@ func (d *dependencyUpdateCmd) run() error {
HelmHome: d.helmhome, HelmHome: d.helmhome,
Keyring: d.keyring, Keyring: d.keyring,
SkipUpdate: d.skipRefresh, SkipUpdate: d.skipRefresh,
Getters: defaultgetters.Get(settings), Getters: getter.All(settings),
} }
if d.verify { if d.verify {
man.Verify = downloader.VerifyIfPossible man.Verify = downloader.VerifyIfPossible

@ -26,7 +26,8 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/helm/pkg/chartutil" "k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/downloader" "k8s.io/helm/pkg/downloader"
"k8s.io/helm/pkg/getter/defaultgetters" "k8s.io/helm/pkg/getter"
"k8s.io/helm/pkg/repo"
) )
const fetchDesc = ` const fetchDesc = `
@ -50,11 +51,16 @@ type fetchCmd struct {
chartRef string chartRef string
destdir string destdir string
version string version string
repoURL string
verify bool verify bool
verifyLater bool verifyLater bool
keyring string keyring string
certFile string
keyFile string
caFile string
out io.Writer out io.Writer
} }
@ -87,6 +93,10 @@ 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.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.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.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")
return cmd return cmd
} }
@ -97,7 +107,7 @@ func (f *fetchCmd) run() error {
Out: f.out, Out: f.out,
Keyring: f.keyring, Keyring: f.keyring,
Verify: downloader.VerifyNever, Verify: downloader.VerifyNever,
Getters: defaultgetters.Get(settings), Getters: getter.All(settings),
} }
if f.verify { if f.verify {
@ -118,6 +128,14 @@ func (f *fetchCmd) run() error {
defer os.RemoveAll(dest) 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) saved, v, err := c.DownloadTo(f.chartRef, f.version, dest)
if err != nil { if err != nil {
return err return err

@ -27,7 +27,7 @@ import (
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/helm/cmd/helm/installer" "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/helm/helmpath"
"k8s.io/helm/pkg/repo" "k8s.io/helm/pkg/repo"
) )
@ -66,17 +66,18 @@ var (
) )
type initCmd struct { type initCmd struct {
image string image string
clientOnly bool clientOnly bool
canary bool canary bool
upgrade bool upgrade bool
namespace string namespace string
dryRun bool dryRun bool
skipRefresh bool skipRefresh bool
out io.Writer out io.Writer
home helmpath.Home home helmpath.Home
opts installer.Options opts installer.Options
kubeClient internalclientset.Interface kubeClient internalclientset.Interface
serviceAccount string
} }
func newInitCmd(out io.Writer) *cobra.Command { func newInitCmd(out io.Writer) *cobra.Command {
@ -116,6 +117,7 @@ func newInitCmd(out io.Writer) *cobra.Command {
f.StringVar(&localRepositoryURL, "local-repo-url", localRepositoryURL, "URL for local repository") 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.BoolVar(&i.opts.EnableHostNetwork, "net-host", false, "install tiller with net=host")
f.StringVar(&i.serviceAccount, "service-account", "", "name of service account")
return cmd return cmd
} }
@ -154,6 +156,7 @@ func (i *initCmd) run() error {
i.opts.Namespace = i.namespace i.opts.Namespace = i.namespace
i.opts.UseCanary = i.canary i.opts.UseCanary = i.canary
i.opts.ImageSpec = i.image i.opts.ImageSpec = i.image
i.opts.ServiceAccount = i.serviceAccount
if settings.Debug { if settings.Debug {
writeYAMLManifest := func(apiVersion, kind, body string, first, last bool) error { writeYAMLManifest := func(apiVersion, kind, body string, first, last bool) error {
@ -314,7 +317,7 @@ func initStableRepo(cacheFile string, skipRefresh bool) (*repo.Entry, error) {
URL: stableRepositoryURL, URL: stableRepositoryURL,
Cache: cacheFile, Cache: cacheFile,
} }
r, err := repo.NewChartRepository(&c, defaultgetters.Get(settings)) r, err := repo.NewChartRepository(&c, getter.All(settings))
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -50,6 +50,11 @@ type inspectCmd struct {
keyring string keyring string
out io.Writer out io.Writer
version string version string
repoURL string
certFile string
keyFile string
caFile string
} }
const ( const (
@ -72,7 +77,8 @@ func newInspectCmd(out io.Writer) *cobra.Command {
if err := checkArgsLength(len(args), "chart name"); err != nil { if err := checkArgsLength(len(args), "chart name"); err != nil {
return err 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 { if err != nil {
return err return err
} }
@ -90,7 +96,8 @@ func newInspectCmd(out io.Writer) *cobra.Command {
if err := checkArgsLength(len(args), "chart name"); err != nil { if err := checkArgsLength(len(args), "chart name"); err != nil {
return err 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 { if err != nil {
return err return err
} }
@ -108,7 +115,8 @@ func newInspectCmd(out io.Writer) *cobra.Command {
if err := checkArgsLength(len(args), "chart name"); err != nil { if err := checkArgsLength(len(args), "chart name"); err != nil {
return err 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 { if err != nil {
return err return err
} }
@ -136,6 +144,30 @@ func newInspectCmd(out io.Writer) *cobra.Command {
valuesSubCmd.Flags().StringVar(&insp.version, verflag, "", verdesc) valuesSubCmd.Flags().StringVar(&insp.version, verflag, "", verdesc)
chartSubCmd.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(valuesSubCmd)
inspectCommand.AddCommand(chartSubCmd) inspectCommand.AddCommand(chartSubCmd)

@ -34,11 +34,12 @@ import (
"k8s.io/helm/pkg/chartutil" "k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/downloader" "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/helm"
"k8s.io/helm/pkg/kube" "k8s.io/helm/pkg/kube"
"k8s.io/helm/pkg/proto/hapi/chart" "k8s.io/helm/pkg/proto/hapi/chart"
"k8s.io/helm/pkg/proto/hapi/release" "k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/helm/pkg/repo"
"k8s.io/helm/pkg/strvals" "k8s.io/helm/pkg/strvals"
) )
@ -115,6 +116,11 @@ type installCmd struct {
version string version string
timeout int64 timeout int64
wait bool wait bool
repoURL string
certFile string
keyFile string
caFile string
} }
type valueFiles []string type valueFiles []string
@ -149,7 +155,8 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command {
if err := checkArgsLength(len(args), "chart name"); err != nil { if err := checkArgsLength(len(args), "chart name"); err != nil {
return err return err
} }
cp, err := locateChartPath(args[0], inst.version, inst.verify, inst.keyring) cp, err := locateChartPath(inst.repoURL, args[0], inst.version, inst.verify, inst.keyring,
inst.certFile, inst.keyFile, inst.caFile)
if err != nil { if err != nil {
return err return err
} }
@ -173,6 +180,10 @@ 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.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.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.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")
return cmd return cmd
} }
@ -223,7 +234,12 @@ func (i *installCmd) run() error {
} }
if req, err := chartutil.LoadRequirements(chartRequested); err == nil { 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)
}
} }
//done := make(chan struct{}) //done := make(chan struct{})
@ -345,7 +361,8 @@ func (i *installCmd) printRelease(rel *release.Release) {
// - URL // - URL
// //
// If 'verify' is true, this will attempt to also verify the chart. // 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) name = strings.TrimSpace(name)
version = strings.TrimSpace(version) version = strings.TrimSpace(version)
if fi, err := os.Stat(name); err == nil { if fi, err := os.Stat(name); err == nil {
@ -376,11 +393,19 @@ func locateChartPath(name, version string, verify bool, keyring string) (string,
HelmHome: settings.Home, HelmHome: settings.Home,
Out: os.Stdout, Out: os.Stdout,
Keyring: keyring, Keyring: keyring,
Getters: defaultgetters.Get(settings), Getters: getter.All(settings),
} }
if verify { if verify {
dl.Verify = downloader.VerifyAlways 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, ".") filename, _, err := dl.DownloadTo(name, version, ".")
if err == nil { if err == nil {
@ -417,7 +442,9 @@ func defaultNamespace() string {
return "default" 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() deps := ch.GetDependencies()
for _, r := range reqs.Dependencies { for _, r := range reqs.Dependencies {
found := false found := false
@ -428,7 +455,12 @@ func checkDependencies(ch *chart.Chart, reqs *chartutil.Requirements, out io.Wri
} }
} }
if !found { 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,9 @@ func TestInstall(t *testing.T) {
}, },
// Install, chart with missing dependencies in /charts // Install, chart with missing dependencies in /charts
{ {
name: "install chart with missing dependencies", name: "install chart with missing dependencies",
args: []string{"testdata/testcharts/chart-missing-deps"}, args: []string{"testdata/testcharts/chart-missing-deps"},
expected: "Warning: reqsubchart2 is in requirements.yaml but not in the charts/ directory!", err: true,
}, },
} }

@ -131,6 +131,7 @@ func generateDeployment(opts *Options) *extensions.Deployment {
Labels: labels, Labels: labels,
}, },
Spec: api.PodSpec{ Spec: api.PodSpec{
ServiceAccountName: opts.ServiceAccount,
Containers: []api.Container{ Containers: []api.Container{
{ {
Name: "tiller", Name: "tiller",

@ -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) { func TestDeploymentManifest_WithTLS(t *testing.T) {
tests := []struct { tests := []struct {
opts Options opts Options

@ -43,6 +43,9 @@ type Options struct {
// Namespace is the kubernetes namespace to use to deploy tiller. // Namespace is the kubernetes namespace to use to deploy tiller.
Namespace string Namespace string
// ServiceAccount is the Kubernetes service account to add to tiller
ServiceAccount string
// ImageSpec indentifies the image tiller will use when deployed. // ImageSpec indentifies the image tiller will use when deployed.
// //
// Valid if and only if UseCanary is false. // Valid if and only if UseCanary is false.

@ -127,7 +127,9 @@ func (p *packageCmd) run(cmd *cobra.Command, args []string) error {
} }
if reqs, err := chartutil.LoadRequirements(ch); err == nil { if reqs, err := chartutil.LoadRequirements(ch); err == nil {
checkDependencies(ch, reqs, p.out) if err := checkDependencies(ch, reqs, p.out); err != nil {
return err
}
} }
var dest string var dest string

@ -118,8 +118,8 @@ func TestPackage(t *testing.T) {
{ {
name: "package testdata/testcharts/chart-missing-deps", name: "package testdata/testcharts/chart-missing-deps",
args: []string{"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", hasfile: "chart-missing-deps-0.1.0.tgz",
err: true,
}, },
} }

@ -22,7 +22,7 @@ import (
"github.com/spf13/cobra" "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/helm/helmpath"
"k8s.io/helm/pkg/repo" "k8s.io/helm/pkg/repo"
) )
@ -98,7 +98,7 @@ func addRepository(name, url string, home helmpath.Home, certFile, keyFile, caFi
CAFile: caFile, CAFile: caFile,
} }
r, err := repo.NewChartRepository(&c, defaultgetters.Get(settings)) r, err := repo.NewChartRepository(&c, getter.All(settings))
if err != nil { if err != nil {
return err return err
} }

@ -24,7 +24,7 @@ import (
"github.com/spf13/cobra" "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/helm/helmpath"
"k8s.io/helm/pkg/repo" "k8s.io/helm/pkg/repo"
) )
@ -76,7 +76,7 @@ func (u *repoUpdateCmd) run() error {
} }
var repos []*repo.ChartRepository var repos []*repo.ChartRepository
for _, cfg := range f.Repositories { for _, cfg := range f.Repositories {
r, err := repo.NewChartRepository(cfg, defaultgetters.Get(settings)) r, err := repo.NewChartRepository(cfg, getter.All(settings))
if err != nil { if err != nil {
return err return err
} }

@ -23,7 +23,7 @@ import (
"strings" "strings"
"testing" "testing"
"k8s.io/helm/pkg/getter/defaultgetters" "k8s.io/helm/pkg/getter"
"k8s.io/helm/pkg/helm/helmpath" "k8s.io/helm/pkg/helm/helmpath"
"k8s.io/helm/pkg/repo" "k8s.io/helm/pkg/repo"
"k8s.io/helm/pkg/repo/repotest" "k8s.io/helm/pkg/repo/repotest"
@ -85,7 +85,7 @@ func TestUpdateCharts(t *testing.T) {
Name: "charts", Name: "charts",
URL: ts.URL(), URL: ts.URL(),
Cache: hh.CacheIndex("charts"), Cache: hh.CacheIndex("charts"),
}, defaultgetters.Get(settings)) }, getter.All(settings))
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }

@ -74,6 +74,11 @@ type upgradeCmd struct {
resetValues bool resetValues bool
reuseValues bool reuseValues bool
wait bool wait bool
repoURL string
certFile string
keyFile string
caFile string
} }
func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command { func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command {
@ -117,6 +122,10 @@ 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.resetValues, "reset-values", false, "when upgrading, reset the values to the ones built into the chart")
f.BoolVar(&upgrade.reuseValues, "reuse-values", false, "when upgrading, reuse the last release's values, and merge in any new values. If '--reset-values' is specified, this is ignored.") f.BoolVar(&upgrade.reuseValues, "reuse-values", false, "when upgrading, reuse the last release's values, and merge in any 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.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.MarkDeprecated("disable-hooks", "use --no-hooks instead") f.MarkDeprecated("disable-hooks", "use --no-hooks instead")
@ -124,7 +133,7 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command {
} }
func (u *upgradeCmd) run() error { 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 { if err != nil {
return err return err
} }
@ -166,7 +175,9 @@ func (u *upgradeCmd) run() error {
// Check chart requirements to make sure all dependencies are present in /charts // Check chart requirements to make sure all dependencies are present in /charts
if ch, err := chartutil.Load(chartPath); err == nil { if ch, err := chartutil.Load(chartPath); err == nil {
if req, err := chartutil.LoadRequirements(ch); 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
}
} }
} }

@ -138,10 +138,10 @@ func TestUpgradeCmd(t *testing.T) {
expected: "Release \"crazy-bunny\" has been upgraded. Happy Helming!\n", expected: "Release \"crazy-bunny\" has been upgraded. Happy Helming!\n",
}, },
{ {
name: "upgrade a release with missing dependencies", name: "upgrade a release with missing dependencies",
args: []string{"bonkers-bunny", missingDepsPath}, args: []string{"bonkers-bunny", missingDepsPath},
resp: releaseMock(&releaseOptions{name: "bonkers-bunny", version: 1, chart: ch3}), resp: releaseMock(&releaseOptions{name: "bonkers-bunny", version: 1, chart: ch3}),
expected: "Warning: reqsubchart2 is in requirements.yaml but not in the charts/ directory!", err: true,
}, },
} }

@ -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 For all other kinds, as soon as Kubernetes marks the resource as loaded
(added or updated), the resource is considered "Ready". When many (added or updated), the resource is considered "Ready". When many
resources are declared in a hook, the resources are executed serially, resources are declared in a hook, the resources are executed serially. If they
but the order of their execution is not guaranteed. 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 ### 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 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 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, and a config map as a pre-install hook.
though, that there are no ordering guarantees about hooks.
When subcharts declare hooks, those are also evaluated. There is no way 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 for a top-level chart to disable the hooks declared by subcharts.
again, there is no guaranteed ordering.
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: annotations:
"helm.sh/hook-weight": "5" "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.

@ -10,6 +10,8 @@ Helm and Tiller.
- kubectl 1.2 or later - kubectl 1.2 or later
- A Kubernetes cluster (optional) - A Kubernetes cluster (optional)
- The gRPC toolchain - The gRPC toolchain
- Git
- Mercurial
## Building Helm/Tiller ## Building Helm/Tiller

@ -40,7 +40,7 @@ Environment:
``` ```
### SEE ALSO ### 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 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 delete](helm_delete.md) - given a release name, delete the release from Kubernetes
* [helm dependency](helm_dependency.md) - manage a chart's dependencies * [helm dependency](helm_dependency.md) - manage a chart's dependencies

@ -1,24 +1,24 @@
## helm completion ## helm completion
Generate bash autocompletions script Generate autocompletions script for the specified shell (bash or zsh)
### Synopsis ### 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 Can be sourced as such
$ source <(helm completion) $ source <(helm completion bash)
``` ```
helm completion helm completion SHELL
``` ```
### Options inherited from parent commands ### Options inherited from parent commands

@ -27,9 +27,13 @@ helm fetch [flags] [chart URL | repo/chartname] [...]
### Options ### 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 ".") -d, --destination string location to write the chart. If this and tardir are specified, tardir is appended to this (default ".")
--key-file string identify HTTPS client using this SSL key file
--keyring string keyring containing public keys (default "~/.gnupg/pubring.gpg") --keyring string keyring containing public keys (default "~/.gnupg/pubring.gpg")
--prov fetch the provenance file, but don't perform verification --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 --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 ".") --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 --verify verify the package against its signature
@ -49,4 +53,4 @@ helm fetch [flags] [chart URL | repo/chartname] [...]
### SEE ALSO ### SEE ALSO
* [helm](helm.md) - The Helm package manager for Kubernetes. * [helm](helm.md) - The Helm package manager for Kubernetes.
###### Auto generated by spf13/cobra on 16-Apr-2017 ###### Auto generated by spf13/cobra on 24-Apr-2017

@ -38,6 +38,7 @@ helm init
--dry-run do not install local or remote --dry-run do not install local or remote
--local-repo-url string URL for local repository (default "http://127.0.0.1:8879/charts") --local-repo-url string URL for local repository (default "http://127.0.0.1:8879/charts")
--net-host install tiller with net=host --net-host install tiller with net=host
--service-account string name of service account
--skip-refresh do not refresh (download) the local repository cache --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") --stable-repo-url string URL for stable repository (default "https://kubernetes-charts.storage.googleapis.com")
-i, --tiller-image string override tiller image -i, --tiller-image string override tiller image
@ -62,4 +63,4 @@ helm init
### SEE ALSO ### SEE ALSO
* [helm](helm.md) - The Helm package manager for Kubernetes. * [helm](helm.md) - The Helm package manager for Kubernetes.
###### Auto generated by spf13/cobra on 18-Apr-2017 ###### Auto generated by spf13/cobra on 1-May-2017

@ -19,9 +19,13 @@ helm inspect [CHART]
### Options ### Options
``` ```
--keyring string path to the keyring containing public verification keys (default "~/.gnupg/pubring.gpg") --ca-file string chart repository url where to locate the requested chart
--verify verify the provenance data for this chart --cert-file string verify certificates of HTTPS-enabled servers using this CA bundle
--version string version of the chart. By default, the newest chart is shown --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 ### Options inherited from parent commands
@ -39,4 +43,4 @@ helm inspect [CHART]
* [helm inspect chart](helm_inspect_chart.md) - shows inspect chart * [helm inspect chart](helm_inspect_chart.md) - shows inspect chart
* [helm inspect values](helm_inspect_values.md) - shows inspect values * [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 24-Apr-2017

@ -17,9 +17,13 @@ helm inspect chart [CHART]
### Options ### Options
``` ```
--keyring string path to the keyring containing public verification keys (default "~/.gnupg/pubring.gpg") --ca-file string chart repository url where to locate the requested chart
--verify verify the provenance data for this chart --cert-file string verify certificates of HTTPS-enabled servers using this CA bundle
--version string version of the chart. By default, the newest chart is shown --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 ### Options inherited from parent commands
@ -35,4 +39,4 @@ helm inspect chart [CHART]
### SEE ALSO ### SEE ALSO
* [helm inspect](helm_inspect.md) - inspect a chart * [helm inspect](helm_inspect.md) - inspect a chart
###### Auto generated by spf13/cobra on 16-Apr-2017 ###### Auto generated by spf13/cobra on 24-Apr-2017

@ -17,9 +17,13 @@ helm inspect values [CHART]
### Options ### Options
``` ```
--keyring string path to the keyring containing public verification keys (default "~/.gnupg/pubring.gpg") --ca-file string chart repository url where to locate the requested chart
--verify verify the provenance data for this chart --cert-file string verify certificates of HTTPS-enabled servers using this CA bundle
--version string version of the chart. By default, the newest chart is shown --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 ### Options inherited from parent commands
@ -35,4 +39,4 @@ helm inspect values [CHART]
### SEE ALSO ### SEE ALSO
* [helm inspect](helm_inspect.md) - inspect a chart * [helm inspect](helm_inspect.md) - inspect a chart
###### Auto generated by spf13/cobra on 16-Apr-2017 ###### Auto generated by spf13/cobra on 24-Apr-2017

@ -68,13 +68,17 @@ helm install [CHART]
### Options ### 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
--dry-run simulate an install --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") --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 -n, --name string release name. If unspecified, it will autogenerate one for you
--name-template string specify template used to name the release --name-template string specify template used to name the release
--namespace string namespace to install the release into --namespace string namespace to install the release into
--no-hooks prevent hooks from running during install --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 --replace re-use the given name, even if that name is already used. This is unsafe in production
--repo string chart repository url where to locate the requested chart
--set stringArray set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) --set 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) --timeout int time in seconds to wait for any individual kubernetes operation (like Jobs for hooks) (default 300)
--tls enable TLS for request --tls enable TLS for request
@ -101,4 +105,4 @@ helm install [CHART]
### SEE ALSO ### SEE ALSO
* [helm](helm.md) - The Helm package manager for Kubernetes. * [helm](helm.md) - The Helm package manager for Kubernetes.
###### Auto generated by spf13/cobra on 16-Apr-2017 ###### Auto generated by spf13/cobra on 24-Apr-2017

@ -36,12 +36,16 @@ helm upgrade [RELEASE] [CHART]
### Options ### 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
--dry-run simulate an upgrade --dry-run simulate an upgrade
-i, --install if a release by this name doesn't already exist, run an install -i, --install if a release by this name doesn't already exist, run an install
--key-file string identify HTTPS client using this SSL key file
--keyring string path to the keyring that contains public signing keys (default "~/.gnupg/pubring.gpg") --keyring string path to the keyring that contains public signing keys (default "~/.gnupg/pubring.gpg")
--namespace string namespace to install the release into (only used if --install is set) (default "default") --namespace string namespace to install the release into (only used if --install is set) (default "default")
--no-hooks disable pre/post upgrade hooks --no-hooks disable pre/post upgrade hooks
--recreate-pods performs pods restart for the resource if applicable --recreate-pods performs pods restart for the resource if applicable
--repo string chart repository url where to locate the requested chart
--reset-values when upgrading, reset the values to the ones built into the chart --reset-values when upgrading, reset the values to the ones built into the chart
--reuse-values when upgrading, reuse the last release's values, and merge in any new values. If '--reset-values' is specified, this is ignored. --reuse-values when upgrading, reuse the last release's values, and merge in any new values. If '--reset-values' is specified, this is ignored.
--set stringArray set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) --set stringArray set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)
@ -70,4 +74,4 @@ helm upgrade [RELEASE] [CHART]
### SEE ALSO ### SEE ALSO
* [helm](helm.md) - The Helm package manager for Kubernetes. * [helm](helm.md) - The Helm package manager for Kubernetes.
###### Auto generated by spf13/cobra on 16-Apr-2017 ###### Auto generated by spf13/cobra on 24-Apr-2017

@ -5,26 +5,26 @@
.SH NAME .SH NAME
.PP .PP
helm\-completion \- Generate bash autocompletions script helm\-completion \- Generate autocompletions script for the specified shell (bash or zsh)
.SH SYNOPSIS .SH SYNOPSIS
.PP .PP
\fBhelm completion\fP \fBhelm completion SHELL\fP
.SH DESCRIPTION .SH DESCRIPTION
.PP .PP
Generate bash autocompletions script for Helm. Generate autocompletions script for Helm for the specified shell (bash or zsh).
.PP .PP
This command can generate shell autocompletions. This command can generate shell autocompletions. e.g.
.PP .PP
.RS .RS
.nf .nf
$ helm completion $ helm completion bash
.fi .fi
.RE .RE
@ -36,7 +36,7 @@ Can be sourced as such
.RS .RS
.nf .nf
$ source <(helm completion) $ source <(helm completion bash)
.fi .fi
.RE .RE

@ -33,10 +33,22 @@ result in an error, and the chart will not be saved locally.
.SH OPTIONS .SH OPTIONS
.PP
\fB\-\-ca\-file\fP=""
verify certificates of HTTPS\-enabled servers using this CA bundle
.PP
\fB\-\-cert\-file\fP=""
identify HTTPS client using this SSL certificate file
.PP .PP
\fB\-d\fP, \fB\-\-destination\fP="." \fB\-d\fP, \fB\-\-destination\fP="."
location to write the chart. If this and tardir are specified, tardir is appended to this location to write the chart. If this and tardir are specified, tardir is appended to this
.PP
\fB\-\-key\-file\fP=""
identify HTTPS client using this SSL key file
.PP .PP
\fB\-\-keyring\fP="~/.gnupg/pubring.gpg" \fB\-\-keyring\fP="~/.gnupg/pubring.gpg"
keyring containing public keys keyring containing public keys
@ -45,6 +57,10 @@ result in an error, and the chart will not be saved locally.
\fB\-\-prov\fP[=false] \fB\-\-prov\fP[=false]
fetch the provenance file, but don't perform verification fetch the provenance file, but don't perform verification
.PP
\fB\-\-repo\fP=""
chart repository url where to locate the requested chart
.PP .PP
\fB\-\-untar\fP[=false] \fB\-\-untar\fP[=false]
if set to true, will untar the chart after downloading it if set to true, will untar the chart after downloading it
@ -91,4 +107,4 @@ result in an error, and the chart will not be saved locally.
.SH HISTORY .SH HISTORY
.PP .PP
16\-Apr\-2017 Auto generated by spf13/cobra 24\-Apr\-2017 Auto generated by spf13/cobra

@ -1,4 +1,4 @@
.TH "HELM" "1" "Apr 2017" "Auto generated by spf13/cobra" "" .TH "HELM" "1" "May 2017" "Auto generated by spf13/cobra" ""
.nh .nh
.ad l .ad l
@ -61,6 +61,10 @@ To dump a manifest containing the Tiller deployment YAML, combine the
\fB\-\-net\-host\fP[=false] \fB\-\-net\-host\fP[=false]
install tiller with net=host install tiller with net=host
.PP
\fB\-\-service\-account\fP=""
name of service account
.PP .PP
\fB\-\-skip\-refresh\fP[=false] \fB\-\-skip\-refresh\fP[=false]
do not refresh (download) the local repository cache do not refresh (download) the local repository cache
@ -128,4 +132,4 @@ To dump a manifest containing the Tiller deployment YAML, combine the
.SH HISTORY .SH HISTORY
.PP .PP
18\-Apr\-2017 Auto generated by spf13/cobra 1\-May\-2017 Auto generated by spf13/cobra

@ -23,10 +23,26 @@ Inspect prints the contents of the Chart.yaml file and the values.yaml file.
.SH OPTIONS .SH OPTIONS
.PP
\fB\-\-ca\-file\fP=""
chart repository url where to locate the requested chart
.PP
\fB\-\-cert\-file\fP=""
verify certificates of HTTPS\-enabled servers using this CA bundle
.PP
\fB\-\-key\-file\fP=""
identify HTTPS client using this SSL key file
.PP .PP
\fB\-\-keyring\fP="~/.gnupg/pubring.gpg" \fB\-\-keyring\fP="~/.gnupg/pubring.gpg"
path to the keyring containing public verification keys path to the keyring containing public verification keys
.PP
\fB\-\-repo\fP=""
chart repository url where to locate the requested chart
.PP .PP
\fB\-\-verify\fP[=false] \fB\-\-verify\fP[=false]
verify the provenance data for this chart verify the provenance data for this chart
@ -65,4 +81,4 @@ Inspect prints the contents of the Chart.yaml file and the values.yaml file.
.SH HISTORY .SH HISTORY
.PP .PP
16\-Apr\-2017 Auto generated by spf13/cobra 24\-Apr\-2017 Auto generated by spf13/cobra

@ -20,10 +20,26 @@ of the Charts.yaml file
.SH OPTIONS .SH OPTIONS
.PP
\fB\-\-ca\-file\fP=""
chart repository url where to locate the requested chart
.PP
\fB\-\-cert\-file\fP=""
verify certificates of HTTPS\-enabled servers using this CA bundle
.PP
\fB\-\-key\-file\fP=""
identify HTTPS client using this SSL key file
.PP .PP
\fB\-\-keyring\fP="~/.gnupg/pubring.gpg" \fB\-\-keyring\fP="~/.gnupg/pubring.gpg"
path to the keyring containing public verification keys path to the keyring containing public verification keys
.PP
\fB\-\-repo\fP=""
chart repository url where to locate the requested chart
.PP .PP
\fB\-\-verify\fP[=false] \fB\-\-verify\fP[=false]
verify the provenance data for this chart verify the provenance data for this chart
@ -62,4 +78,4 @@ of the Charts.yaml file
.SH HISTORY .SH HISTORY
.PP .PP
16\-Apr\-2017 Auto generated by spf13/cobra 24\-Apr\-2017 Auto generated by spf13/cobra

@ -20,10 +20,26 @@ of the values.yaml file
.SH OPTIONS .SH OPTIONS
.PP
\fB\-\-ca\-file\fP=""
chart repository url where to locate the requested chart
.PP
\fB\-\-cert\-file\fP=""
verify certificates of HTTPS\-enabled servers using this CA bundle
.PP
\fB\-\-key\-file\fP=""
identify HTTPS client using this SSL key file
.PP .PP
\fB\-\-keyring\fP="~/.gnupg/pubring.gpg" \fB\-\-keyring\fP="~/.gnupg/pubring.gpg"
path to the keyring containing public verification keys path to the keyring containing public verification keys
.PP
\fB\-\-repo\fP=""
chart repository url where to locate the requested chart
.PP .PP
\fB\-\-verify\fP[=false] \fB\-\-verify\fP[=false]
verify the provenance data for this chart verify the provenance data for this chart
@ -62,4 +78,4 @@ of the values.yaml file
.SH HISTORY .SH HISTORY
.PP .PP
16\-Apr\-2017 Auto generated by spf13/cobra 24\-Apr\-2017 Auto generated by spf13/cobra

@ -114,10 +114,22 @@ charts in a repository, use 'helm search'.
.SH OPTIONS .SH OPTIONS
.PP
\fB\-\-ca\-file\fP=""
verify certificates of HTTPS\-enabled servers using this CA bundle
.PP
\fB\-\-cert\-file\fP=""
identify HTTPS client using this SSL certificate file
.PP .PP
\fB\-\-dry\-run\fP[=false] \fB\-\-dry\-run\fP[=false]
simulate an install simulate an install
.PP
\fB\-\-key\-file\fP=""
identify HTTPS client using this SSL key file
.PP .PP
\fB\-\-keyring\fP="~/.gnupg/pubring.gpg" \fB\-\-keyring\fP="~/.gnupg/pubring.gpg"
location of public keys used for verification location of public keys used for verification
@ -142,6 +154,10 @@ charts in a repository, use 'helm search'.
\fB\-\-replace\fP[=false] \fB\-\-replace\fP[=false]
re\-use the given name, even if that name is already used. This is unsafe in production re\-use the given name, even if that name is already used. This is unsafe in production
.PP
\fB\-\-repo\fP=""
chart repository url where to locate the requested chart
.PP .PP
\fB\-\-set\fP=[] \fB\-\-set\fP=[]
set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)
@ -216,4 +232,4 @@ charts in a repository, use 'helm search'.
.SH HISTORY .SH HISTORY
.PP .PP
16\-Apr\-2017 Auto generated by spf13/cobra 24\-Apr\-2017 Auto generated by spf13/cobra

@ -57,6 +57,14 @@ $ helm upgrade \-\-set foo=bar \-\-set foo=newbar redis ./redis
.SH OPTIONS .SH OPTIONS
.PP
\fB\-\-ca\-file\fP=""
verify certificates of HTTPS\-enabled servers using this CA bundle
.PP
\fB\-\-cert\-file\fP=""
identify HTTPS client using this SSL certificate file
.PP .PP
\fB\-\-dry\-run\fP[=false] \fB\-\-dry\-run\fP[=false]
simulate an upgrade simulate an upgrade
@ -65,6 +73,10 @@ $ helm upgrade \-\-set foo=bar \-\-set foo=newbar redis ./redis
\fB\-i\fP, \fB\-\-install\fP[=false] \fB\-i\fP, \fB\-\-install\fP[=false]
if a release by this name doesn't already exist, run an install if a release by this name doesn't already exist, run an install
.PP
\fB\-\-key\-file\fP=""
identify HTTPS client using this SSL key file
.PP .PP
\fB\-\-keyring\fP="~/.gnupg/pubring.gpg" \fB\-\-keyring\fP="~/.gnupg/pubring.gpg"
path to the keyring that contains public signing keys path to the keyring that contains public signing keys
@ -81,6 +93,10 @@ $ helm upgrade \-\-set foo=bar \-\-set foo=newbar redis ./redis
\fB\-\-recreate\-pods\fP[=false] \fB\-\-recreate\-pods\fP[=false]
performs pods restart for the resource if applicable performs pods restart for the resource if applicable
.PP
\fB\-\-repo\fP=""
chart repository url where to locate the requested chart
.PP .PP
\fB\-\-reset\-values\fP[=false] \fB\-\-reset\-values\fP[=false]
when upgrading, reset the values to the ones built into the chart when upgrading, reset the values to the ones built into the chart
@ -163,4 +179,4 @@ $ helm upgrade \-\-set foo=bar \-\-set foo=newbar redis ./redis
.SH HISTORY .SH HISTORY
.PP .PP
16\-Apr\-2017 Auto generated by spf13/cobra 24\-Apr\-2017 Auto generated by spf13/cobra

@ -215,7 +215,7 @@ You can then override any of these settings in a YAML formatted file,
and then pass that file during installation. and then pass that file during installation.
```console ```console
$ echo 'mariadbUser: user0` > config.yaml $ echo 'mariadbUser: user0' > config.yaml
$ helm install -f config.yaml stable/mariadb $ helm install -f config.yaml stable/mariadb
``` ```

23
glide.lock generated

@ -1,5 +1,5 @@
hash: 59f320c07649cfd057b84f1044074670230fa3ca27b32632eb77a16a972adc8e hash: e323e66f9aba77578f7dcc0886e3117ebc373bc391374b2d5ddd293c276c8966
updated: 2017-04-24T14:43:55.783514424-07:00 updated: 2017-05-02T22:27:03.674351365-04:00
imports: imports:
- name: bitbucket.org/ww/goautoneg - name: bitbucket.org/ww/goautoneg
version: 75cd24fc2f2c2a2088577d12123ddee5f54e0675 version: 75cd24fc2f2c2a2088577d12123ddee5f54e0675
@ -20,6 +20,8 @@ imports:
version: 3ac7bf7a47d159a033b107610db8a1b6575507a4 version: 3ac7bf7a47d159a033b107610db8a1b6575507a4
subpackages: subpackages:
- quantile - quantile
- name: github.com/BurntSushi/toml
version: b26d9c308763d68093482582cea63d69be07a0f0
- name: github.com/chai2010/gettext-go - name: github.com/chai2010/gettext-go
version: bf70f2a70fb1b1f36d90d671a72795984eab0fcb version: bf70f2a70fb1b1f36d90d671a72795984eab0fcb
- name: github.com/coreos/go-oidc - name: github.com/coreos/go-oidc
@ -134,7 +136,7 @@ imports:
subpackages: subpackages:
- lru - lru
- name: github.com/golang/protobuf - name: github.com/golang/protobuf
version: df1d3ca07d2d07bba352d5b73c4313b4e2a6203e version: 2bba0603135d7d7f5cb73b2125beeda19c09f4ef
subpackages: subpackages:
- proto - proto
- ptypes/any - ptypes/any
@ -167,9 +169,9 @@ imports:
- name: github.com/Masterminds/semver - name: github.com/Masterminds/semver
version: 3f0ab6d4ab4bed1c61caf056b63a6e62190c7801 version: 3f0ab6d4ab4bed1c61caf056b63a6e62190c7801
- name: github.com/Masterminds/sprig - name: github.com/Masterminds/sprig
version: 23597e5f6ad0e4d590e71314bfd0251a4a3cf849 version: a48f46e0125cf60347eda24fccf1b09f1a0d681f
- name: github.com/Masterminds/vcs - name: github.com/Masterminds/vcs
version: 795e20f901c3d561de52811fb3488a2cb2c8588b version: 3084677c2c188840777bff30054f2b553729d329
- name: github.com/mattn/go-runewidth - name: github.com/mattn/go-runewidth
version: 14207d285c6c197daabb5c9793d63e7af9ab2d50 version: 14207d285c6c197daabb5c9793d63e7af9ab2d50
- name: github.com/matttproud/golang_protobuf_extensions - name: github.com/matttproud/golang_protobuf_extensions
@ -180,10 +182,6 @@ imports:
version: ad45545899c7b13c020ea92b2072220eefad42b8 version: ad45545899c7b13c020ea92b2072220eefad42b8
- name: github.com/naoina/go-stringutil - name: github.com/naoina/go-stringutil
version: 6b638e95a32d0c1131db0e7fe83775cbea4a0d0b version: 6b638e95a32d0c1131db0e7fe83775cbea4a0d0b
- name: github.com/naoina/toml
version: 751171607256bb66e64c9f0220c00662420c38e9
subpackages:
- ast
- name: github.com/pborman/uuid - name: github.com/pborman/uuid
version: ca53cad383cad2479bbba7f7a1a05797ec1386e4 version: ca53cad383cad2479bbba7f7a1a05797ec1386e4
- name: github.com/prometheus/client_golang - name: github.com/prometheus/client_golang
@ -294,20 +292,23 @@ imports:
- internal/urlfetch - internal/urlfetch
- urlfetch - urlfetch
- name: google.golang.org/grpc - name: google.golang.org/grpc
version: b7f1379d3cbbbeb2ca3405852012e237aa05459e version: 8050b9cbc271307e5a716a9d782803d09b0d6f2d
subpackages: subpackages:
- codes - codes
- credentials - credentials
- grpclog - grpclog
- internal - internal
- keepalive
- metadata - metadata
- naming - naming
- peer - peer
- stats
- tap
- transport - transport
- name: gopkg.in/inf.v0 - name: gopkg.in/inf.v0
version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4 version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4
- name: gopkg.in/yaml.v2 - name: gopkg.in/yaml.v2
version: a3f3340b5840cee44f372bddb5880fcbc419b46a version: 53feefa2559fb8dfa8d81baad31be332c97d6c77
- name: k8s.io/apimachinery - name: k8s.io/apimachinery
version: 9c89140a45325f83409e90359888133478207c7a version: 9c89140a45325f83409e90359888133478207c7a
subpackages: subpackages:

@ -10,20 +10,24 @@ import:
version: 9ff6c6923cfffbcd502984b8e0c80539a94968b7 version: 9ff6c6923cfffbcd502984b8e0c80539a94968b7
- package: github.com/Masterminds/vcs - package: github.com/Masterminds/vcs
version: ~1.11.0 version: ~1.11.0
# Pin version of mergo that is compatible with both sprig and Kubernetes
- package: github.com/imdario/mergo
version: 6633656539c1639d9d78127b7d47c622b5d7b6dc
- package: github.com/Masterminds/sprig - package: github.com/Masterminds/sprig
version: ^2.10 version: ^2.11
- package: github.com/ghodss/yaml - package: github.com/ghodss/yaml
- package: github.com/Masterminds/semver - package: github.com/Masterminds/semver
version: ~1.2.3 version: ~1.2.3
- package: github.com/technosophos/moniker - package: github.com/technosophos/moniker
- package: github.com/golang/protobuf - package: github.com/golang/protobuf
version: df1d3ca07d2d07bba352d5b73c4313b4e2a6203e version: 2bba0603135d7d7f5cb73b2125beeda19c09f4ef
subpackages: subpackages:
- proto - proto
- ptypes/any - ptypes/any
- ptypes/timestamp - ptypes/timestamp
- package: google.golang.org/grpc - package: google.golang.org/grpc
version: 1.0.3 version: 1.2.1
- package: k8s.io/apimachinery - package: k8s.io/apimachinery
- package: k8s.io/client-go - package: k8s.io/client-go
- package: k8s.io/kubernetes - package: k8s.io/kubernetes
@ -38,8 +42,8 @@ import:
version: ^0.2.1 version: ^0.2.1
- package: github.com/evanphx/json-patch - package: github.com/evanphx/json-patch
- package: github.com/facebookgo/symwalk - package: github.com/facebookgo/symwalk
- package: github.com/naoina/toml - package: github.com/BurntSushi/toml
version: ~0.1.0 version: ~0.3.0
- package: github.com/naoina/go-stringutil - package: github.com/naoina/go-stringutil
version: ~0.1.0 version: ~0.1.0
- package: github.com/chai2010/gettext-go - package: github.com/chai2010/gettext-go

@ -195,7 +195,7 @@ const defaultNotes = `1. Get the application URL by running these commands:
{{- else if contains "NodePort" .Values.service.type }} {{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "fullname" . }}) export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT/login echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }} {{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available. NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get svc -w {{ template "fullname" . }}' You can watch the status of by running 'kubectl get svc -w {{ template "fullname" . }}'

@ -16,6 +16,7 @@ limitations under the License.
package chartutil package chartutil
import ( import (
"bytes"
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"path" "path"
@ -23,9 +24,9 @@ import (
yaml "gopkg.in/yaml.v2" yaml "gopkg.in/yaml.v2"
"github.com/BurntSushi/toml"
"github.com/gobwas/glob" "github.com/gobwas/glob"
"github.com/golang/protobuf/ptypes/any" "github.com/golang/protobuf/ptypes/any"
"github.com/naoina/toml"
) )
// Files is a map of files in a chart that can be accessed from a template. // Files is a map of files in a chart that can be accessed from a template.
@ -197,12 +198,13 @@ func FromYaml(str string) map[string]interface{} {
// //
// This is designed to be called from a template. // This is designed to be called from a template.
func ToToml(v interface{}) string { func ToToml(v interface{}) string {
data, err := toml.Marshal(v) b := bytes.NewBuffer(nil)
e := toml.NewEncoder(b)
err := e.Encode(v)
if err != nil { if err != nil {
// Swallow errors inside of a template. return err.Error()
return ""
} }
return string(data) return b.String()
} }
// ToJson takes an interface, marshals it to json, and returns a string. It will // ToJson takes an interface, marshals it to json, and returns a string. It will

@ -112,9 +112,9 @@ func TestToYaml(t *testing.T) {
} }
func TestToToml(t *testing.T) { func TestToToml(t *testing.T) {
expect := "foo=\"bar\"\n" expect := "foo = \"bar\"\n"
v := struct { v := struct {
Foo string `json:"foo"` Foo string `toml:"foo"`
}{ }{
Foo: "bar", Foo: "bar",
} }
@ -122,6 +122,18 @@ func TestToToml(t *testing.T) {
if got := ToToml(v); got != expect { if got := ToToml(v); got != expect {
t.Errorf("Expected %q, got %q", expect, got) t.Errorf("Expected %q, got %q", expect, got)
} }
// Regression for https://github.com/kubernetes/helm/issues/2271
dict := map[string]map[string]string{
"mast": {
"sail": "white",
},
}
got := ToToml(dict)
expect = "[mast]\n sail = \"white\"\n"
if got != expect {
t.Errorf("Expected:\n%s\nGot\n%s\n", expect, got)
}
} }
func TestFromYaml(t *testing.T) { func TestFromYaml(t *testing.T) {

@ -66,7 +66,7 @@ type ChartDownloader struct {
// HelmHome is the $HELM_HOME. // HelmHome is the $HELM_HOME.
HelmHome helmpath.Home HelmHome helmpath.Home
// Getter collection for the operation // Getter collection for the operation
Getters []getter.Prop Getters getter.Providers
} }
// DownloadTo retrieves a chart. Depending on the settings, it may also download a provenance file. // DownloadTo retrieves a chart. Depending on the settings, it may also download a provenance file.
@ -161,7 +161,7 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, ge
// If there is no special config, return the default HTTP client and // If there is no special config, return the default HTTP client and
// swallow the error. // swallow the error.
if err == ErrNoOwnerRepo { if err == ErrNoOwnerRepo {
getterConstructor, err := getter.ConstructorByScheme(c.Getters, u.Scheme) getterConstructor, err := c.Getters.ByScheme(u.Scheme)
if err != nil { if err != nil {
return u, nil, err return u, nil, err
} }

@ -25,8 +25,7 @@ import (
"path/filepath" "path/filepath"
"testing" "testing"
"k8s.io/helm/pkg/getter/defaultgetters" "k8s.io/helm/pkg/getter"
"k8s.io/helm/pkg/getter/http"
"k8s.io/helm/pkg/helm/environment" "k8s.io/helm/pkg/helm/environment"
"k8s.io/helm/pkg/helm/helmpath" "k8s.io/helm/pkg/helm/helmpath"
"k8s.io/helm/pkg/repo" "k8s.io/helm/pkg/repo"
@ -52,7 +51,7 @@ func TestResolveChartRef(t *testing.T) {
c := ChartDownloader{ c := ChartDownloader{
HelmHome: helmpath.Home("testdata/helmhome"), HelmHome: helmpath.Home("testdata/helmhome"),
Out: os.Stderr, Out: os.Stderr,
Getters: defaultgetters.Get(environment.EnvSettings{}), Getters: getter.All(environment.EnvSettings{}),
} }
for _, tt := range tests { for _, tt := range tests {
@ -89,7 +88,12 @@ func TestDownload(t *testing.T) {
})) }))
defer srv.Close() defer srv.Close()
getter, err := httpgetter.New(srv.URL, "", "", "") provider, err := getter.ByScheme("http", environment.EnvSettings{})
if err != nil {
t.Fatal("No http provider found")
}
getter, err := provider.New(srv.URL, "", "", "")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -182,7 +186,7 @@ func TestDownloadTo(t *testing.T) {
Out: os.Stderr, Out: os.Stderr,
Verify: VerifyAlways, Verify: VerifyAlways,
Keyring: "testdata/helm-test-key.pub", Keyring: "testdata/helm-test-key.pub",
Getters: defaultgetters.Get(environment.EnvSettings{}), Getters: getter.All(environment.EnvSettings{}),
} }
cname := "/signtest-0.1.0.tgz" cname := "/signtest-0.1.0.tgz"
where, v, err := c.DownloadTo(srv.URL()+cname, "", dest) where, v, err := c.DownloadTo(srv.URL()+cname, "", dest)
@ -245,7 +249,7 @@ func TestDownloadTo_VerifyLater(t *testing.T) {
HelmHome: hh, HelmHome: hh,
Out: os.Stderr, Out: os.Stderr,
Verify: VerifyLater, Verify: VerifyLater,
Getters: defaultgetters.Get(environment.EnvSettings{}), Getters: getter.All(environment.EnvSettings{}),
} }
cname := "/signtest-0.1.0.tgz" cname := "/signtest-0.1.0.tgz"
where, _, err := c.DownloadTo(srv.URL()+cname, "", dest) where, _, err := c.DownloadTo(srv.URL()+cname, "", dest)
@ -274,7 +278,7 @@ func TestScanReposForURL(t *testing.T) {
HelmHome: hh, HelmHome: hh,
Out: os.Stderr, Out: os.Stderr,
Verify: VerifyLater, Verify: VerifyLater,
Getters: defaultgetters.Get(environment.EnvSettings{}), Getters: getter.All(environment.EnvSettings{}),
} }
u := "http://example.com/alpine-0.2.0.tgz" u := "http://example.com/alpine-0.2.0.tgz"

@ -56,7 +56,7 @@ type Manager struct {
// SkipUpdate indicates that the repository should not be updated first. // SkipUpdate indicates that the repository should not be updated first.
SkipUpdate bool SkipUpdate bool
// Getter collection for the operation // Getter collection for the operation
Getters []getter.Prop Getters []getter.Provider
} }
// Build rebuilds a local charts directory from a lockfile. // Build rebuilds a local charts directory from a lockfile.

@ -138,12 +138,12 @@ func (e *Engine) alterFuncMap(t *template.Template) template.FuncMap {
} }
// Add the 'include' function here so we can close over t. // Add the 'include' function here so we can close over t.
funcMap["include"] = func(name string, data interface{}) string { funcMap["include"] = func(name string, data interface{}) (string, error) {
buf := bytes.NewBuffer(nil) buf := bytes.NewBuffer(nil)
if err := t.ExecuteTemplate(buf, name, data); err != nil { if err := t.ExecuteTemplate(buf, name, data); err != nil {
buf.WriteString(err.Error()) return "", err
} }
return buf.String() return buf.String(), nil
} }
// Add the 'required' function here // Add the 'required' function here

@ -1,71 +0,0 @@
/*
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 defaultgetters
import (
"os"
"k8s.io/helm/pkg/getter"
"k8s.io/helm/pkg/getter/http"
"k8s.io/helm/pkg/getter/plugin"
"k8s.io/helm/pkg/helm/environment"
"k8s.io/helm/pkg/helm/helmpath"
"k8s.io/helm/pkg/plugin"
)
// Get gathers the getter constructors for the downloaders.
// Currently the build-in http getter and the discovered
// plugins with downloader notations are collected.
func Get(settings environment.EnvSettings) []getter.Prop {
result := []getter.Prop{
{
Schemes: getter.Schemes{"http", "https"},
Constructor: httpgetter.New,
},
}
pluginDownloaders, _ := collectPlugins(settings)
result = append(result, pluginDownloaders...)
return result
}
func collectPlugins(settings environment.EnvSettings) ([]getter.Prop, error) {
plugdirs := os.Getenv(environment.PluginEnvVar)
if plugdirs == "" {
home := helmpath.Home(os.Getenv(environment.HomeEnvVar))
plugdirs = home.Plugins()
}
plugins, err := plugin.FindPlugins(plugdirs)
if err != nil {
return nil, err
}
var result []getter.Prop
for _, plugin := range plugins {
for _, downloader := range plugin.Metadata.Downloaders {
result = append(result, getter.Prop{
Schemes: downloader.Protocols,
Constructor: plugingetter.ConstructNew(
downloader.Command,
settings,
plugin.Metadata.Name,
plugin.Dir,
),
})
}
}
return result, nil
}

@ -0,0 +1,21 @@
/*
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 getter provides a generalize tool for fetching data by scheme.
This provides a method by which the plugin system can load arbitrary protocol
handlers based upon a URL scheme.
*/
package getter

@ -19,6 +19,8 @@ package getter
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"k8s.io/helm/pkg/helm/environment"
) )
// Getter is an interface to support GET to the specified URL. // Getter is an interface to support GET to the specified URL.
@ -27,27 +29,70 @@ type Getter interface {
Get(url string) (*bytes.Buffer, error) Get(url string) (*bytes.Buffer, error)
} }
//Schemes is the list to represent a specific Getter's protocol capabilities // Constructor is the function for every getter which creates a specific instance
type Schemes []string // according to the configuration
//Constructor is the function for every getter which creates a specific instance
//according to the configuration
type Constructor func(URL, CertFile, KeyFile, CAFile string) (Getter, error) type Constructor func(URL, CertFile, KeyFile, CAFile string) (Getter, error)
//Prop represents any getter and its capability // Provider represents any getter and the schemes that it supports.
type Prop struct { //
Schemes Schemes // For example, an HTTP provider may provide one getter that handles both
Constructor Constructor // 'http' and 'https' schemes.
type Provider struct {
Schemes []string
New Constructor
}
// Provides returns true if the given scheme is supported by this Provider.
func (p Provider) Provides(scheme string) bool {
for _, i := range p.Schemes {
if i == scheme {
return true
}
}
return false
}
// Providers is a collection of Provider objects.
type Providers []Provider
// ByScheme returns a Provider that handles the given scheme.
//
// If no provider handles this scheme, this will return an error.
func (p Providers) ByScheme(scheme string) (Constructor, error) {
for _, pp := range p {
if pp.Provides(scheme) {
return pp.New, nil
}
}
return nil, fmt.Errorf("scheme %q not supported", scheme)
}
// All finds all of the registered getters as a list of Provider instances.
// Currently the build-in http/https getter and the discovered
// plugins with downloader notations are collected.
func All(settings environment.EnvSettings) Providers {
result := Providers{
{
Schemes: []string{"http", "https"},
New: newHTTPGetter,
},
}
pluginDownloaders, _ := collectPlugins(settings)
result = append(result, pluginDownloaders...)
return result
} }
//ConstructorByScheme returns a contstructor based on the required scheme // ByScheme returns a getter for the given scheme.
func ConstructorByScheme(props []Prop, requiredScheme string) (Constructor, error) { //
for _, item := range props { // If the scheme is not supported, this will return an error.
for _, itemScheme := range item.Schemes { func ByScheme(scheme string, settings environment.EnvSettings) (Provider, error) {
if itemScheme == requiredScheme { // Q: What do you call a scheme string who's the boss?
return item.Constructor, nil // A: Bruce Schemestring, of course.
} a := All(settings)
for _, p := range a {
if p.Provides(scheme) {
return p, nil
} }
} }
return nil, fmt.Errorf("Getter not found") return Provider{}, fmt.Errorf("scheme %q not supported", scheme)
} }

@ -0,0 +1,81 @@
/*
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 getter
import (
"os"
"testing"
)
func TestProvider(t *testing.T) {
p := Provider{
[]string{"one", "three"},
func(h, e, l, m string) (Getter, error) { return nil, nil },
}
if !p.Provides("three") {
t.Error("Expected provider to provide three")
}
}
func TestProviders(t *testing.T) {
ps := Providers{
{[]string{"one", "three"}, func(h, e, l, m string) (Getter, error) { return nil, nil }},
{[]string{"two", "four"}, func(h, e, l, m string) (Getter, error) { return nil, nil }},
}
if _, err := ps.ByScheme("one"); err != nil {
t.Error(err)
}
if _, err := ps.ByScheme("four"); err != nil {
t.Error(err)
}
if _, err := ps.ByScheme("five"); err == nil {
t.Error("Did not expect handler for five")
}
}
func TestAll(t *testing.T) {
oldhh := os.Getenv("HELM_HOME")
defer os.Setenv("HELM_HOME", oldhh)
os.Setenv("HELM_HOME", "")
env := hh(false)
all := All(env)
if len(all) != 3 {
t.Errorf("expected 3 providers (default plus two plugins), got %d", len(all))
}
if _, err := all.ByScheme("test2"); err != nil {
t.Error(err)
}
}
func TestByScheme(t *testing.T) {
oldhh := os.Getenv("HELM_HOME")
defer os.Setenv("HELM_HOME", oldhh)
os.Setenv("HELM_HOME", "")
env := hh(false)
if _, err := ByScheme("test", env); err != nil {
t.Error(err)
}
if _, err := ByScheme("https", env); err != nil {
t.Error(err)
}
}

@ -1,11 +1,10 @@
/* /*
Copyright 2016 The Kubernetes Authors All rights reserved. Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
You may obtain a copy of the License at You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
@ -14,7 +13,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package httpgetter package getter
import ( import (
"bytes" "bytes"
@ -22,18 +21,17 @@ import (
"io" "io"
"net/http" "net/http"
"k8s.io/helm/pkg/getter"
"k8s.io/helm/pkg/tlsutil" "k8s.io/helm/pkg/tlsutil"
"k8s.io/helm/pkg/urlutil" "k8s.io/helm/pkg/urlutil"
) )
//HTTPGetter is the efault HTTP(/S) backend handler //httpGetter is the efault HTTP(/S) backend handler
type HTTPGetter struct { type httpGetter struct {
client *http.Client client *http.Client
} }
//Get performs a Get from repo.Getter and returns the body. //Get performs a Get from repo.Getter and returns the body.
func (g *HTTPGetter) Get(href string) (*bytes.Buffer, error) { func (g *httpGetter) Get(href string) (*bytes.Buffer, error) {
buf := bytes.NewBuffer(nil) buf := bytes.NewBuffer(nil)
resp, err := g.client.Get(href) resp, err := g.client.Get(href)
@ -49,9 +47,9 @@ func (g *HTTPGetter) Get(href string) (*bytes.Buffer, error) {
return buf, err return buf, err
} }
//New constructs a valid http/https client as Getter // newHTTPGetter constructs a valid http/https client as Getter
func New(URL, CertFile, KeyFile, CAFile string) (getter.Getter, error) { func newHTTPGetter(URL, CertFile, KeyFile, CAFile string) (Getter, error) {
var client HTTPGetter var client httpGetter
if CertFile != "" && KeyFile != "" && CAFile != "" { if CertFile != "" && KeyFile != "" && CAFile != "" {
tlsConf, err := tlsutil.NewClientTLS(CertFile, KeyFile, CAFile) tlsConf, err := tlsutil.NewClientTLS(CertFile, KeyFile, CAFile)
if err != nil { if err != nil {

@ -0,0 +1,48 @@
/*
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 getter
import (
"net/http"
"path/filepath"
"testing"
)
func TestHTTPGetter(t *testing.T) {
g, err := newHTTPGetter("http://example.com", "", "", "")
if err != nil {
t.Fatal(err)
}
if hg, ok := g.(*httpGetter); !ok {
t.Fatal("Expected newHTTPGetter to produce an httpGetter")
} else if hg.client != http.DefaultClient {
t.Fatal("Expected newHTTPGetter to return a default HTTP client.")
}
// Test with SSL:
cd := "../../testdata"
join := filepath.Join
ca, pub, priv := join(cd, "ca.pem"), join(cd, "crt.pem"), join(cd, "key.pem")
g, err = newHTTPGetter("http://example.com/", pub, priv, ca)
if err != nil {
t.Fatal(err)
}
if _, ok := g.(*httpGetter); !ok {
t.Fatal("Expected newHTTPGetter to produce an httpGetter")
}
}

@ -13,7 +13,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package plugingetter package getter
import ( import (
"bytes" "bytes"
@ -22,14 +22,37 @@ import (
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"k8s.io/helm/pkg/getter"
"k8s.io/helm/pkg/helm/environment" "k8s.io/helm/pkg/helm/environment"
"k8s.io/helm/pkg/plugin" "k8s.io/helm/pkg/plugin"
) )
// PluginGetter is a generic type to invoke custom downloaders, // collectPlugins scans for getter plugins.
// This will load plugins according to the environment.
func collectPlugins(settings environment.EnvSettings) (Providers, error) {
plugins, err := plugin.FindPlugins(settings.PlugDirs)
if err != nil {
return nil, err
}
var result Providers
for _, plugin := range plugins {
for _, downloader := range plugin.Metadata.Downloaders {
result = append(result, Provider{
Schemes: downloader.Protocols,
New: newPluginGetter(
downloader.Command,
settings,
plugin.Metadata.Name,
plugin.Dir,
),
})
}
}
return result, nil
}
// pluginGetter is a generic type to invoke custom downloaders,
// implemented in plugins. // implemented in plugins.
type PluginGetter struct { type pluginGetter struct {
command string command string
certFile, keyFile, cAFile string certFile, keyFile, cAFile string
settings environment.EnvSettings settings environment.EnvSettings
@ -38,7 +61,7 @@ type PluginGetter struct {
} }
// Get runs downloader plugin command // Get runs downloader plugin command
func (p *PluginGetter) Get(href string) (*bytes.Buffer, error) { func (p *pluginGetter) Get(href string) (*bytes.Buffer, error) {
argv := []string{p.certFile, p.keyFile, p.cAFile, href} argv := []string{p.certFile, p.keyFile, p.cAFile, href}
prog := exec.Command(filepath.Join(p.base, p.command), argv...) prog := exec.Command(filepath.Join(p.base, p.command), argv...)
plugin.SetupPluginEnv(p.settings, p.name, p.base) plugin.SetupPluginEnv(p.settings, p.name, p.base)
@ -56,13 +79,10 @@ func (p *PluginGetter) Get(href string) (*bytes.Buffer, error) {
return buf, nil return buf, nil
} }
// ConstructNew constructs a valid plugin getter // newPluginGetter constructs a valid plugin getter
func ConstructNew(command string, func newPluginGetter(command string, settings environment.EnvSettings, name, base string) Constructor {
settings environment.EnvSettings, return func(URL, CertFile, KeyFile, CAFile string) (Getter, error) {
name string, result := &pluginGetter{
base string) getter.Constructor {
return func(URL, CertFile, KeyFile, CAFile string) (getter.Getter, error) {
result := &PluginGetter{
command: command, command: command,
certFile: CertFile, certFile: CertFile,
keyFile: KeyFile, keyFile: KeyFile,

@ -0,0 +1,92 @@
/*
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 getter
import (
"os"
"path/filepath"
"strings"
"testing"
"k8s.io/helm/pkg/helm/environment"
"k8s.io/helm/pkg/helm/helmpath"
)
func hh(debug bool) environment.EnvSettings {
apath, err := filepath.Abs("./testdata")
if err != nil {
panic(err)
}
hp := helmpath.Home(apath)
return environment.EnvSettings{
Home: hp,
PlugDirs: hp.Plugins(),
Debug: debug,
}
}
func TestCollectPlugins(t *testing.T) {
// Reset HELM HOME to testdata.
oldhh := os.Getenv("HELM_HOME")
defer os.Setenv("HELM_HOME", oldhh)
os.Setenv("HELM_HOME", "")
env := hh(false)
p, err := collectPlugins(env)
if err != nil {
t.Fatal(err)
}
if len(p) != 2 {
t.Errorf("Expected 2 plugins, got %d: %v", len(p), p)
}
if _, err := p.ByScheme("test2"); err != nil {
t.Error(err)
}
if _, err := p.ByScheme("test"); err != nil {
t.Error(err)
}
if _, err := p.ByScheme("nosuchthing"); err == nil {
t.Fatal("did not expect protocol handler for nosuchthing")
}
}
func TestPluginGetter(t *testing.T) {
oldhh := os.Getenv("HELM_HOME")
defer os.Setenv("HELM_HOME", oldhh)
os.Setenv("HELM_HOME", "")
env := hh(false)
pg := newPluginGetter("echo", env, "test", ".")
g, err := pg("test://foo/bar", "", "", "")
if err != nil {
t.Fatal(err)
}
data, err := g.Get("test://foo/bar")
if err != nil {
t.Fatal(err)
}
expect := "test://foo/bar"
got := strings.TrimSpace(data.String())
if got != expect {
t.Errorf("Expected %q, got %q", expect, got)
}
}

@ -0,0 +1,8 @@
#!/bin/bash
echo ENVIRONMENT
env
echo ""
echo ARGUMENTS
echo $@

@ -0,0 +1,15 @@
name: "testgetter"
version: "0.1.0"
usage: "Fetch a package from a test:// source"
description: |-
Print the environment that the plugin was given, then exit.
This registers the test:// protocol.
command: "$HELM_PLUGIN_DIR/get.sh"
ignoreFlags: true
downloaders:
#- command: "$HELM_PLUGIN_DIR/get.sh"
- command: "echo"
protocols:
- "test"

@ -0,0 +1,8 @@
#!/bin/bash
echo ENVIRONMENT
env
echo ""
echo ARGUMENTS
echo $@

@ -0,0 +1,10 @@
name: "testgetter2"
version: "0.1.0"
usage: "Fetch a different package from a test2:// source"
description: "Handle test2 scheme"
command: "$HELM_PLUGIN_DIR/get.sh"
ignoreFlags: true
downloaders:
- command: "echo"
protocols:
- "test2"

@ -0,0 +1 @@
repository/local/index.yaml

File diff suppressed because it is too large Load Diff

@ -0,0 +1,3 @@
apiVersion: v1
entries: {}
generated: 2017-04-28T12:34:38.900985501-06:00

@ -0,0 +1,15 @@
apiVersion: v1
generated: 2017-04-28T12:34:38.551693035-06:00
repositories:
- caFile: ""
cache: repository/cache/stable-index.yaml
certFile: ""
keyFile: ""
name: stable
url: https://kubernetes-charts.storage.googleapis.com
- caFile: ""
cache: repository/cache/local-index.yaml
certFile: ""
keyFile: ""
name: local
url: http://127.0.0.1:8879/charts

@ -30,12 +30,17 @@ import (
) )
const ( const (
HomeEnvVar = "HELM_HOME" // HomeEnvVar is the HELM_HOME environment variable key.
PluginEnvVar = "HELM_PLUGIN" HomeEnvVar = "HELM_HOME"
// PluginEnvVar is the HELM_PLUGIN environment variable key.
PluginEnvVar = "HELM_PLUGIN"
// PluginDisableEnvVar is the HELM_NO_PLUGINS environment variable key.
PluginDisableEnvVar = "HELM_NO_PLUGINS" PluginDisableEnvVar = "HELM_NO_PLUGINS"
HostEnvVar = "HELM_HOST" // HostEnvVar is the HELM_HOST environment variable key.
HostEnvVar = "HELM_HOST"
) )
// DefaultHelmHome gets the configured HELM_HOME, or returns the default.
func DefaultHelmHome() string { func DefaultHelmHome() string {
if home := os.Getenv(HomeEnvVar); home != "" { if home := os.Getenv(HomeEnvVar); home != "" {
return home return home
@ -43,14 +48,21 @@ func DefaultHelmHome() string {
return filepath.Join(os.Getenv("HOME"), ".helm") return filepath.Join(os.Getenv("HOME"), ".helm")
} }
// DefaultHelmHost returns the configured HELM_HOST or an empty string.
func DefaultHelmHost() string { func DefaultHelmHost() string {
return os.Getenv(HostEnvVar) return os.Getenv(HostEnvVar)
} }
// EnvSettings describes all of the environment settings.
type EnvSettings struct { type EnvSettings struct {
TillerHost string // TillerHost is the host and port of Tiller.
TillerHost string
// TillerNamespace is the namespace in which Tiller runs.
TillerNamespace string TillerNamespace string
Home helmpath.Home // Home is the local path to the Helm home directory.
PlugDirs string Home helmpath.Home
Debug bool // PluginDirs is the path to the plugin directories.
PlugDirs string
// Debug indicates whether or not Helm is running in Debug mode.
Debug bool
} }

@ -408,7 +408,7 @@ func WithMaxHistory(max int32) HistoryOption {
// NewContext creates a versioned context. // NewContext creates a versioned context.
func NewContext() context.Context { func NewContext() context.Context {
md := metadata.Pairs("x-helm-api-client", version.Version) md := metadata.Pairs("x-helm-api-client", version.GetVersion())
return metadata.NewContext(context.TODO(), md) return metadata.NewContext(context.TODO(), md)
} }

@ -92,7 +92,7 @@ func (c *Client) waitForResources(timeout time.Duration, created Result) error {
} }
// Find RS associated with deployment // Find RS associated with deployment
newReplicaSet, err := deploymentutil.FindNewReplicaSet(currentDeployment, replicaSets) newReplicaSet, err := deploymentutil.FindNewReplicaSet(currentDeployment, replicaSets)
if err != nil { if err != nil || newReplicaSet == nil {
return false, err return false, err
} }
newDeployment := deployment{ newDeployment := deployment{

@ -24,6 +24,13 @@ func (m *Config) String() string { return proto.CompactTextString(m)
func (*Config) ProtoMessage() {} func (*Config) ProtoMessage() {}
func (*Config) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{0} } func (*Config) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{0} }
func (m *Config) GetRaw() string {
if m != nil {
return m.Raw
}
return ""
}
func (m *Config) GetValues() map[string]*Value { func (m *Config) GetValues() map[string]*Value {
if m != nil { if m != nil {
return m.Values return m.Values
@ -41,6 +48,13 @@ func (m *Value) String() string { return proto.CompactTextString(m) }
func (*Value) ProtoMessage() {} func (*Value) ProtoMessage() {}
func (*Value) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{1} } func (*Value) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{1} }
func (m *Value) GetValue() string {
if m != nil {
return m.Value
}
return ""
}
func init() { func init() {
proto.RegisterType((*Config)(nil), "hapi.chart.Config") proto.RegisterType((*Config)(nil), "hapi.chart.Config")
proto.RegisterType((*Value)(nil), "hapi.chart.Value") proto.RegisterType((*Value)(nil), "hapi.chart.Value")

@ -47,6 +47,20 @@ func (m *Maintainer) String() string { return proto.CompactTextString
func (*Maintainer) ProtoMessage() {} func (*Maintainer) ProtoMessage() {}
func (*Maintainer) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{0} } func (*Maintainer) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{0} }
func (m *Maintainer) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *Maintainer) GetEmail() string {
if m != nil {
return m.Email
}
return ""
}
// Metadata for a Chart file. This models the structure of a Chart.yaml file. // Metadata for a Chart file. This models the structure of a Chart.yaml file.
// //
// Spec: https://k8s.io/helm/blob/master/docs/design/chart_format.md#the-chart-file // Spec: https://k8s.io/helm/blob/master/docs/design/chart_format.md#the-chart-file
@ -89,6 +103,48 @@ func (m *Metadata) String() string { return proto.CompactTextString(m
func (*Metadata) ProtoMessage() {} func (*Metadata) ProtoMessage() {}
func (*Metadata) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{1} } func (*Metadata) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{1} }
func (m *Metadata) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *Metadata) GetHome() string {
if m != nil {
return m.Home
}
return ""
}
func (m *Metadata) GetSources() []string {
if m != nil {
return m.Sources
}
return nil
}
func (m *Metadata) GetVersion() string {
if m != nil {
return m.Version
}
return ""
}
func (m *Metadata) GetDescription() string {
if m != nil {
return m.Description
}
return ""
}
func (m *Metadata) GetKeywords() []string {
if m != nil {
return m.Keywords
}
return nil
}
func (m *Metadata) GetMaintainers() []*Maintainer { func (m *Metadata) GetMaintainers() []*Maintainer {
if m != nil { if m != nil {
return m.Maintainers return m.Maintainers
@ -96,6 +152,62 @@ func (m *Metadata) GetMaintainers() []*Maintainer {
return nil return nil
} }
func (m *Metadata) GetEngine() string {
if m != nil {
return m.Engine
}
return ""
}
func (m *Metadata) GetIcon() string {
if m != nil {
return m.Icon
}
return ""
}
func (m *Metadata) GetApiVersion() string {
if m != nil {
return m.ApiVersion
}
return ""
}
func (m *Metadata) GetCondition() string {
if m != nil {
return m.Condition
}
return ""
}
func (m *Metadata) GetTags() string {
if m != nil {
return m.Tags
}
return ""
}
func (m *Metadata) GetAppVersion() string {
if m != nil {
return m.AppVersion
}
return ""
}
func (m *Metadata) GetDeprecated() bool {
if m != nil {
return m.Deprecated
}
return false
}
func (m *Metadata) GetTillerVersion() string {
if m != nil {
return m.TillerVersion
}
return ""
}
func init() { func init() {
proto.RegisterType((*Maintainer)(nil), "hapi.chart.Maintainer") proto.RegisterType((*Maintainer)(nil), "hapi.chart.Maintainer")
proto.RegisterType((*Metadata)(nil), "hapi.chart.Metadata") proto.RegisterType((*Metadata)(nil), "hapi.chart.Metadata")

@ -29,6 +29,20 @@ func (m *Template) String() string { return proto.CompactTextString(m
func (*Template) ProtoMessage() {} func (*Template) ProtoMessage() {}
func (*Template) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{0} } func (*Template) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{0} }
func (m *Template) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *Template) GetData() []byte {
if m != nil {
return m.Data
}
return nil
}
func init() { func init() {
proto.RegisterType((*Template)(nil), "hapi.chart.Template") proto.RegisterType((*Template)(nil), "hapi.chart.Template")
} }

@ -112,6 +112,41 @@ func (m *Hook) String() string { return proto.CompactTextString(m) }
func (*Hook) ProtoMessage() {} func (*Hook) ProtoMessage() {}
func (*Hook) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } func (*Hook) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (m *Hook) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *Hook) GetKind() string {
if m != nil {
return m.Kind
}
return ""
}
func (m *Hook) GetPath() string {
if m != nil {
return m.Path
}
return ""
}
func (m *Hook) GetManifest() string {
if m != nil {
return m.Manifest
}
return ""
}
func (m *Hook) GetEvents() []Hook_Event {
if m != nil {
return m.Events
}
return nil
}
func (m *Hook) GetLastRun() *google_protobuf.Timestamp { func (m *Hook) GetLastRun() *google_protobuf.Timestamp {
if m != nil { if m != nil {
return m.LastRun return m.LastRun
@ -119,6 +154,13 @@ func (m *Hook) GetLastRun() *google_protobuf.Timestamp {
return nil return nil
} }
func (m *Hook) GetWeight() int32 {
if m != nil {
return m.Weight
}
return 0
}
func init() { func init() {
proto.RegisterType((*Hook)(nil), "hapi.release.Hook") proto.RegisterType((*Hook)(nil), "hapi.release.Hook")
proto.RegisterEnum("hapi.release.Hook_Event", Hook_Event_name, Hook_Event_value) proto.RegisterEnum("hapi.release.Hook_Event", Hook_Event_name, Hook_Event_value)

@ -58,6 +58,13 @@ func (m *Info) GetDeleted() *google_protobuf.Timestamp {
return nil return nil
} }
func (m *Info) GetDescription() string {
if m != nil {
return m.Description
}
return ""
}
func init() { func init() {
proto.RegisterType((*Info)(nil), "hapi.release.Info") proto.RegisterType((*Info)(nil), "hapi.release.Info")
} }

@ -42,6 +42,13 @@ func (m *Release) String() string { return proto.CompactTextString(m)
func (*Release) ProtoMessage() {} func (*Release) ProtoMessage() {}
func (*Release) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{0} } func (*Release) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{0} }
func (m *Release) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *Release) GetInfo() *Info { func (m *Release) GetInfo() *Info {
if m != nil { if m != nil {
return m.Info return m.Info
@ -63,6 +70,13 @@ func (m *Release) GetConfig() *hapi_chart.Config {
return nil return nil
} }
func (m *Release) GetManifest() string {
if m != nil {
return m.Manifest
}
return ""
}
func (m *Release) GetHooks() []*Hook { func (m *Release) GetHooks() []*Hook {
if m != nil { if m != nil {
return m.Hooks return m.Hooks
@ -70,6 +84,20 @@ func (m *Release) GetHooks() []*Hook {
return nil return nil
} }
func (m *Release) GetVersion() int32 {
if m != nil {
return m.Version
}
return 0
}
func (m *Release) GetNamespace() string {
if m != nil {
return m.Namespace
}
return ""
}
func init() { func init() {
proto.RegisterType((*Release)(nil), "hapi.release.Release") proto.RegisterType((*Release)(nil), "hapi.release.Release")
} }

@ -69,6 +69,27 @@ func (m *Status) String() string { return proto.CompactTextString(m)
func (*Status) ProtoMessage() {} func (*Status) ProtoMessage() {}
func (*Status) Descriptor() ([]byte, []int) { return fileDescriptor4, []int{0} } func (*Status) Descriptor() ([]byte, []int) { return fileDescriptor4, []int{0} }
func (m *Status) GetCode() Status_Code {
if m != nil {
return m.Code
}
return Status_UNKNOWN
}
func (m *Status) GetResources() string {
if m != nil {
return m.Resources
}
return ""
}
func (m *Status) GetNotes() string {
if m != nil {
return m.Notes
}
return ""
}
func (m *Status) GetLastTestSuiteRun() *TestSuite { func (m *Status) GetLastTestSuiteRun() *TestSuite {
if m != nil { if m != nil {
return m.LastTestSuiteRun return m.LastTestSuiteRun

@ -51,6 +51,27 @@ func (m *TestRun) String() string { return proto.CompactTextString(m)
func (*TestRun) ProtoMessage() {} func (*TestRun) ProtoMessage() {}
func (*TestRun) Descriptor() ([]byte, []int) { return fileDescriptor5, []int{0} } func (*TestRun) Descriptor() ([]byte, []int) { return fileDescriptor5, []int{0} }
func (m *TestRun) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *TestRun) GetStatus() TestRun_Status {
if m != nil {
return m.Status
}
return TestRun_UNKNOWN
}
func (m *TestRun) GetInfo() string {
if m != nil {
return m.Info
}
return ""
}
func (m *TestRun) GetStartedAt() *google_protobuf.Timestamp { func (m *TestRun) GetStartedAt() *google_protobuf.Timestamp {
if m != nil { if m != nil {
return m.StartedAt return m.StartedAt

@ -141,6 +141,55 @@ func (m *ListReleasesRequest) String() string { return proto.CompactT
func (*ListReleasesRequest) ProtoMessage() {} func (*ListReleasesRequest) ProtoMessage() {}
func (*ListReleasesRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } func (*ListReleasesRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (m *ListReleasesRequest) GetLimit() int64 {
if m != nil {
return m.Limit
}
return 0
}
func (m *ListReleasesRequest) GetOffset() string {
if m != nil {
return m.Offset
}
return ""
}
func (m *ListReleasesRequest) GetSortBy() ListSort_SortBy {
if m != nil {
return m.SortBy
}
return ListSort_UNKNOWN
}
func (m *ListReleasesRequest) GetFilter() string {
if m != nil {
return m.Filter
}
return ""
}
func (m *ListReleasesRequest) GetSortOrder() ListSort_SortOrder {
if m != nil {
return m.SortOrder
}
return ListSort_ASC
}
func (m *ListReleasesRequest) GetStatusCodes() []hapi_release3.Status_Code {
if m != nil {
return m.StatusCodes
}
return nil
}
func (m *ListReleasesRequest) GetNamespace() string {
if m != nil {
return m.Namespace
}
return ""
}
// ListSort defines sorting fields on a release list. // ListSort defines sorting fields on a release list.
type ListSort struct { type ListSort struct {
} }
@ -168,6 +217,27 @@ func (m *ListReleasesResponse) String() string { return proto.Compact
func (*ListReleasesResponse) ProtoMessage() {} func (*ListReleasesResponse) ProtoMessage() {}
func (*ListReleasesResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } func (*ListReleasesResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
func (m *ListReleasesResponse) GetCount() int64 {
if m != nil {
return m.Count
}
return 0
}
func (m *ListReleasesResponse) GetNext() string {
if m != nil {
return m.Next
}
return ""
}
func (m *ListReleasesResponse) GetTotal() int64 {
if m != nil {
return m.Total
}
return 0
}
func (m *ListReleasesResponse) GetReleases() []*hapi_release5.Release { func (m *ListReleasesResponse) GetReleases() []*hapi_release5.Release {
if m != nil { if m != nil {
return m.Releases return m.Releases
@ -188,6 +258,20 @@ func (m *GetReleaseStatusRequest) String() string { return proto.Comp
func (*GetReleaseStatusRequest) ProtoMessage() {} func (*GetReleaseStatusRequest) ProtoMessage() {}
func (*GetReleaseStatusRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } func (*GetReleaseStatusRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
func (m *GetReleaseStatusRequest) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *GetReleaseStatusRequest) GetVersion() int32 {
if m != nil {
return m.Version
}
return 0
}
// GetReleaseStatusResponse is the response indicating the status of the named release. // GetReleaseStatusResponse is the response indicating the status of the named release.
type GetReleaseStatusResponse struct { type GetReleaseStatusResponse struct {
// Name is the name of the release. // Name is the name of the release.
@ -203,6 +287,13 @@ func (m *GetReleaseStatusResponse) String() string { return proto.Com
func (*GetReleaseStatusResponse) ProtoMessage() {} func (*GetReleaseStatusResponse) ProtoMessage() {}
func (*GetReleaseStatusResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } func (*GetReleaseStatusResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
func (m *GetReleaseStatusResponse) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *GetReleaseStatusResponse) GetInfo() *hapi_release4.Info { func (m *GetReleaseStatusResponse) GetInfo() *hapi_release4.Info {
if m != nil { if m != nil {
return m.Info return m.Info
@ -210,6 +301,13 @@ func (m *GetReleaseStatusResponse) GetInfo() *hapi_release4.Info {
return nil return nil
} }
func (m *GetReleaseStatusResponse) GetNamespace() string {
if m != nil {
return m.Namespace
}
return ""
}
// GetReleaseContentRequest is a request to get the contents of a release. // GetReleaseContentRequest is a request to get the contents of a release.
type GetReleaseContentRequest struct { type GetReleaseContentRequest struct {
// The name of the release // The name of the release
@ -223,6 +321,20 @@ func (m *GetReleaseContentRequest) String() string { return proto.Com
func (*GetReleaseContentRequest) ProtoMessage() {} func (*GetReleaseContentRequest) ProtoMessage() {}
func (*GetReleaseContentRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } func (*GetReleaseContentRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
func (m *GetReleaseContentRequest) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *GetReleaseContentRequest) GetVersion() int32 {
if m != nil {
return m.Version
}
return 0
}
// GetReleaseContentResponse is a response containing the contents of a release. // GetReleaseContentResponse is a response containing the contents of a release.
type GetReleaseContentResponse struct { type GetReleaseContentResponse struct {
// The release content // The release content
@ -304,6 +416,13 @@ func (m *UpdateReleaseRequest) String() string { return proto.Compact
func (*UpdateReleaseRequest) ProtoMessage() {} func (*UpdateReleaseRequest) ProtoMessage() {}
func (*UpdateReleaseRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} } func (*UpdateReleaseRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} }
func (m *UpdateReleaseRequest) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *UpdateReleaseRequest) GetChart() *hapi_chart3.Chart { func (m *UpdateReleaseRequest) GetChart() *hapi_chart3.Chart {
if m != nil { if m != nil {
return m.Chart return m.Chart
@ -318,6 +437,55 @@ func (m *UpdateReleaseRequest) GetValues() *hapi_chart.Config {
return nil return nil
} }
func (m *UpdateReleaseRequest) GetDryRun() bool {
if m != nil {
return m.DryRun
}
return false
}
func (m *UpdateReleaseRequest) GetDisableHooks() bool {
if m != nil {
return m.DisableHooks
}
return false
}
func (m *UpdateReleaseRequest) GetRecreate() bool {
if m != nil {
return m.Recreate
}
return false
}
func (m *UpdateReleaseRequest) GetTimeout() int64 {
if m != nil {
return m.Timeout
}
return 0
}
func (m *UpdateReleaseRequest) GetResetValues() bool {
if m != nil {
return m.ResetValues
}
return false
}
func (m *UpdateReleaseRequest) GetWait() bool {
if m != nil {
return m.Wait
}
return false
}
func (m *UpdateReleaseRequest) GetReuseValues() bool {
if m != nil {
return m.ReuseValues
}
return false
}
// UpdateReleaseResponse is the response to an update request. // UpdateReleaseResponse is the response to an update request.
type UpdateReleaseResponse struct { type UpdateReleaseResponse struct {
Release *hapi_release5.Release `protobuf:"bytes,1,opt,name=release" json:"release,omitempty"` Release *hapi_release5.Release `protobuf:"bytes,1,opt,name=release" json:"release,omitempty"`
@ -358,6 +526,55 @@ func (m *RollbackReleaseRequest) String() string { return proto.Compa
func (*RollbackReleaseRequest) ProtoMessage() {} func (*RollbackReleaseRequest) ProtoMessage() {}
func (*RollbackReleaseRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} } func (*RollbackReleaseRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} }
func (m *RollbackReleaseRequest) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *RollbackReleaseRequest) GetDryRun() bool {
if m != nil {
return m.DryRun
}
return false
}
func (m *RollbackReleaseRequest) GetDisableHooks() bool {
if m != nil {
return m.DisableHooks
}
return false
}
func (m *RollbackReleaseRequest) GetVersion() int32 {
if m != nil {
return m.Version
}
return 0
}
func (m *RollbackReleaseRequest) GetRecreate() bool {
if m != nil {
return m.Recreate
}
return false
}
func (m *RollbackReleaseRequest) GetTimeout() int64 {
if m != nil {
return m.Timeout
}
return 0
}
func (m *RollbackReleaseRequest) GetWait() bool {
if m != nil {
return m.Wait
}
return false
}
// RollbackReleaseResponse is the response to an update request. // RollbackReleaseResponse is the response to an update request.
type RollbackReleaseResponse struct { type RollbackReleaseResponse struct {
Release *hapi_release5.Release `protobuf:"bytes,1,opt,name=release" json:"release,omitempty"` Release *hapi_release5.Release `protobuf:"bytes,1,opt,name=release" json:"release,omitempty"`
@ -421,6 +638,55 @@ func (m *InstallReleaseRequest) GetValues() *hapi_chart.Config {
return nil return nil
} }
func (m *InstallReleaseRequest) GetDryRun() bool {
if m != nil {
return m.DryRun
}
return false
}
func (m *InstallReleaseRequest) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *InstallReleaseRequest) GetDisableHooks() bool {
if m != nil {
return m.DisableHooks
}
return false
}
func (m *InstallReleaseRequest) GetNamespace() string {
if m != nil {
return m.Namespace
}
return ""
}
func (m *InstallReleaseRequest) GetReuseName() bool {
if m != nil {
return m.ReuseName
}
return false
}
func (m *InstallReleaseRequest) GetTimeout() int64 {
if m != nil {
return m.Timeout
}
return 0
}
func (m *InstallReleaseRequest) GetWait() bool {
if m != nil {
return m.Wait
}
return false
}
// InstallReleaseResponse is the response from a release installation. // InstallReleaseResponse is the response from a release installation.
type InstallReleaseResponse struct { type InstallReleaseResponse struct {
Release *hapi_release5.Release `protobuf:"bytes,1,opt,name=release" json:"release,omitempty"` Release *hapi_release5.Release `protobuf:"bytes,1,opt,name=release" json:"release,omitempty"`
@ -455,6 +721,34 @@ func (m *UninstallReleaseRequest) String() string { return proto.Comp
func (*UninstallReleaseRequest) ProtoMessage() {} func (*UninstallReleaseRequest) ProtoMessage() {}
func (*UninstallReleaseRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{15} } func (*UninstallReleaseRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{15} }
func (m *UninstallReleaseRequest) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *UninstallReleaseRequest) GetDisableHooks() bool {
if m != nil {
return m.DisableHooks
}
return false
}
func (m *UninstallReleaseRequest) GetPurge() bool {
if m != nil {
return m.Purge
}
return false
}
func (m *UninstallReleaseRequest) GetTimeout() int64 {
if m != nil {
return m.Timeout
}
return 0
}
// UninstallReleaseResponse represents a successful response to an uninstall request. // UninstallReleaseResponse represents a successful response to an uninstall request.
type UninstallReleaseResponse struct { type UninstallReleaseResponse struct {
// Release is the release that was marked deleted. // Release is the release that was marked deleted.
@ -475,6 +769,13 @@ func (m *UninstallReleaseResponse) GetRelease() *hapi_release5.Release {
return nil return nil
} }
func (m *UninstallReleaseResponse) GetInfo() string {
if m != nil {
return m.Info
}
return ""
}
// GetVersionRequest requests for version information. // GetVersionRequest requests for version information.
type GetVersionRequest struct { type GetVersionRequest struct {
} }
@ -513,6 +814,20 @@ func (m *GetHistoryRequest) String() string { return proto.CompactTex
func (*GetHistoryRequest) ProtoMessage() {} func (*GetHistoryRequest) ProtoMessage() {}
func (*GetHistoryRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{19} } func (*GetHistoryRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{19} }
func (m *GetHistoryRequest) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *GetHistoryRequest) GetMax() int32 {
if m != nil {
return m.Max
}
return 0
}
// GetHistoryResponse is received in response to a GetHistory rpc. // GetHistoryResponse is received in response to a GetHistory rpc.
type GetHistoryResponse struct { type GetHistoryResponse struct {
Releases []*hapi_release5.Release `protobuf:"bytes,1,rep,name=releases" json:"releases,omitempty"` Releases []*hapi_release5.Release `protobuf:"bytes,1,rep,name=releases" json:"releases,omitempty"`
@ -545,6 +860,27 @@ func (m *TestReleaseRequest) String() string { return proto.CompactTe
func (*TestReleaseRequest) ProtoMessage() {} func (*TestReleaseRequest) ProtoMessage() {}
func (*TestReleaseRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{21} } func (*TestReleaseRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{21} }
func (m *TestReleaseRequest) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *TestReleaseRequest) GetTimeout() int64 {
if m != nil {
return m.Timeout
}
return 0
}
func (m *TestReleaseRequest) GetCleanup() bool {
if m != nil {
return m.Cleanup
}
return false
}
// TestReleaseResponse represents a message from executing a test // TestReleaseResponse represents a message from executing a test
type TestReleaseResponse struct { type TestReleaseResponse struct {
Msg string `protobuf:"bytes,1,opt,name=msg" json:"msg,omitempty"` Msg string `protobuf:"bytes,1,opt,name=msg" json:"msg,omitempty"`
@ -555,6 +891,13 @@ func (m *TestReleaseResponse) String() string { return proto.CompactT
func (*TestReleaseResponse) ProtoMessage() {} func (*TestReleaseResponse) ProtoMessage() {}
func (*TestReleaseResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{22} } func (*TestReleaseResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{22} }
func (m *TestReleaseResponse) GetMsg() string {
if m != nil {
return m.Msg
}
return ""
}
func init() { func init() {
proto.RegisterType((*ListReleasesRequest)(nil), "hapi.services.tiller.ListReleasesRequest") proto.RegisterType((*ListReleasesRequest)(nil), "hapi.services.tiller.ListReleasesRequest")
proto.RegisterType((*ListSort)(nil), "hapi.services.tiller.ListSort") proto.RegisterType((*ListSort)(nil), "hapi.services.tiller.ListSort")
@ -589,7 +932,7 @@ var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file // This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against. // is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion3 const _ = grpc.SupportPackageIsVersion4
// Client API for ReleaseService service // Client API for ReleaseService service
@ -1097,7 +1440,7 @@ var _ReleaseService_serviceDesc = grpc.ServiceDesc{
ServerStreams: true, ServerStreams: true,
}, },
}, },
Metadata: fileDescriptor0, Metadata: "hapi/services/tiller.proto",
} }
func init() { proto.RegisterFile("hapi/services/tiller.proto", fileDescriptor0) } func init() { proto.RegisterFile("hapi/services/tiller.proto", fileDescriptor0) }

@ -40,6 +40,27 @@ func (m *Version) String() string { return proto.CompactTextString(m)
func (*Version) ProtoMessage() {} func (*Version) ProtoMessage() {}
func (*Version) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } func (*Version) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (m *Version) GetSemVer() string {
if m != nil {
return m.SemVer
}
return ""
}
func (m *Version) GetGitCommit() string {
if m != nil {
return m.GitCommit
}
return ""
}
func (m *Version) GetGitTreeState() string {
if m != nil {
return m.GitTreeState
}
return ""
}
func init() { func init() {
proto.RegisterType((*Version)(nil), "hapi.version.Version") proto.RegisterType((*Version)(nil), "hapi.version.Version")
} }

@ -19,6 +19,7 @@ package releaseutil
import ( import (
"fmt" "fmt"
"regexp" "regexp"
"strings"
) )
// SimpleHead defines what the structure of the head of a manifest file // SimpleHead defines what the structure of the head of a manifest file
@ -34,16 +35,25 @@ type SimpleHead struct {
var sep = regexp.MustCompile("(?:^|\\s*\n)---\\s*") var sep = regexp.MustCompile("(?:^|\\s*\n)---\\s*")
// SplitManifests takes a string of manifest and returns a map contains individual manifests // SplitManifests takes a string of manifest and returns a map contains individual manifests
func SplitManifests(bigfile string) map[string]string { func SplitManifests(bigFile string) map[string]string {
// Basically, we're quickly splitting a stream of YAML documents into an // Basically, we're quickly splitting a stream of YAML documents into an
// array of YAML docs. In the current implementation, the file name is just // array of YAML docs. In the current implementation, the file name is just
// a place holder, and doesn't have any further meaning. // a place holder, and doesn't have any further meaning.
tpl := "manifest-%d" tpl := "manifest-%d"
res := map[string]string{} res := map[string]string{}
// Making sure that any extra whitespace in YAML stream doesn't interfere in splitting documents correctly. // Making sure that any extra whitespace in YAML stream doesn't interfere in splitting documents correctly.
docs := sep.Split(bigfile, -1) bigFileTmp := strings.TrimSpace(bigFile)
for i, d := range docs { docs := sep.Split(bigFileTmp, -1)
res[fmt.Sprintf(tpl, i)] = d var count int
for _, d := range docs {
if d == "" {
continue
}
d = strings.TrimSpace(d)
res[fmt.Sprintf(tpl, count)] = d
count = count + 1
} }
return res return res
} }

@ -0,0 +1,61 @@
/*
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 releaseutil // import "k8s.io/helm/pkg/releaseutil"
import (
"reflect"
"testing"
)
const manifestFile = `
---
apiVersion: v1
kind: Pod
metadata:
name: finding-nemo,
annotations:
"helm.sh/hook": test-success
spec:
containers:
- name: nemo-test
image: fake-image
cmd: fake-command
`
const expectedManifest = `apiVersion: v1
kind: Pod
metadata:
name: finding-nemo,
annotations:
"helm.sh/hook": test-success
spec:
containers:
- name: nemo-test
image: fake-image
cmd: fake-command`
func TestSplitManifest(t *testing.T) {
manifests := SplitManifests(manifestFile)
if len(manifests) != 1 {
t.Errorf("Expected 1 manifest, got %v", len(manifests))
}
expected := map[string]string{"manifest-0": expectedManifest}
if !reflect.DeepEqual(manifests, expected) {
t.Errorf("Expected %v, got %v", expected, manifests)
}
}

@ -50,13 +50,13 @@ type ChartRepository struct {
} }
// NewChartRepository constructs ChartRepository // NewChartRepository constructs ChartRepository
func NewChartRepository(cfg *Entry, getters []getter.Prop) (*ChartRepository, error) { func NewChartRepository(cfg *Entry, getters getter.Providers) (*ChartRepository, error) {
u, err := url.Parse(cfg.URL) u, err := url.Parse(cfg.URL)
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid chart URL format: %s", cfg.URL) return nil, fmt.Errorf("invalid chart URL format: %s", cfg.URL)
} }
getterConstructor, err := getter.ConstructorByScheme(getters, u.Scheme) getterConstructor, err := getters.ByScheme(u.Scheme)
if err != nil { if err != nil {
return nil, fmt.Errorf("Could not find protocol handler for: %s", u.Scheme) return nil, fmt.Errorf("Could not find protocol handler for: %s", u.Scheme)
} }
@ -177,3 +177,50 @@ func (r *ChartRepository) generateIndex() error {
r.IndexFile.SortEntries() r.IndexFile.SortEntries()
return nil return nil
} }
// FindChartInRepoURL finds chart in chart repository pointed by repoURL
// without adding repo to repostiories
func FindChartInRepoURL(repoURL, chartName, chartVersion, certFile, keyFile, caFile string, getters getter.Providers) (string, error) {
// Download and write the index file to a temporary location
tempIndexFile, err := ioutil.TempFile("", "tmp-repo-file")
if err != nil {
return "", fmt.Errorf("cannot write index file for repository requested")
}
defer os.Remove(tempIndexFile.Name())
c := Entry{
URL: repoURL,
CertFile: certFile,
KeyFile: keyFile,
CAFile: caFile,
}
r, err := NewChartRepository(&c, getters)
if err != nil {
return "", err
}
if err := r.DownloadIndexFile(tempIndexFile.Name()); err != nil {
return "", fmt.Errorf("Looks like %q is not a valid chart repository or cannot be reached: %s", repoURL, err)
}
// Read the index file for the repository to get chart information and return chart URL
repoIndex, err := LoadIndexFile(tempIndexFile.Name())
if err != nil {
return "", err
}
errMsg := fmt.Sprintf("chart %q", chartName)
if chartVersion != "" {
errMsg = fmt.Sprintf("%s version %q", errMsg, chartVersion)
}
cv, err := repoIndex.Get(chartName, chartVersion)
if err != nil {
return "", fmt.Errorf("%s not found in %s repository", errMsg, repoURL)
}
if len(cv.URLs) == 0 {
return "", fmt.Errorf("%s has no downloadable URLs", errMsg)
}
return cv.URLs[0], nil
}

@ -23,7 +23,7 @@ import (
"testing" "testing"
"time" "time"
"k8s.io/helm/pkg/getter/defaultgetters" "k8s.io/helm/pkg/getter"
"k8s.io/helm/pkg/helm/environment" "k8s.io/helm/pkg/helm/environment"
"k8s.io/helm/pkg/proto/hapi/chart" "k8s.io/helm/pkg/proto/hapi/chart"
) )
@ -37,7 +37,7 @@ func TestLoadChartRepository(t *testing.T) {
r, err := NewChartRepository(&Entry{ r, err := NewChartRepository(&Entry{
Name: testRepository, Name: testRepository,
URL: testURL, URL: testURL,
}, defaultgetters.Get(environment.EnvSettings{})) }, getter.All(environment.EnvSettings{}))
if err != nil { if err != nil {
t.Errorf("Problem creating chart repository from %s: %v", testRepository, err) t.Errorf("Problem creating chart repository from %s: %v", testRepository, err)
} }
@ -69,7 +69,7 @@ func TestIndex(t *testing.T) {
r, err := NewChartRepository(&Entry{ r, err := NewChartRepository(&Entry{
Name: testRepository, Name: testRepository,
URL: testURL, URL: testURL,
}, defaultgetters.Get(environment.EnvSettings{})) }, getter.All(environment.EnvSettings{}))
if err != nil { if err != nil {
t.Errorf("Problem creating chart repository from %s: %v", testRepository, err) t.Errorf("Problem creating chart repository from %s: %v", testRepository, err)
} }

@ -24,7 +24,7 @@ import (
"path/filepath" "path/filepath"
"testing" "testing"
"k8s.io/helm/pkg/getter/defaultgetters" "k8s.io/helm/pkg/getter"
"k8s.io/helm/pkg/helm/environment" "k8s.io/helm/pkg/helm/environment"
"k8s.io/helm/pkg/proto/hapi/chart" "k8s.io/helm/pkg/proto/hapi/chart"
) )
@ -152,7 +152,7 @@ func TestDownloadIndexFile(t *testing.T) {
Name: testRepo, Name: testRepo,
URL: srv.URL, URL: srv.URL,
Cache: indexFilePath, Cache: indexFilePath,
}, defaultgetters.Get(environment.EnvSettings{})) }, getter.All(environment.EnvSettings{}))
if err != nil { if err != nil {
t.Errorf("Problem creating chart repository from %s: %v", testRepo, err) t.Errorf("Problem creating chart repository from %s: %v", testRepo, err)
} }

@ -19,6 +19,7 @@ package storage // import "k8s.io/helm/pkg/storage"
import ( import (
"fmt" "fmt"
"log" "log"
"sync"
rspb "k8s.io/helm/pkg/proto/hapi/release" rspb "k8s.io/helm/pkg/proto/hapi/release"
relutil "k8s.io/helm/pkg/releaseutil" relutil "k8s.io/helm/pkg/releaseutil"
@ -28,6 +29,11 @@ import (
// Storage represents a storage engine for a Release. // Storage represents a storage engine for a Release.
type Storage struct { type Storage struct {
driver.Driver driver.Driver
// releaseLocks are for locking releases to make sure that only one operation at a time is executed on each release
releaseLocks map[string]*sync.Mutex
// releaseLocksLock is a mutex for accessing releaseLocks
releaseLocksLock *sync.Mutex
} }
// Get retrieves the release from storage. An error is returned // Get retrieves the release from storage. An error is returned
@ -153,6 +159,51 @@ func (s *Storage) Last(name string) (*rspb.Release, error) {
return h[0], nil return h[0], nil
} }
// LockRelease gains a mutually exclusive access to a release via a mutex.
func (s *Storage) LockRelease(name string) error {
s.releaseLocksLock.Lock()
defer s.releaseLocksLock.Unlock()
var lock *sync.Mutex
lock, exists := s.releaseLocks[name]
if !exists {
releases, err := s.ListReleases()
if err != nil {
return err
}
found := false
for _, release := range releases {
if release.Name == name {
found = true
}
}
if !found {
return fmt.Errorf("Unable to lock release %s: release not found", name)
}
lock = &sync.Mutex{}
s.releaseLocks[name] = lock
}
lock.Lock()
return nil
}
// UnlockRelease releases a mutually exclusive access to a release.
// If release doesn't exist or wasn't previously locked - the unlock will pass
func (s *Storage) UnlockRelease(name string) {
s.releaseLocksLock.Lock()
defer s.releaseLocksLock.Unlock()
var lock *sync.Mutex
lock, exists := s.releaseLocks[name]
if !exists {
return
}
lock.Unlock()
}
// makeKey concatenates a release name and version into // makeKey concatenates a release name and version into
// a string with format ```<release_name>#v<version>```. // a string with format ```<release_name>#v<version>```.
// This key is used to uniquely identify storage objects. // This key is used to uniquely identify storage objects.
@ -167,5 +218,9 @@ func Init(d driver.Driver) *Storage {
if d == nil { if d == nil {
d = driver.NewMemory() d = driver.NewMemory()
} }
return &Storage{Driver: d} return &Storage{
Driver: d,
releaseLocks: make(map[string]*sync.Mutex),
releaseLocksLock: &sync.Mutex{},
}
} }

@ -272,3 +272,31 @@ func assertErrNil(eh func(args ...interface{}), err error, message string) {
eh(fmt.Sprintf("%s: %q", message, err)) eh(fmt.Sprintf("%s: %q", message, err))
} }
} }
func TestReleaseLocksNotExist(t *testing.T) {
s := Init(driver.NewMemory())
err := s.LockRelease("no-such-release")
if err == nil {
t.Errorf("Exptected error when trying to lock non-existing release, got nil")
}
}
func TestReleaseLocks(t *testing.T) {
s := Init(driver.NewMemory())
releaseName := "angry-beaver"
rls := ReleaseTestData{
Name: releaseName,
Version: 1,
}.ToRelease()
s.Create(rls)
err := s.LockRelease(releaseName)
if err != nil {
t.Errorf("Exptected nil err when locking existing release")
}
s.UnlockRelease(releaseName)
}

@ -317,6 +317,12 @@ func (s *ReleaseServer) GetReleaseLogs(svc services.ReleaseService_GetReleaseLog
// UpdateRelease takes an existing release and new information, and upgrades the release. // UpdateRelease takes an existing release and new information, and upgrades the release.
func (s *ReleaseServer) UpdateRelease(c ctx.Context, req *services.UpdateReleaseRequest) (*services.UpdateReleaseResponse, error) { func (s *ReleaseServer) UpdateRelease(c ctx.Context, req *services.UpdateReleaseRequest) (*services.UpdateReleaseResponse, error) {
err := s.env.Releases.LockRelease(req.Name)
if err != nil {
return nil, err
}
defer s.env.Releases.UnlockRelease(req.Name)
currentRelease, updatedRelease, err := s.prepareUpdate(req) currentRelease, updatedRelease, err := s.prepareUpdate(req)
if err != nil { if err != nil {
return nil, err return nil, err
@ -499,6 +505,12 @@ func (s *ReleaseServer) prepareUpdate(req *services.UpdateReleaseRequest) (*rele
// RollbackRelease rolls back to a previous version of the given release. // RollbackRelease rolls back to a previous version of the given release.
func (s *ReleaseServer) RollbackRelease(c ctx.Context, req *services.RollbackReleaseRequest) (*services.RollbackReleaseResponse, error) { func (s *ReleaseServer) RollbackRelease(c ctx.Context, req *services.RollbackReleaseRequest) (*services.RollbackReleaseResponse, error) {
err := s.env.Releases.LockRelease(req.Name)
if err != nil {
return nil, err
}
defer s.env.Releases.UnlockRelease(req.Name)
currentRelease, targetRelease, err := s.prepareRollback(req) currentRelease, targetRelease, err := s.prepareRollback(req)
if err != nil { if err != nil {
return nil, err return nil, err
@ -1017,6 +1029,12 @@ func (s *ReleaseServer) purgeReleases(rels ...*release.Release) error {
// UninstallRelease deletes all of the resources associated with this release, and marks the release DELETED. // UninstallRelease deletes all of the resources associated with this release, and marks the release DELETED.
func (s *ReleaseServer) UninstallRelease(c ctx.Context, req *services.UninstallReleaseRequest) (*services.UninstallReleaseResponse, error) { func (s *ReleaseServer) UninstallRelease(c ctx.Context, req *services.UninstallReleaseRequest) (*services.UninstallReleaseResponse, error) {
err := s.env.Releases.LockRelease(req.Name)
if err != nil {
return nil, err
}
defer s.env.Releases.UnlockRelease(req.Name)
if !ValidName.MatchString(req.Name) { if !ValidName.MatchString(req.Name) {
log.Printf("uninstall: Release not found: %s", req.Name) log.Printf("uninstall: Release not found: %s", req.Name)
return nil, errMissingRelease return nil, errMissingRelease

@ -38,6 +38,7 @@ import (
"k8s.io/helm/pkg/storage" "k8s.io/helm/pkg/storage"
"k8s.io/helm/pkg/storage/driver" "k8s.io/helm/pkg/storage/driver"
"k8s.io/helm/pkg/tiller/environment" "k8s.io/helm/pkg/tiller/environment"
"k8s.io/helm/pkg/version"
) )
const notesText = "my notes here" const notesText = "my notes here"
@ -465,6 +466,7 @@ func TestInstallRelease_WithNotesRendered(t *testing.T) {
} }
func TestInstallRelease_TillerVersion(t *testing.T) { func TestInstallRelease_TillerVersion(t *testing.T) {
version.Version = "2.2.0"
c := helm.NewContext() c := helm.NewContext()
rs := rsFixture() rs := rsFixture()
@ -486,6 +488,7 @@ func TestInstallRelease_TillerVersion(t *testing.T) {
} }
func TestInstallRelease_WrongTillerVersion(t *testing.T) { func TestInstallRelease_WrongTillerVersion(t *testing.T) {
version.Version = "2.2.0"
c := helm.NewContext() c := helm.NewContext()
rs := rsFixture() rs := rsFixture()

@ -88,8 +88,8 @@ func versionFromContext(ctx context.Context) string {
func checkClientVersion(ctx context.Context) error { func checkClientVersion(ctx context.Context) error {
clientVersion := versionFromContext(ctx) clientVersion := versionFromContext(ctx)
if !version.IsCompatible(clientVersion, version.Version) { if !version.IsCompatible(clientVersion, version.GetVersion()) {
return fmt.Errorf("incompatible versions client: %s server: %s", clientVersion, version.Version) return fmt.Errorf("incompatible versions client[%s] server[%s]", clientVersion, version.GetVersion())
} }
return nil return nil
} }

@ -17,10 +17,10 @@ limitations under the License.
package urlutil package urlutil
import ( import (
"net"
"net/url" "net/url"
"path" "path"
"path/filepath" "path/filepath"
"strings"
) )
// URLJoin joins a base URL to one or more path components. // URLJoin joins a base URL to one or more path components.
@ -70,10 +70,18 @@ func ExtractHostname(addr string) (string, error) {
if err != nil { if err != nil {
return "", err return "", err
} }
return stripPort(u.Host), nil
}
host, _, err := net.SplitHostPort(u.Host) // Backported from Go 1.8 because Circle is still on 1.7
if err != nil { func stripPort(hostport string) string {
return "", err colon := strings.IndexByte(hostport, ':')
if colon == -1 {
return hostport
} }
return host, nil if i := strings.IndexByte(hostport, ']'); i != -1 {
return strings.TrimPrefix(hostport[:i], "[")
}
return hostport[:colon]
} }

@ -62,3 +62,16 @@ func TestEqual(t *testing.T) {
} }
} }
} }
func TestExtractHostname(t *testing.T) {
tests := map[string]string{
"http://example.com": "example.com",
"https://example.com/foo": "example.com",
"https://example.com:31337/not/with/a/bang/but/a/whimper": "example.com",
}
for start, expect := range tests {
if got, _ := ExtractHostname(start); got != expect {
t.Errorf("Got %q, expected %q", got, expect)
}
}
}

@ -18,12 +18,16 @@ package version // import "k8s.io/helm/pkg/version"
import ( import (
"fmt" "fmt"
"strings"
"github.com/Masterminds/semver" "github.com/Masterminds/semver"
) )
// IsCompatible tests if a client and server version are compatible. // IsCompatible tests if a client and server version are compatible.
func IsCompatible(client, server string) bool { func IsCompatible(client, server string) bool {
if isUnreleased(client) || isUnreleased(server) {
return true
}
cv, err := semver.NewVersion(client) cv, err := semver.NewVersion(client)
if err != nil { if err != nil {
return false return false
@ -55,3 +59,7 @@ func IsCompatibleRange(constraint, ver string) bool {
} }
return c.Check(sv) return c.Check(sv)
} }
func isUnreleased(v string) bool {
return strings.HasSuffix(v, "unreleased")
}

@ -26,10 +26,10 @@ var (
// Increment major number for new feature additions and behavioral changes. // Increment major number for new feature additions and behavioral changes.
// Increment minor number for bug fixes and performance enhancements. // Increment minor number for bug fixes and performance enhancements.
// Increment patch number for critical fixes to existing releases. // Increment patch number for critical fixes to existing releases.
Version = "v2.3.0" Version = "v2.4"
// BuildMetadata is extra build time data // BuildMetadata is extra build time data
BuildMetadata = "" BuildMetadata = "unreleased"
// GitCommit is the git sha1 // GitCommit is the git sha1
GitCommit = "" GitCommit = ""
// GitTreeState is the state of the git tree // GitTreeState is the state of the git tree

@ -1,137 +0,0 @@
apiVersion: v1
kind: ReplicationController
metadata:
name: kube-dns-v10
namespace: kube-system
labels:
k8s-app: kube-dns
version: v10
kubernetes.io/cluster-service: "true"
spec:
replicas: 1
selector:
k8s-app: kube-dns
version: v10
template:
metadata:
labels:
k8s-app: kube-dns
version: v10
kubernetes.io/cluster-service: "true"
spec:
containers:
- name: etcd
image: gcr.io/google_containers/etcd-amd64:2.2.1
resources:
# keep request = limit to keep this container in guaranteed class
limits:
cpu: 100m
memory: 50Mi
requests:
cpu: 100m
memory: 50Mi
command:
- /usr/local/bin/etcd
- -data-dir
- /var/etcd/data
- -listen-client-urls
- http://127.0.0.1:2379,http://127.0.0.1:4001
- -advertise-client-urls
- http://127.0.0.1:2379,http://127.0.0.1:4001
- -initial-cluster-token
- skydns-etcd
volumeMounts:
- name: etcd-storage
mountPath: /var/etcd/data
- name: kube2sky
image: gcr.io/google_containers/kube2sky:1.12
resources:
# keep request = limit to keep this container in guaranteed class
limits:
cpu: 100m
memory: 50Mi
requests:
cpu: 100m
memory: 50Mi
args:
# command = "/kube2sky"
- --domain=cluster.local
- name: skydns
image: gcr.io/google_containers/skydns:2015-10-13-8c72f8c
resources:
# keep request = limit to keep this container in guaranteed class
limits:
cpu: 100m
memory: 50Mi
requests:
cpu: 100m
memory: 50Mi
args:
# command = "/skydns"
- -machines=http://127.0.0.1:4001
- -addr=0.0.0.0:53
- -ns-rotate=false
- -domain=cluster.local.
ports:
- containerPort: 53
name: dns
protocol: UDP
- containerPort: 53
name: dns-tcp
protocol: TCP
livenessProbe:
httpGet:
path: /healthz
port: 8080
scheme: HTTP
initialDelaySeconds: 30
timeoutSeconds: 5
readinessProbe:
httpGet:
path: /healthz
port: 8080
scheme: HTTP
initialDelaySeconds: 1
timeoutSeconds: 5
- name: healthz
image: gcr.io/google_containers/exechealthz:1.0
resources:
# keep request = limit to keep this container in guaranteed class
limits:
cpu: 10m
memory: 20Mi
requests:
cpu: 10m
memory: 20Mi
args:
- -cmd=nslookup kubernetes.default.svc.cluster.local 127.0.0.1 >/dev/null
- -port=8080
ports:
- containerPort: 8080
protocol: TCP
volumes:
- name: etcd-storage
emptyDir: {}
dnsPolicy: Default # Don't use cluster DNS.
---
apiVersion: v1
kind: Service
metadata:
name: kube-dns
namespace: kube-system
labels:
k8s-app: kube-dns
kubernetes.io/cluster-service: "true"
kubernetes.io/name: "KubeDNS"
spec:
selector:
k8s-app: kube-dns
clusterIP: 10.0.0.10
ports:
- name: dns
port: 53
protocol: UDP
- name: dns-tcp
port: 53
protocol: TCP

@ -242,6 +242,8 @@ _helm_completion()
must_have_one_flag=() must_have_one_flag=()
must_have_one_noun=() must_have_one_noun=()
must_have_one_noun+=("bash")
must_have_one_noun+=("zsh")
noun_aliases=() noun_aliases=()
} }
@ -422,13 +424,21 @@ _helm_fetch()
flags_with_completion=() flags_with_completion=()
flags_completion=() flags_completion=()
flags+=("--ca-file=")
local_nonpersistent_flags+=("--ca-file=")
flags+=("--cert-file=")
local_nonpersistent_flags+=("--cert-file=")
flags+=("--destination=") flags+=("--destination=")
two_word_flags+=("-d") two_word_flags+=("-d")
local_nonpersistent_flags+=("--destination=") local_nonpersistent_flags+=("--destination=")
flags+=("--key-file=")
local_nonpersistent_flags+=("--key-file=")
flags+=("--keyring=") flags+=("--keyring=")
local_nonpersistent_flags+=("--keyring=") local_nonpersistent_flags+=("--keyring=")
flags+=("--prov") flags+=("--prov")
local_nonpersistent_flags+=("--prov") local_nonpersistent_flags+=("--prov")
flags+=("--repo=")
local_nonpersistent_flags+=("--repo=")
flags+=("--untar") flags+=("--untar")
local_nonpersistent_flags+=("--untar") local_nonpersistent_flags+=("--untar")
flags+=("--untardir=") flags+=("--untardir=")
@ -638,6 +648,8 @@ _helm_init()
local_nonpersistent_flags+=("--local-repo-url=") local_nonpersistent_flags+=("--local-repo-url=")
flags+=("--net-host") flags+=("--net-host")
local_nonpersistent_flags+=("--net-host") local_nonpersistent_flags+=("--net-host")
flags+=("--service-account=")
local_nonpersistent_flags+=("--service-account=")
flags+=("--skip-refresh") flags+=("--skip-refresh")
local_nonpersistent_flags+=("--skip-refresh") local_nonpersistent_flags+=("--skip-refresh")
flags+=("--stable-repo-url=") flags+=("--stable-repo-url=")
@ -679,8 +691,16 @@ _helm_inspect_chart()
flags_with_completion=() flags_with_completion=()
flags_completion=() flags_completion=()
flags+=("--ca-file=")
local_nonpersistent_flags+=("--ca-file=")
flags+=("--cert-file=")
local_nonpersistent_flags+=("--cert-file=")
flags+=("--key-file=")
local_nonpersistent_flags+=("--key-file=")
flags+=("--keyring=") flags+=("--keyring=")
local_nonpersistent_flags+=("--keyring=") local_nonpersistent_flags+=("--keyring=")
flags+=("--repo=")
local_nonpersistent_flags+=("--repo=")
flags+=("--verify") flags+=("--verify")
local_nonpersistent_flags+=("--verify") local_nonpersistent_flags+=("--verify")
flags+=("--version=") flags+=("--version=")
@ -707,8 +727,16 @@ _helm_inspect_values()
flags_with_completion=() flags_with_completion=()
flags_completion=() flags_completion=()
flags+=("--ca-file=")
local_nonpersistent_flags+=("--ca-file=")
flags+=("--cert-file=")
local_nonpersistent_flags+=("--cert-file=")
flags+=("--key-file=")
local_nonpersistent_flags+=("--key-file=")
flags+=("--keyring=") flags+=("--keyring=")
local_nonpersistent_flags+=("--keyring=") local_nonpersistent_flags+=("--keyring=")
flags+=("--repo=")
local_nonpersistent_flags+=("--repo=")
flags+=("--verify") flags+=("--verify")
local_nonpersistent_flags+=("--verify") local_nonpersistent_flags+=("--verify")
flags+=("--version=") flags+=("--version=")
@ -737,8 +765,16 @@ _helm_inspect()
flags_with_completion=() flags_with_completion=()
flags_completion=() flags_completion=()
flags+=("--ca-file=")
local_nonpersistent_flags+=("--ca-file=")
flags+=("--cert-file=")
local_nonpersistent_flags+=("--cert-file=")
flags+=("--key-file=")
local_nonpersistent_flags+=("--key-file=")
flags+=("--keyring=") flags+=("--keyring=")
local_nonpersistent_flags+=("--keyring=") local_nonpersistent_flags+=("--keyring=")
flags+=("--repo=")
local_nonpersistent_flags+=("--repo=")
flags+=("--verify") flags+=("--verify")
local_nonpersistent_flags+=("--verify") local_nonpersistent_flags+=("--verify")
flags+=("--version=") flags+=("--version=")
@ -765,8 +801,14 @@ _helm_install()
flags_with_completion=() flags_with_completion=()
flags_completion=() flags_completion=()
flags+=("--ca-file=")
local_nonpersistent_flags+=("--ca-file=")
flags+=("--cert-file=")
local_nonpersistent_flags+=("--cert-file=")
flags+=("--dry-run") flags+=("--dry-run")
local_nonpersistent_flags+=("--dry-run") local_nonpersistent_flags+=("--dry-run")
flags+=("--key-file=")
local_nonpersistent_flags+=("--key-file=")
flags+=("--keyring=") flags+=("--keyring=")
local_nonpersistent_flags+=("--keyring=") local_nonpersistent_flags+=("--keyring=")
flags+=("--name=") flags+=("--name=")
@ -780,6 +822,8 @@ _helm_install()
local_nonpersistent_flags+=("--no-hooks") local_nonpersistent_flags+=("--no-hooks")
flags+=("--replace") flags+=("--replace")
local_nonpersistent_flags+=("--replace") local_nonpersistent_flags+=("--replace")
flags+=("--repo=")
local_nonpersistent_flags+=("--repo=")
flags+=("--set=") flags+=("--set=")
local_nonpersistent_flags+=("--set=") local_nonpersistent_flags+=("--set=")
flags+=("--timeout=") flags+=("--timeout=")
@ -1392,6 +1436,10 @@ _helm_upgrade()
flags_with_completion=() flags_with_completion=()
flags_completion=() flags_completion=()
flags+=("--ca-file=")
local_nonpersistent_flags+=("--ca-file=")
flags+=("--cert-file=")
local_nonpersistent_flags+=("--cert-file=")
flags+=("--disable-hooks") flags+=("--disable-hooks")
local_nonpersistent_flags+=("--disable-hooks") local_nonpersistent_flags+=("--disable-hooks")
flags+=("--dry-run") flags+=("--dry-run")
@ -1399,6 +1447,8 @@ _helm_upgrade()
flags+=("--install") flags+=("--install")
flags+=("-i") flags+=("-i")
local_nonpersistent_flags+=("--install") local_nonpersistent_flags+=("--install")
flags+=("--key-file=")
local_nonpersistent_flags+=("--key-file=")
flags+=("--keyring=") flags+=("--keyring=")
local_nonpersistent_flags+=("--keyring=") local_nonpersistent_flags+=("--keyring=")
flags+=("--namespace=") flags+=("--namespace=")
@ -1407,6 +1457,8 @@ _helm_upgrade()
local_nonpersistent_flags+=("--no-hooks") local_nonpersistent_flags+=("--no-hooks")
flags+=("--recreate-pods") flags+=("--recreate-pods")
local_nonpersistent_flags+=("--recreate-pods") local_nonpersistent_flags+=("--recreate-pods")
flags+=("--repo=")
local_nonpersistent_flags+=("--repo=")
flags+=("--reset-values") flags+=("--reset-values")
local_nonpersistent_flags+=("--reset-values") local_nonpersistent_flags+=("--reset-values")
flags+=("--reuse-values") flags+=("--reuse-values")

@ -1,358 +0,0 @@
#!/usr/bin/env bash
# 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.
# Bash 'Strict Mode'
# http://redsymbol.net/articles/unofficial-bash-strict-mode
set -euo pipefail
IFS=$'\n\t'
HELM_ROOT="${BASH_SOURCE[0]%/*}/.."
cd "$HELM_ROOT"
# Globals ----------------------------------------------------------------------
KUBE_VERSION=${KUBE_VERSION:-}
KUBE_PORT=${KUBE_PORT:-8080}
KUBE_CONTEXT=${KUBE_CONTEXT:-docker}
KUBECTL=${KUBECTL:-kubectl}
ENABLE_CLUSTER_DNS=${KUBE_ENABLE_CLUSTER_DNS:-true}
LOG_LEVEL=${LOG_LEVEL:-2}
# Helper Functions -------------------------------------------------------------
# Display error message and exit
error_exit() {
echo "error: ${1:-"unknown error"}" 1>&2
exit 1
}
# Checks if a command exists. Returns 1 or 0
command_exists() {
hash "${1}" 2>/dev/null
}
# fetch url using wget or curl and print to stdout
fetch_url() {
local url="$1"
if command_exists wget; then
curl -sSL "$url"
elif command_exists curl; then
wget -qO- "$url"
else
error_exit "Couldn't find curl or wget. Bailing out."
fi
}
# Program Functions ------------------------------------------------------------
# Check host platform and docker host
verify_prereqs() {
echo "Verifying Prerequisites...."
case "$(uname -s)" in
Darwin)
host_os=darwin
;;
Linux)
host_os=linux
;;
*)
error_exit "Unsupported host OS. Must be Linux or Mac OS X."
;;
esac
case "$(uname -m)" in
x86_64*)
host_arch=amd64
;;
i?86_64*)
host_arch=amd64
;;
amd64*)
host_arch=amd64
;;
arm*)
host_arch=arm
;;
i?86*)
host_arch=x86
;;
s390x*)
host_arch=s390x
;;
ppc64le*)
host_arch=ppc64le
;;
*)
error_exit "Unsupported host arch. Must be x86_64, 386, arm, s390x or ppc64le."
;;
esac
command_exists docker || error_exit "You need docker"
if ! docker info >/dev/null 2>&1 ; then
error_exit "Can't connect to 'docker' daemon."
fi
if docker inspect kubelet >/dev/null 2>&1 ; then
error_exit "Kubernetes is already running"
fi
$KUBECTL version --client >/dev/null || download_kubectl
}
# Get the latest stable release tag
get_latest_version_number() {
local channel="stable"
if [[ -n "${ALPHA:-}" ]]; then
channel="latest"
fi
local latest_url="https://storage.googleapis.com/kubernetes-release/release/${channel}.txt"
fetch_url "$latest_url"
}
# Detect ip address od docker host
detect_docker_host_ip() {
if [[ -n "${DOCKER_HOST:-}" ]]; then
awk -F'[/:]' '{print $4}' <<< "$DOCKER_HOST"
else
ifconfig docker0 \
| grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' \
| grep -Eo '([0-9]*\.){3}[0-9]*' >/dev/null 2>&1 || :
fi
}
# Set KUBE_MASTER_IP from docker host ip. Defaults to localhost
set_master_ip() {
local docker_ip
if [[ -z "${KUBE_MASTER_IP:-}" ]]; then
docker_ip=$(detect_docker_host_ip)
if [[ -n "${docker_ip}" ]]; then
KUBE_MASTER_IP="${docker_ip}"
else
KUBE_MASTER_IP=localhost
fi
fi
}
# Start dockerized kubelet
start_kubernetes() {
echo "Starting kubelet"
# Enable dns
if [[ "${ENABLE_CLUSTER_DNS}" = true ]]; then
dns_args="--cluster-dns=10.0.0.10 --cluster-domain=cluster.local"
else
# DNS server for real world hostnames.
dns_args="--cluster-dns=8.8.8.8"
fi
local start_time=$(date +%s)
docker run \
--name=kubelet \
--volume=/:/rootfs:ro \
--volume=/sys:/sys:ro \
--volume=/var/lib/docker/:/var/lib/docker:rw \
--volume=/var/lib/kubelet/:/var/lib/kubelet:rw,rslave \
--volume=/var/run:/var/run:rw \
--net=host \
--pid=host \
--privileged=true \
-d \
gcr.io/google_containers/hyperkube-amd64:${KUBE_VERSION} \
/hyperkube kubelet \
--containerized \
--hostname-override="127.0.0.1" \
--api-servers=http://localhost:${KUBE_PORT} \
--config=/etc/kubernetes/manifests \
--allow-privileged=true \
${dns_args} \
--v=${LOG_LEVEL} >/dev/null
until $KUBECTL cluster-info &> /dev/null; do
sleep 1
done
if [[ $KUBE_VERSION == "1.2"* ]]; then
create_kube_system_namespace
create_kube_dns
fi
# We expect to have at least 3 running pods - etcd, master and kube-proxy.
local attempt=1
while (($(KUBECTL get pods --all-namespaces --no-headers 2>/dev/null | grep -c "Running") < 3)); do
echo -n "."
sleep $(( attempt++ ))
done
echo
echo "Started master components in $(($(date +%s) - start_time)) seconds."
}
# Open kubernetes master api port.
setup_firewall() {
[[ -n "${DOCKER_MACHINE_NAME:-}" ]] || return
echo "Adding iptables hackery for docker-machine..."
local machine_ip
machine_ip=$(docker-machine ip "$DOCKER_MACHINE_NAME")
local iptables_rule="PREROUTING -p tcp -d ${machine_ip} --dport ${KUBE_PORT} -j DNAT --to-destination 127.0.0.1:${KUBE_PORT}"
if ! docker-machine ssh "${DOCKER_MACHINE_NAME}" "sudo /usr/local/sbin/iptables -t nat -C ${iptables_rule}" &> /dev/null; then
docker-machine ssh "${DOCKER_MACHINE_NAME}" "sudo /usr/local/sbin/iptables -t nat -I ${iptables_rule}"
fi
}
# Create kube-system namespace in kubernetes
create_kube_system_namespace() {
$KUBECTL create namespace kube-system >/dev/null
}
# Activate skydns in kubernetes and wait for pods to be ready.
create_kube_dns() {
[[ "${ENABLE_CLUSTER_DNS}" = true ]] || return
local start_time=$(date +%s)
echo "Setting up cluster dns..."
$KUBECTL create -f ./scripts/cluster/skydns.yaml >/dev/null
echo "Waiting for cluster DNS to become available..."
local attempt=1
until $KUBECTL get pods --no-headers --namespace kube-system --selector=k8s-app=kube-dns 2>/dev/null | grep "Running" &>/dev/null; do
echo -n "."
sleep $(( attempt++ ))
done
echo
echo "Started DNS in $(($(date +%s) - start_time)) seconds."
}
# Generate kubeconfig data for the created cluster.
generate_kubeconfig() {
local cluster_args=(
"--server=http://${KUBE_MASTER_IP}:${KUBE_PORT}"
"--insecure-skip-tls-verify=true"
)
$KUBECTL config set-cluster "${KUBE_CONTEXT}" "${cluster_args[@]}" >/dev/null
$KUBECTL config set-context "${KUBE_CONTEXT}" --cluster="${KUBE_CONTEXT}" >/dev/null
$KUBECTL config use-context "${KUBE_CONTEXT}" >/dev/null
echo "Wrote config for kubeconfig using context: '${KUBE_CONTEXT}'"
}
# Download kubectl
download_kubectl() {
echo "Downloading kubectl binary..."
local output="/usr/local/bin/kubectl"
kubectl_url="https://storage.googleapis.com/kubernetes-release/release/${KUBE_VERSION}/bin/${host_os}/${host_arch}/kubectl"
fetch_url "${kubectl_url}" > "${output}"
chmod a+x "${output}"
KUBECTL="${output}"
}
# Clean volumes that are left by kubelet
#
# https://github.com/kubernetes/kubernetes/issues/23197
# code stolen from https://github.com/huggsboson/docker-compose-kubernetes/blob/SwitchToSharedMount/kube-up.sh
clean_volumes() {
if [[ -n "${DOCKER_MACHINE_NAME:-}" ]]; then
docker-machine ssh "${DOCKER_MACHINE_NAME}" "mount | grep -o 'on /var/lib/kubelet.* type' | cut -c 4- | rev | cut -c 6- | rev | sort -r | xargs --no-run-if-empty sudo umount"
docker-machine ssh "${DOCKER_MACHINE_NAME}" "sudo rm -Rf /var/lib/kubelet"
docker-machine ssh "${DOCKER_MACHINE_NAME}" "sudo mkdir -p /var/lib/kubelet"
docker-machine ssh "${DOCKER_MACHINE_NAME}" "sudo mount --bind /var/lib/kubelet /var/lib/kubelet"
docker-machine ssh "${DOCKER_MACHINE_NAME}" "sudo mount --make-shared /var/lib/kubelet"
else
mount | grep -o 'on /var/lib/kubelet.* type' | cut -c 4- | rev | cut -c 6- | rev | sort -r | xargs --no-run-if-empty sudo umount
sudo rm -Rf /var/lib/kubelet
sudo mkdir -p /var/lib/kubelet
sudo mount --bind /var/lib/kubelet /var/lib/kubelet
sudo mount --make-shared /var/lib/kubelet
fi
}
# Helper function to properly remove containers
delete_container() {
local container=("$@")
docker stop "${container[@]}" &>/dev/null || :
docker wait "${container[@]}" &>/dev/null || :
docker rm --force --volumes "${container[@]}" &>/dev/null || :
}
# Delete master components and resources in kubernetes.
kube_down() {
echo "Deleting all resources in kubernetes..."
$KUBECTL delete replicationcontrollers,services,pods,secrets --all >/dev/null 2>&1 || :
$KUBECTL delete replicationcontrollers,services,pods,secrets --all --namespace=kube-system >/dev/null 2>&1 || :
$KUBECTL delete namespace kube-system >/dev/null 2>&1 || :
echo "Stopping kubelet..."
delete_container kubelet
echo "Stopping remaining kubernetes containers..."
local kube_containers=($(docker ps -aqf "name=k8s_"))
if [[ "${#kube_containers[@]}" -gt 0 ]]; then
delete_container "${kube_containers[@]}"
fi
}
# Start a kubernetes cluster in docker.
kube_up() {
verify_prereqs
set_master_ip
clean_volumes
setup_firewall
generate_kubeconfig
start_kubernetes
$KUBECTL cluster-info
}
KUBE_VERSION=${KUBE_VERSION:-$(get_latest_version_number)}
# Main -------------------------------------------------------------------------
main() {
case "$1" in
up|start)
kube_up
;;
down|stop)
kube_down
;;
restart)
kube_down
kube_up
;;
*)
echo "Usage: $0 {up|down|restart}"
;;
esac
}
main "${@:-}"

@ -1,9 +1,9 @@
MUTABLE_VERSION ?= canary MUTABLE_VERSION := canary
GIT_COMMIT ?= $(shell git rev-parse HEAD) GIT_COMMIT = $(shell git rev-parse HEAD)
GIT_SHA ?= $(shell git rev-parse --short HEAD) GIT_SHA = $(shell git rev-parse --short HEAD)
GIT_TAG ?= $(shell git describe --tags --abbrev=0 2>/dev/null) GIT_TAG = $(shell git describe --tags --abbrev=0 --exact-match 2>/dev/null)
GIT_DIRTY ?= $(shell test -n "`git status --porcelain`" && echo "dirty" || echo "clean") GIT_DIRTY = $(shell test -n "`git status --porcelain`" && echo "dirty" || echo "clean")
ifdef VERSION ifdef VERSION
DOCKER_VERSION = $(VERSION) DOCKER_VERSION = $(VERSION)
@ -11,25 +11,38 @@ ifdef VERSION
endif endif
DOCKER_VERSION ?= git-${GIT_SHA} DOCKER_VERSION ?= git-${GIT_SHA}
BINARY_VERSION ?= ${GIT_TAG}-${GIT_SHA} BINARY_VERSION ?= ${GIT_TAG}
IMAGE := ${DOCKER_REGISTRY}/${IMAGE_PREFIX}/${SHORT_NAME}:${DOCKER_VERSION} # Only set Version if building a tag or VERSION is set
MUTABLE_IMAGE := ${DOCKER_REGISTRY}/${IMAGE_PREFIX}/${SHORT_NAME}:${MUTABLE_VERSION} ifneq ($(BINARY_VERSION),)
LDFLAGS += -X k8s.io/helm/pkg/version.Version=${BINARY_VERSION}
endif
# Clear the "unreleased" string in BuildMetadata
ifneq ($(GIT_TAG),)
LDFLAGS += -X k8s.io/helm/pkg/version.BuildMetadata=
endif
LDFLAGS += -X k8s.io/helm/pkg/version.Version=${GIT_TAG}
LDFLAGS += -X k8s.io/helm/pkg/version.GitCommit=${GIT_COMMIT} LDFLAGS += -X k8s.io/helm/pkg/version.GitCommit=${GIT_COMMIT}
LDFLAGS += -X k8s.io/helm/pkg/version.GitTreeState=${GIT_DIRTY} LDFLAGS += -X k8s.io/helm/pkg/version.GitTreeState=${GIT_DIRTY}
IMAGE := ${DOCKER_REGISTRY}/${IMAGE_PREFIX}/${SHORT_NAME}:${DOCKER_VERSION}
MUTABLE_IMAGE := ${DOCKER_REGISTRY}/${IMAGE_PREFIX}/${SHORT_NAME}:${MUTABLE_VERSION}
DOCKER_PUSH = docker push DOCKER_PUSH = docker push
ifeq ($(DOCKER_REGISTRY),gcr.io) ifeq ($(DOCKER_REGISTRY),gcr.io)
DOCKER_PUSH = gcloud docker push DOCKER_PUSH = gcloud docker push
endif endif
info: info:
@echo "Build tag: ${DOCKER_VERSION}" @echo "Version: ${VERSION}"
@echo "Registry: ${DOCKER_REGISTRY}" @echo "Git Tag: ${GIT_TAG}"
@echo "Immutable tag: ${IMAGE}" @echo "Git Commit: ${GIT_COMMIT}"
@echo "Mutable tag: ${MUTABLE_IMAGE}" @echo "Git Tree State: ${GIT_DIRTY}"
@echo "Docker Version: ${DOCKER_VERSION}"
@echo "Registry: ${DOCKER_REGISTRY}"
@echo "Immutable Image: ${IMAGE}"
@echo "Mutable Image: ${MUTABLE_IMAGE}"
.PHONY: docker-push .PHONY: docker-push
docker-push: docker-mutable-push docker-immutable-push docker-push: docker-mutable-push docker-immutable-push

Loading…
Cancel
Save