Merge remote-tracking branch 'upstream/master'

pull/2862/head
Ryan Payton 8 years ago
commit 3cb4a38a72

@ -10,16 +10,28 @@ jobs:
steps:
- checkout
- setup_remote_docker
- restore_cache:
keys:
- glide-{{ checksum "glide.yaml" }}-{{ checksum "glide.lock" }}
- glide- # used as a fall through if the checksum fails to find exact entry
- run:
name: install dependencies
command: make bootstrap
- save_cache:
key: vendor-{{ checksum "glide.yaml" }}-{{ checksum "glide.lock" }}
key: glide-{{ checksum "glide.yaml" }}-{{ checksum "glide.lock" }}
paths:
- vendor
- /root/.glide # Where the glide cache is stored
- run:
name: test
command: .circleci/test.sh
- deploy:
name: deploy
command: .circleci/deploy.sh
workflows:
version: 2
build:
jobs:
- build:
filters:
tags:
only: /.*/

@ -2,7 +2,7 @@ DOCKER_REGISTRY ?= gcr.io
IMAGE_PREFIX ?= kubernetes-helm
SHORT_NAME ?= tiller
SHORT_NAME_RUDDER ?= rudder
TARGETS = darwin/amd64 linux/amd64 linux/386 linux/arm linux/arm64 linux/ppc64le windows/amd64
TARGETS ?= darwin/amd64 linux/amd64 linux/386 linux/arm linux/arm64 linux/ppc64le windows/amd64
DIST_DIRS = find * -type d -exec
APP = helm

@ -7,7 +7,7 @@
Helm is a tool for managing Kubernetes charts. Charts are packages of
pre-configured Kubernetes resources.
Use Helm to...
Use Helm to:
- Find and use [popular software packaged as Kubernetes charts](https://github.com/kubernetes/charts)
- Share your own applications as Kubernetes charts
@ -34,10 +34,10 @@ Think of it like apt/yum/homebrew for Kubernetes.
Binary downloads of the Helm client can be found at the following links:
- [OSX](https://kubernetes-helm.storage.googleapis.com/helm-v2.6.2-darwin-amd64.tar.gz)
- [Linux](https://kubernetes-helm.storage.googleapis.com/helm-v2.6.2-linux-amd64.tar.gz)
- [Linux 32-bit](https://kubernetes-helm.storage.googleapis.com/helm-v2.6.2-linux-386.tar.gz)
- [Windows](https://kubernetes-helm.storage.googleapis.com/helm-v2.6.2-windows-amd64.tar.gz)
- [OSX](https://kubernetes-helm.storage.googleapis.com/helm-v2.7.2-darwin-amd64.tar.gz)
- [Linux](https://kubernetes-helm.storage.googleapis.com/helm-v2.7.2-linux-amd64.tar.gz)
- [Linux 32-bit](https://kubernetes-helm.storage.googleapis.com/helm-v2.7.2-linux-386.tar.gz)
- [Windows](https://kubernetes-helm.storage.googleapis.com/helm-v2.7.2-windows-amd64.tar.gz)
Unpack the `helm` binary and add it to your PATH and you are good to go!
macOS/[homebrew](https://brew.sh/) users can also use `brew install kubernetes-helm`.

@ -25,6 +25,9 @@ message Maintainer {
// Email is an optional email address to contact the named maintainer
string email = 2;
// Url is an optional URL to an address for the named maintainer
string url = 3;
}
// Metadata for a Chart file. This models the structure of a Chart.yaml file.

@ -23,6 +23,7 @@ import (
"github.com/spf13/cobra"
"k8s.io/helm/pkg/helm"
"k8s.io/helm/pkg/proto/hapi/release"
)
func TestDelete(t *testing.T) {
@ -33,28 +34,32 @@ func TestDelete(t *testing.T) {
args: []string{"aeneas"},
flags: []string{},
expected: "", // Output of a delete is an empty string and exit 0.
resp: releaseMock(&releaseOptions{name: "aeneas"}),
resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"}),
rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"})},
},
{
name: "delete with timeout",
args: []string{"aeneas"},
flags: []string{"--timeout", "120"},
expected: "",
resp: releaseMock(&releaseOptions{name: "aeneas"}),
resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"}),
rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"})},
},
{
name: "delete without hooks",
args: []string{"aeneas"},
flags: []string{"--no-hooks"},
expected: "",
resp: releaseMock(&releaseOptions{name: "aeneas"}),
resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"}),
rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"})},
},
{
name: "purge",
args: []string{"aeneas"},
flags: []string{"--purge"},
expected: "",
resp: releaseMock(&releaseOptions{name: "aeneas"}),
resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"}),
rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"})},
},
{
name: "delete without release",

@ -79,8 +79,8 @@ func newFetchCmd(out io.Writer) *cobra.Command {
}
if fch.version == "" && fch.devel {
debug("setting version to >0.0.0-a")
fch.version = ">0.0.0-a"
debug("setting version to >0.0.0-0")
fch.version = ">0.0.0-0"
}
for i := 0; i < len(args); i++ {
@ -105,7 +105,7 @@ func newFetchCmd(out io.Writer) *cobra.Command {
f.StringVar(&fch.certFile, "cert-file", "", "identify HTTPS client using this SSL certificate file")
f.StringVar(&fch.keyFile, "key-file", "", "identify HTTPS client using this SSL key file")
f.StringVar(&fch.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")
f.BoolVar(&fch.devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-a'. If --version is set, this is ignored.")
f.BoolVar(&fch.devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored.")
return cmd
}

@ -64,7 +64,7 @@ func newGetCmd(client helm.Interface, out io.Writer) *cobra.Command {
}
get.release = args[0]
if get.client == nil {
get.client = helm.NewClient(helm.Host(settings.TillerHost))
get.client = newClient()
}
return get.run()
},
@ -72,9 +72,9 @@ func newGetCmd(client helm.Interface, out io.Writer) *cobra.Command {
cmd.Flags().Int32Var(&get.version, "revision", 0, "get the named release with revision")
cmd.AddCommand(newGetValuesCmd(nil, out))
cmd.AddCommand(newGetManifestCmd(nil, out))
cmd.AddCommand(newGetHooksCmd(nil, out))
cmd.AddCommand(addFlagsTLS(newGetValuesCmd(nil, out)))
cmd.AddCommand(addFlagsTLS(newGetManifestCmd(nil, out)))
cmd.AddCommand(addFlagsTLS(newGetHooksCmd(nil, out)))
return cmd
}

@ -23,6 +23,7 @@ import (
"github.com/spf13/cobra"
"k8s.io/helm/pkg/helm"
"k8s.io/helm/pkg/proto/hapi/release"
)
func TestGetHooks(t *testing.T) {
@ -30,8 +31,9 @@ func TestGetHooks(t *testing.T) {
{
name: "get hooks with release",
args: []string{"aeneas"},
expected: mockHookTemplate,
resp: releaseMock(&releaseOptions{name: "aeneas"}),
expected: helm.MockHookTemplate,
resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"}),
rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"})},
},
{
name: "get hooks without args",

@ -23,6 +23,7 @@ import (
"github.com/spf13/cobra"
"k8s.io/helm/pkg/helm"
"k8s.io/helm/pkg/proto/hapi/release"
)
func TestGetManifest(t *testing.T) {
@ -30,8 +31,9 @@ func TestGetManifest(t *testing.T) {
{
name: "get manifest with release",
args: []string{"juno"},
expected: mockManifest,
resp: releaseMock(&releaseOptions{name: "juno"}),
expected: helm.MockManifest,
resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "juno"}),
rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "juno"})},
},
{
name: "get manifest without args",

@ -23,15 +23,17 @@ import (
"github.com/spf13/cobra"
"k8s.io/helm/pkg/helm"
"k8s.io/helm/pkg/proto/hapi/release"
)
func TestGetCmd(t *testing.T) {
tests := []releaseCase{
{
name: "get with a release",
resp: releaseMock(&releaseOptions{name: "thomas-guide"}),
resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide"}),
args: []string{"thomas-guide"},
expected: "REVISION: 1\nRELEASED: (.*)\nCHART: foo-0.1.0-beta.1\nUSER-SUPPLIED VALUES:\nname: \"value\"\nCOMPUTED VALUES:\nname: value\n\nHOOKS:\n---\n# pre-install-hook\n" + mockHookTemplate + "\nMANIFEST:",
expected: "REVISION: 1\nRELEASED: (.*)\nCHART: foo-0.1.0-beta.1\nUSER-SUPPLIED VALUES:\nname: \"value\"\nCOMPUTED VALUES:\nname: value\n\nHOOKS:\n---\n# pre-install-hook\n" + helm.MockHookTemplate + "\nMANIFEST:",
rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide"})},
},
{
name: "get requires release name arg",

@ -23,15 +23,17 @@ import (
"github.com/spf13/cobra"
"k8s.io/helm/pkg/helm"
"k8s.io/helm/pkg/proto/hapi/release"
)
func TestGetValuesCmd(t *testing.T) {
tests := []releaseCase{
{
name: "get values with a release",
resp: releaseMock(&releaseOptions{name: "thomas-guide"}),
resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide"}),
args: []string{"thomas-guide"},
expected: "name: \"value\"",
rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide"})},
},
{
name: "get values requires release name arg",

@ -45,6 +45,10 @@ var (
tlsVerify bool // enable TLS and verify remote certificates
tlsEnable bool // enable TLS
tlsCaCertDefault = "$HELM_HOME/ca.pem"
tlsCertDefault = "$HELM_HOME/cert.pem"
tlsKeyDefault = "$HELM_HOME/key.pem"
tillerTunnel *kube.Tunnel
settings helm_env.EnvSettings
)
@ -174,7 +178,7 @@ func setupConnection(c *cobra.Command, args []string) error {
return err
}
settings.TillerHost = fmt.Sprintf("localhost:%d", tunnel.Local)
settings.TillerHost = fmt.Sprintf("127.0.0.1:%d", tunnel.Local)
debug("Created tunnel using local port: '%d'\n", tunnel.Local)
}
@ -216,7 +220,7 @@ func prettyError(err error) error {
// configForContext creates a Kubernetes REST client configuration for a given kubeconfig context.
func configForContext(context string) (*rest.Config, error) {
config, err := kube.GetConfig(context).ClientConfig()
config, err := kube.GetConfig(context, settings.KubeConfig).ClientConfig()
if err != nil {
return nil, fmt.Errorf("could not get Kubernetes config for context %q: %s", context, err)
}
@ -239,16 +243,16 @@ func getKubeClient(context string) (*rest.Config, kubernetes.Interface, error) {
// getInternalKubeClient creates a Kubernetes config and an "internal" client for a given kubeconfig context.
//
// Prefer the similar getKubeClient if you don't need to use such an internal client.
func getInternalKubeClient(context string) (*rest.Config, internalclientset.Interface, error) {
func getInternalKubeClient(context string) (internalclientset.Interface, error) {
config, err := configForContext(context)
if err != nil {
return nil, nil, err
return nil, err
}
client, err := internalclientset.NewForConfig(config)
if err != nil {
return nil, nil, fmt.Errorf("could not get Kubernetes client: %s", err)
return nil, fmt.Errorf("could not get Kubernetes client: %s", err)
}
return config, client, nil
return client, nil
}
// ensureHelmClient returns a new helm client impl. if h is not nil.
@ -263,6 +267,16 @@ func newClient() helm.Interface {
options := []helm.Option{helm.Host(settings.TillerHost)}
if tlsVerify || tlsEnable {
if tlsCaCertFile == "" {
tlsCaCertFile = settings.Home.TLSCaCert()
}
if tlsCertFile == "" {
tlsCertFile = settings.Home.TLSCert()
}
if tlsKeyFile == "" {
tlsKeyFile = settings.Home.TLSKey()
}
debug("Key=%q, Cert=%q, CA=%q\n", tlsKeyFile, tlsCertFile, tlsCaCertFile)
tlsopts := tlsutil.Options{KeyFile: tlsKeyFile, CertFile: tlsCertFile, InsecureSkipVerify: true}
if tlsVerify {
tlsopts.CaCertFile = tlsCaCertFile
@ -281,12 +295,6 @@ func newClient() helm.Interface {
// addFlagsTLS adds the flags for supporting client side TLS to the
// helm command (only those that invoke communicate to Tiller.)
func addFlagsTLS(cmd *cobra.Command) *cobra.Command {
// defaults
var (
tlsCaCertDefault = "$HELM_HOME/ca.pem"
tlsCertDefault = "$HELM_HOME/cert.pem"
tlsKeyDefault = "$HELM_HOME/key.pem"
)
// add flags
cmd.Flags().StringVar(&tlsCaCertFile, "tls-ca-cert", tlsCaCertDefault, "path to TLS CA certificate file")

@ -21,115 +21,30 @@ import (
"fmt"
"io"
"io/ioutil"
"math/rand"
"os"
"path/filepath"
"regexp"
"strings"
"testing"
"github.com/golang/protobuf/ptypes/timestamp"
"github.com/spf13/cobra"
"k8s.io/helm/pkg/helm"
"k8s.io/helm/pkg/helm/helmpath"
"k8s.io/helm/pkg/proto/hapi/chart"
"k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/helm/pkg/repo"
)
var mockHookTemplate = `apiVersion: v1
kind: Job
metadata:
annotations:
"helm.sh/hooks": pre-install
`
var mockManifest = `apiVersion: v1
kind: Secret
metadata:
name: fixture
`
type releaseOptions struct {
name string
version int32
chart *chart.Chart
statusCode release.Status_Code
namespace string
}
func releaseMock(opts *releaseOptions) *release.Release {
date := timestamp.Timestamp{Seconds: 242085845, Nanos: 0}
name := opts.name
if name == "" {
name = "testrelease-" + string(rand.Intn(100))
}
var version int32 = 1
if opts.version != 0 {
version = opts.version
}
namespace := opts.namespace
if namespace == "" {
namespace = "default"
}
ch := opts.chart
if opts.chart == nil {
ch = &chart.Chart{
Metadata: &chart.Metadata{
Name: "foo",
Version: "0.1.0-beta.1",
},
Templates: []*chart.Template{
{Name: "templates/foo.tpl", Data: []byte(mockManifest)},
},
}
}
scode := release.Status_DEPLOYED
if opts.statusCode > 0 {
scode = opts.statusCode
}
return &release.Release{
Name: name,
Info: &release.Info{
FirstDeployed: &date,
LastDeployed: &date,
Status: &release.Status{Code: scode},
Description: "Release mock",
},
Chart: ch,
Config: &chart.Config{Raw: `name: "value"`},
Version: version,
Namespace: namespace,
Hooks: []*release.Hook{
{
Name: "pre-install-hook",
Kind: "Job",
Path: "pre-install-hook.yaml",
Manifest: mockHookTemplate,
LastRun: &date,
Events: []release.Hook_Event{release.Hook_PRE_INSTALL},
},
},
Manifest: mockManifest,
}
}
// releaseCmd is a command that works with a FakeClient
type releaseCmd func(c *helm.FakeClient, out io.Writer) *cobra.Command
// runReleaseCases runs a set of release cases through the given releaseCmd.
func runReleaseCases(t *testing.T, tests []releaseCase, rcmd releaseCmd) {
var buf bytes.Buffer
for _, tt := range tests {
c := &helm.FakeClient{
Rels: []*release.Release{tt.resp},
Rels: tt.rels,
}
cmd := rcmd(c, &buf)
cmd.ParseFlags(tt.flags)
@ -154,6 +69,8 @@ type releaseCase struct {
expected string
err bool
resp *release.Release
// Rels are the available releases at the start of the test.
rels []*release.Release
}
// tempHelmHome sets up a Helm Home in a temp dir.
@ -230,6 +147,7 @@ func ensureTestHome(home helmpath.Home, t *testing.T) error {
t.Logf("$HELM_HOME has been configured at %s.\n", settings.Home.String())
return nil
}
func TestRootCmd(t *testing.T) {

@ -66,7 +66,7 @@ func newHistoryCmd(c helm.Interface, w io.Writer) *cobra.Command {
case len(args) == 0:
return errReleaseRequired
case his.helmc == nil:
his.helmc = helm.NewClient(helm.Host(settings.TillerHost))
his.helmc = newClient()
}
his.rls = args[0]
return his.run()

@ -27,10 +27,10 @@ import (
func TestHistoryCmd(t *testing.T) {
mk := func(name string, vers int32, code rpb.Status_Code) *rpb.Release {
return releaseMock(&releaseOptions{
name: name,
version: vers,
statusCode: code,
return helm.ReleaseMock(&helm.MockReleaseOptions{
Name: name,
Version: vers,
StatusCode: code,
})
}

@ -17,6 +17,8 @@ limitations under the License.
package main
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
@ -27,6 +29,7 @@ import (
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/client-go/kubernetes"
"k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/helm/cmd/helm/installer"
"k8s.io/helm/pkg/getter"
"k8s.io/helm/pkg/helm/helmpath"
@ -121,6 +124,10 @@ func newInitCmd(out io.Writer) *cobra.Command {
f.StringVar(&i.serviceAccount, "service-account", "", "name of service account")
f.IntVar(&i.maxHistory, "history-max", 0, "limit the maximum number of revisions saved per release. Use 0 for no limit.")
f.StringVar(&i.opts.NodeSelectors, "node-selectors", "", "labels to specify the node on which Tiller is installed (app=tiller,helm=rocks)")
f.VarP(&i.opts.Output, "output", "o", "skip installation and output Tiller's manifest in specified format (json or yaml)")
f.StringArrayVar(&i.opts.Values, "override", []string{}, "override values for the Tiller Deployment manifest (can specify multiple or separate values with commas: key1=val1,key2=val2)")
return cmd
}
@ -161,7 +168,6 @@ func (i *initCmd) run() error {
i.opts.ServiceAccount = i.serviceAccount
i.opts.MaxHistory = i.maxHistory
if settings.Debug {
writeYAMLManifest := func(apiVersion, kind, body string, first, last bool) error {
w := i.out
if !first {
@ -186,6 +192,42 @@ func (i *initCmd) run() error {
_, err := fmt.Fprintln(w, "...")
return err
}
if len(i.opts.Output) > 0 {
var body string
var err error
const tm = `{"apiVersion":"extensions/v1beta1","kind":"Deployment",`
if body, err = installer.DeploymentManifest(&i.opts); err != nil {
return err
}
switch i.opts.Output.String() {
case "json":
var out bytes.Buffer
jsonb, err := yaml.ToJSON([]byte(body))
if err != nil {
return err
}
buf := bytes.NewBuffer(make([]byte, 0, len(tm)+len(jsonb)-1))
buf.WriteString(tm)
// Drop the opening object delimiter ('{').
buf.Write(jsonb[1:])
if err := json.Indent(&out, buf.Bytes(), "", " "); err != nil {
return err
}
if _, err = i.out.Write(out.Bytes()); err != nil {
return err
}
return nil
case "yaml":
if err := writeYAMLManifest("extensions/v1beta1", "Deployment", body, true, false); err != nil {
return err
}
return nil
default:
return fmt.Errorf("unknown output format: %q", i.opts.Output)
}
}
if settings.Debug {
var body string
var err error

@ -27,14 +27,16 @@ import (
"github.com/ghodss/yaml"
"k8s.io/api/core/v1"
"k8s.io/api/extensions/v1beta1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes/fake"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/pkg/apis/extensions/v1beta1"
testcore "k8s.io/client-go/testing"
"encoding/json"
"k8s.io/helm/cmd/helm/installer"
"k8s.io/helm/pkg/helm/helmpath"
)
@ -303,3 +305,53 @@ func TestInitCmd_tlsOptions(t *testing.T) {
}
}
}
// TestInitCmd_output tests that init -o formats are unmarshal-able
func TestInitCmd_output(t *testing.T) {
// This is purely defensive in this case.
home, err := ioutil.TempDir("", "helm_home")
if err != nil {
t.Fatal(err)
}
dbg := settings.Debug
settings.Debug = true
defer func() {
os.Remove(home)
settings.Debug = dbg
}()
fc := fake.NewSimpleClientset()
tests := []struct {
expectF func([]byte, interface{}) error
expectName string
}{
{
json.Unmarshal,
"json",
},
{
yaml.Unmarshal,
"yaml",
},
}
for _, s := range tests {
var buf bytes.Buffer
cmd := &initCmd{
out: &buf,
home: helmpath.Home(home),
kubeClient: fc,
opts: installer.Options{Output: installer.OutputFormat(s.expectName)},
namespace: v1.NamespaceDefault,
}
if err := cmd.run(); err != nil {
t.Fatal(err)
}
if got := len(fc.Actions()); got != 0 {
t.Errorf("expected no server calls, got %d", got)
}
d := &v1beta1.Deployment{}
if err = s.expectF(buf.Bytes(), &d); err != nil {
t.Errorf("error unmarshalling init %s output %s %s", s.expectName, err, buf.String())
}
}
}

@ -41,6 +41,7 @@ import (
"k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/helm/pkg/repo"
"k8s.io/helm/pkg/strvals"
"net/url"
)
const installDesc = `
@ -75,21 +76,22 @@ To check the generated manifests of a release without installing the chart,
the '--debug' and '--dry-run' flags can be combined. This will still require a
round-trip to the Tiller server.
If --verify is set, the chart MUST have a provenance file, and the provenenace
fall MUST pass all verification steps.
If --verify is set, the chart MUST have a provenance file, and the provenance
file MUST pass all verification steps.
There are four different ways you can express the chart you want to install:
There are five different ways you can express the chart you want to install:
1. By chart reference: helm install stable/mariadb
2. By path to a packaged chart: helm install ./nginx-1.2.3.tgz
3. By path to an unpacked chart directory: helm install ./nginx
4. By absolute URL: helm install https://example.com/charts/nginx-1.2.3.tgz
5. By chart reference and repo url: helm install --repo https://example.com/charts/ nginx
CHART REFERENCES
A chart reference is a convenient way of reference a chart in a chart repository.
When you use a chart reference ('stable/mariadb'), Helm will look in the local
When you use a chart reference with a repo prefix ('stable/mariadb'), Helm will look in the local
configuration for a chart repository named 'stable', and will then look for a
chart in that repository whose name is 'mariadb'. It will install the latest
version of that chart unless you also supply a version number with the
@ -118,6 +120,7 @@ type installCmd struct {
wait bool
repoURL string
devel bool
depUp bool
certFile string
keyFile string
@ -159,8 +162,8 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command {
debug("Original chart version: %q", inst.version)
if inst.version == "" && inst.devel {
debug("setting version to >0.0.0-a")
inst.version = ">0.0.0-a"
debug("setting version to >0.0.0-0")
inst.version = ">0.0.0-0"
}
cp, err := locateChartPath(inst.repoURL, args[0], inst.version, inst.verify, inst.keyring,
@ -175,7 +178,7 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command {
}
f := cmd.Flags()
f.VarP(&inst.valueFiles, "values", "f", "specify values in a YAML file (can specify multiple)")
f.VarP(&inst.valueFiles, "values", "f", "specify values in a YAML file or a URL(can specify multiple)")
f.StringVarP(&inst.name, "name", "n", "", "release name. If unspecified, it will autogenerate one for you")
f.StringVar(&inst.namespace, "namespace", "", "namespace to install the release into. Defaults to the current kube config namespace.")
f.BoolVar(&inst.dryRun, "dry-run", false, "simulate an install")
@ -192,7 +195,8 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command {
f.StringVar(&inst.certFile, "cert-file", "", "identify HTTPS client using this SSL certificate file")
f.StringVar(&inst.keyFile, "key-file", "", "identify HTTPS client using this SSL key file")
f.StringVar(&inst.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")
f.BoolVar(&inst.devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-a'. If --version is set, this is ignored.")
f.BoolVar(&inst.devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored.")
f.BoolVar(&inst.depUp, "dep-up", false, "run helm dependency update before installing the chart")
return cmd
}
@ -230,8 +234,23 @@ func (i *installCmd) run() error {
// 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); err != nil {
if i.depUp {
man := &downloader.Manager{
Out: i.out,
ChartPath: i.chartPath,
HelmHome: settings.Home,
Keyring: defaultKeyring(),
SkipUpdate: false,
Getters: getter.All(settings),
}
if err := man.Update(); err != nil {
return prettyError(err)
}
} else {
return prettyError(err)
}
}
} else if err != chartutil.ErrRequirementsNotFound {
return fmt.Errorf("cannot load requirements: %v", err)
}
@ -316,8 +335,9 @@ func vals(valueFiles valueFiles, values []string) ([]byte, error) {
if strings.TrimSpace(filePath) == "-" {
bytes, err = ioutil.ReadAll(os.Stdin)
} else {
bytes, err = ioutil.ReadFile(filePath)
bytes, err = readFile(filePath)
}
if err != nil {
return []byte{}, err
}
@ -424,7 +444,7 @@ func locateChartPath(repoURL, name, version string, verify bool, keyring,
return filename, err
}
return filename, fmt.Errorf("file %q not found", name)
return filename, fmt.Errorf("failed to download %q", name)
}
func generateName(nameTemplate string) (string, error) {
@ -441,7 +461,7 @@ func generateName(nameTemplate string) (string, error) {
}
func defaultNamespace() string {
if ns, _, err := kube.GetConfig(settings.KubeContext).Namespace(); err == nil {
if ns, _, err := kube.GetConfig(settings.KubeContext, settings.KubeConfig).Namespace(); err == nil {
return ns
}
return "default"
@ -469,3 +489,23 @@ func checkDependencies(ch *chart.Chart, reqs *chartutil.Requirements) error {
}
return nil
}
//readFile load a file from the local directory or a remote file with a url.
func readFile(filePath string) ([]byte, error) {
u, _ := url.Parse(filePath)
p := getter.All(settings)
// FIXME: maybe someone handle other protocols like ftp.
getterConstructor, err := p.ByScheme(u.Scheme)
if err != nil {
return ioutil.ReadFile(filePath)
} else {
getter, err := getterConstructor(filePath, "", "", "")
if err != nil {
return []byte{}, err
}
data, err := getter.Get(filePath)
return data.Bytes(), err
}
}

@ -24,7 +24,6 @@ import (
"testing"
"github.com/spf13/cobra"
"k8s.io/helm/pkg/helm"
)
@ -36,46 +35,46 @@ func TestInstall(t *testing.T) {
args: []string{"testdata/testcharts/alpine"},
flags: strings.Split("--name aeneas", " "),
expected: "aeneas",
resp: releaseMock(&releaseOptions{name: "aeneas"}),
resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"}),
},
// Install, no hooks
{
name: "install without hooks",
args: []string{"testdata/testcharts/alpine"},
flags: strings.Split("--name aeneas --no-hooks", " "),
expected: "juno",
resp: releaseMock(&releaseOptions{name: "juno"}),
expected: "aeneas",
resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"}),
},
// Install, values from cli
{
name: "install with values",
args: []string{"testdata/testcharts/alpine"},
flags: strings.Split("--set foo=bar", " "),
resp: releaseMock(&releaseOptions{name: "virgil"}),
flags: strings.Split("--name virgil --set foo=bar", " "),
resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "virgil"}),
expected: "virgil",
},
// Install, values from cli via multiple --set
{
name: "install with multiple values",
args: []string{"testdata/testcharts/alpine"},
flags: strings.Split("--set foo=bar", "--set bar=foo"),
resp: releaseMock(&releaseOptions{name: "virgil"}),
flags: strings.Split("--name virgil --set foo=bar --set bar=foo", " "),
resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "virgil"}),
expected: "virgil",
},
// Install, values from yaml
{
name: "install with values",
args: []string{"testdata/testcharts/alpine"},
flags: strings.Split("-f testdata/testcharts/alpine/extra_values.yaml", " "),
resp: releaseMock(&releaseOptions{name: "virgil"}),
flags: strings.Split("--name virgil -f testdata/testcharts/alpine/extra_values.yaml", " "),
resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "virgil"}),
expected: "virgil",
},
// Install, values from multiple yaml
{
name: "install with values",
args: []string{"testdata/testcharts/alpine"},
flags: strings.Split("-f testdata/testcharts/alpine/extra_values.yaml -f testdata/testcharts/alpine/more_values.yaml", " "),
resp: releaseMock(&releaseOptions{name: "virgil"}),
flags: strings.Split("--name virgil -f testdata/testcharts/alpine/extra_values.yaml -f testdata/testcharts/alpine/more_values.yaml", " "),
resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "virgil"}),
expected: "virgil",
},
// Install, no charts
@ -90,23 +89,23 @@ func TestInstall(t *testing.T) {
args: []string{"testdata/testcharts/alpine"},
flags: strings.Split("--name aeneas --replace", " "),
expected: "aeneas",
resp: releaseMock(&releaseOptions{name: "aeneas"}),
resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"}),
},
// Install, with timeout
{
name: "install with a timeout",
args: []string{"testdata/testcharts/alpine"},
flags: strings.Split("--timeout 120", " "),
flags: strings.Split("--name foobar --timeout 120", " "),
expected: "foobar",
resp: releaseMock(&releaseOptions{name: "foobar"}),
resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "foobar"}),
},
// Install, with wait
{
name: "install with a wait",
args: []string{"testdata/testcharts/alpine"},
flags: strings.Split("--wait", " "),
flags: strings.Split("--name apollo --wait", " "),
expected: "apollo",
resp: releaseMock(&releaseOptions{name: "apollo"}),
resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "apollo"}),
},
// Install, using the name-template
{
@ -114,7 +113,7 @@ func TestInstall(t *testing.T) {
args: []string{"testdata/testcharts/alpine"},
flags: []string{"--name-template", "{{upper \"foobar\"}}"},
expected: "FOOBAR",
resp: releaseMock(&releaseOptions{name: "FOOBAR"}),
resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "FOOBAR"}),
},
// Install, perform chart verification along the way.
{

@ -19,16 +19,18 @@ package installer // import "k8s.io/helm/cmd/helm/installer"
import (
"fmt"
"io/ioutil"
"strings"
"github.com/ghodss/yaml"
"k8s.io/api/core/v1"
"k8s.io/api/extensions/v1beta1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/client-go/kubernetes"
corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
extensionsclient "k8s.io/client-go/kubernetes/typed/extensions/v1beta1"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/pkg/apis/extensions/v1beta1"
"k8s.io/helm/pkg/chartutil"
)
// Install uses Kubernetes client to install Tiller.
@ -74,13 +76,17 @@ func Upgrade(client kubernetes.Interface, opts *Options) error {
// createDeployment creates the Tiller Deployment resource.
func createDeployment(client extensionsclient.DeploymentsGetter, opts *Options) error {
obj := deployment(opts)
_, err := client.Deployments(obj.Namespace).Create(obj)
obj, err := deployment(opts)
if err != nil {
return err
}
_, err = client.Deployments(obj.Namespace).Create(obj)
return err
}
// deployment gets the deployment object that installs Tiller.
func deployment(opts *Options) *v1beta1.Deployment {
func deployment(opts *Options) (*v1beta1.Deployment, error) {
return generateDeployment(opts)
}
@ -99,7 +105,10 @@ func service(namespace string) *v1.Service {
// DeploymentManifest gets the manifest (as a string) that describes the Tiller Deployment
// resource.
func DeploymentManifest(opts *Options) (string, error) {
obj := deployment(opts)
obj, err := deployment(opts)
if err != nil {
return "", err
}
buf, err := yaml.Marshal(obj)
return string(buf), err
}
@ -117,8 +126,28 @@ func generateLabels(labels map[string]string) map[string]string {
return labels
}
func generateDeployment(opts *Options) *v1beta1.Deployment {
// parseNodeSelectors parses a comma delimited list of key=values pairs into a map.
func parseNodeSelectorsInto(labels string, m map[string]string) error {
kv := strings.Split(labels, ",")
for _, v := range kv {
el := strings.Split(v, "=")
if len(el) == 2 {
m[el[0]] = el[1]
} else {
return fmt.Errorf("invalid nodeSelector label: %q", kv)
}
}
return nil
}
func generateDeployment(opts *Options) (*v1beta1.Deployment, error) {
labels := generateLabels(map[string]string{"name": "tiller"})
nodeSelectors := map[string]string{}
if len(opts.NodeSelectors) > 0 {
err := parseNodeSelectorsInto(opts.NodeSelectors, nodeSelectors)
if err != nil {
return nil, err
}
}
d := &v1beta1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Namespace: opts.Namespace,
@ -139,6 +168,7 @@ func generateDeployment(opts *Options) *v1beta1.Deployment {
ImagePullPolicy: opts.pullPolicy(),
Ports: []v1.ContainerPort{
{ContainerPort: 44134, Name: "tiller"},
{ContainerPort: 44135, Name: "http"},
},
Env: []v1.EnvVar{
{Name: "TILLER_NAMESPACE", Value: opts.Namespace},
@ -167,9 +197,7 @@ func generateDeployment(opts *Options) *v1beta1.Deployment {
},
},
HostNetwork: opts.EnableHostNetwork,
NodeSelector: map[string]string{
"beta.kubernetes.io/os": "linux",
},
NodeSelector: nodeSelectors,
},
},
},
@ -205,7 +233,40 @@ func generateDeployment(opts *Options) *v1beta1.Deployment {
},
})
}
return d
// if --override values were specified, ultimately convert values and deployment to maps,
// merge them and convert back to Deployment
if len(opts.Values) > 0 {
// base deployment struct
var dd v1beta1.Deployment
// get YAML from original deployment
dy, err := yaml.Marshal(d)
if err != nil {
return nil, fmt.Errorf("Error marshalling base Tiller Deployment: %s", err)
}
// convert deployment YAML to values
dv, err := chartutil.ReadValues(dy)
if err != nil {
return nil, fmt.Errorf("Error converting Deployment manifest: %s ", err)
}
dm := dv.AsMap()
// merge --set values into our map
sm, err := opts.valuesMap(dm)
if err != nil {
return nil, fmt.Errorf("Error merging --set values into Deployment manifest")
}
finalY, err := yaml.Marshal(sm)
if err != nil {
return nil, fmt.Errorf("Error marshalling merged map to YAML: %s ", err)
}
// convert merged values back into deployment
err = yaml.Unmarshal(finalY, &dd)
if err != nil {
return nil, fmt.Errorf("Error unmarshalling Values to Deployment manifest: %s ", err)
}
d = &dd
}
return d, nil
}
func generateService(namespace string) *v1.Service {

@ -23,13 +23,14 @@ import (
"testing"
"github.com/ghodss/yaml"
"k8s.io/api/core/v1"
"k8s.io/api/extensions/v1beta1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes/fake"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/pkg/apis/extensions/v1beta1"
testcore "k8s.io/client-go/testing"
"k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/version"
)
@ -206,6 +207,10 @@ func TestInstall(t *testing.T) {
if i != image {
t.Errorf("expected image = '%s', got '%s'", image, i)
}
ports := len(obj.Spec.Template.Spec.Containers[0].Ports)
if ports != 2 {
t.Errorf("expected ports = 2, got '%d'", ports)
}
return true, obj, nil
})
fc.AddReactor("create", "services", func(action testcore.Action) (bool, runtime.Object, error) {
@ -330,7 +335,7 @@ func TestInstall_canary(t *testing.T) {
func TestUpgrade(t *testing.T) {
image := "gcr.io/kubernetes-helm/tiller:v2.0.0"
serviceAccount := "newServiceAccount"
existingDeployment := deployment(&Options{
existingDeployment, _ := deployment(&Options{
Namespace: v1.NamespaceDefault,
ImageSpec: "imageToReplace",
ServiceAccount: "serviceAccountToReplace",
@ -371,7 +376,7 @@ func TestUpgrade(t *testing.T) {
func TestUpgrade_serviceNotFound(t *testing.T) {
image := "gcr.io/kubernetes-helm/tiller:v2.0.0"
existingDeployment := deployment(&Options{
existingDeployment, _ := deployment(&Options{
Namespace: v1.NamespaceDefault,
ImageSpec: "imageToReplace",
UseCanary: false,
@ -419,3 +424,107 @@ func tlsTestFile(t *testing.T, path string) string {
}
return path
}
func TestDeploymentManifest_WithNodeSelectors(t *testing.T) {
tests := []struct {
opts Options
name string
expect map[string]interface{}
}{
{
Options{Namespace: v1.NamespaceDefault, NodeSelectors: "app=tiller"},
"nodeSelector app=tiller",
map[string]interface{}{"app": "tiller"},
},
{
Options{Namespace: v1.NamespaceDefault, NodeSelectors: "app=tiller,helm=rocks"},
"nodeSelector app=tiller, helm=rocks",
map[string]interface{}{"app": "tiller", "helm": "rocks"},
},
// note: nodeSelector key and value are strings
{
Options{Namespace: v1.NamespaceDefault, NodeSelectors: "app=tiller,minCoolness=1"},
"nodeSelector app=tiller, helm=rocks",
map[string]interface{}{"app": "tiller", "minCoolness": "1"},
},
}
for _, tt := range tests {
o, err := DeploymentManifest(&tt.opts)
if err != nil {
t.Fatalf("%s: error %q", tt.name, err)
}
var d v1beta1.Deployment
if err := yaml.Unmarshal([]byte(o), &d); err != nil {
t.Fatalf("%s: error %q", tt.name, err)
}
// Verify that environment variables in Deployment reflect the use of TLS being enabled.
got := d.Spec.Template.Spec.NodeSelector
for k, v := range tt.expect {
if got[k] != v {
t.Errorf("%s: expected nodeSelector value %q, got %q", tt.name, tt.expect, got)
}
}
}
}
func TestDeploymentManifest_WithSetValues(t *testing.T) {
tests := []struct {
opts Options
name string
expectPath string
expect interface{}
}{
{
Options{Namespace: v1.NamespaceDefault, Values: []string{"spec.template.spec.nodeselector.app=tiller"}},
"setValues spec.template.spec.nodeSelector.app=tiller",
"spec.template.spec.nodeSelector.app",
"tiller",
},
{
Options{Namespace: v1.NamespaceDefault, Values: []string{"spec.replicas=2"}},
"setValues spec.replicas=2",
"spec.replicas",
2,
},
{
Options{Namespace: v1.NamespaceDefault, Values: []string{"spec.template.spec.activedeadlineseconds=120"}},
"setValues spec.template.spec.activedeadlineseconds=120",
"spec.template.spec.activeDeadlineSeconds",
120,
},
}
for _, tt := range tests {
o, err := DeploymentManifest(&tt.opts)
if err != nil {
t.Fatalf("%s: error %q", tt.name, err)
}
values, err := chartutil.ReadValues([]byte(o))
if err != nil {
t.Errorf("Error converting Deployment manifest to Values: %s", err)
}
// path value
pv, err := values.PathValue(tt.expectPath)
if err != nil {
t.Errorf("Error retrieving path value from Deployment Values: %s", err)
}
// convert our expected value to match the result type for comparison
ev := tt.expect
switch pvt := pv.(type) {
case float64:
floatType := reflect.TypeOf(float64(0))
v := reflect.ValueOf(ev)
v = reflect.Indirect(v)
if !v.Type().ConvertibleTo(floatType) {
t.Fatalf("Error converting expected value %v to float64", v.Type())
}
fv := v.Convert(floatType)
if fv.Float() != pvt {
t.Errorf("%s: expected value %q, got %q", tt.name, tt.expect, pv)
}
default:
if pv != tt.expect {
t.Errorf("%s: expected value %q, got %q", tt.name, tt.expect, pv)
}
}
}
}

@ -19,7 +19,8 @@ package installer // import "k8s.io/helm/cmd/helm/installer"
import (
"fmt"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/api/core/v1"
"k8s.io/helm/pkg/strvals"
"k8s.io/helm/pkg/version"
)
@ -76,6 +77,15 @@ type Options struct {
//
// Less than or equal to zero means no limit.
MaxHistory int
// NodeSelectors determine which nodes Tiller can land on.
NodeSelectors string
// Output dumps the Tiller manifest in the specified format (e.g. JSON) but skips Helm/Tiller installation.
Output OutputFormat
// Set merges additional values into the Tiller Deployment manifest.
Values []string
}
func (opts *Options) selectImage() string {
@ -97,3 +107,42 @@ func (opts *Options) pullPolicy() v1.PullPolicy {
}
func (opts *Options) tls() bool { return opts.EnableTLS || opts.VerifyTLS }
// valuesMap returns user set values in map format
func (opts *Options) valuesMap(m map[string]interface{}) (map[string]interface{}, error) {
for _, skv := range opts.Values {
if err := strvals.ParseInto(skv, m); err != nil {
return nil, err
}
}
return m, nil
}
// OutputFormat defines valid values for init output (json, yaml)
type OutputFormat string
// String returns the string value of the OutputFormat
func (f *OutputFormat) String() string {
return string(*f)
}
// Type returns the string value of the OutputFormat
func (f *OutputFormat) Type() string {
return "OutputFormat"
}
const (
fmtJSON OutputFormat = "json"
fmtYAML OutputFormat = "yaml"
)
// Set validates and sets the value of the OutputFormat
func (f *OutputFormat) Set(s string) error {
for _, of := range []OutputFormat{fmtJSON, fmtYAML} {
if s == string(of) {
*f = of
return nil
}
}
return fmt.Errorf("unknown output format %q", s)
}

@ -19,7 +19,7 @@ package installer // import "k8s.io/helm/cmd/helm/installer"
import (
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
"k8s.io/kubernetes/pkg/kubectl"

@ -93,7 +93,7 @@ func newListCmd(client helm.Interface, out io.Writer) *cobra.Command {
list.filter = strings.Join(args, " ")
}
if list.client == nil {
list.client = helm.NewClient(helm.Host(settings.TillerHost))
list.client = newClient()
}
return list.run()
},

@ -36,7 +36,7 @@ func TestListCmd(t *testing.T) {
{
name: "with a release",
resp: []*release.Release{
releaseMock(&releaseOptions{name: "thomas-guide"}),
helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide"}),
},
expected: "thomas-guide",
},
@ -44,7 +44,7 @@ func TestListCmd(t *testing.T) {
name: "list",
args: []string{},
resp: []*release.Release{
releaseMock(&releaseOptions{name: "atlas"}),
helm.ReleaseMock(&helm.MockReleaseOptions{Name: "atlas"}),
},
expected: "NAME \tREVISION\tUPDATED \tSTATUS \tCHART \tNAMESPACE\natlas\t1 \t(.*)\tDEPLOYED\tfoo-0.1.0-beta.1\tdefault \n",
},
@ -52,8 +52,8 @@ func TestListCmd(t *testing.T) {
name: "list, one deployed, one failed",
args: []string{"-q"},
resp: []*release.Release{
releaseMock(&releaseOptions{name: "thomas-guide", statusCode: release.Status_FAILED}),
releaseMock(&releaseOptions{name: "atlas-guide", statusCode: release.Status_DEPLOYED}),
helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide", StatusCode: release.Status_FAILED}),
helm.ReleaseMock(&helm.MockReleaseOptions{Name: "atlas-guide", StatusCode: release.Status_DEPLOYED}),
},
expected: "thomas-guide\natlas-guide",
},
@ -61,8 +61,8 @@ func TestListCmd(t *testing.T) {
name: "with a release, multiple flags",
args: []string{"--deleted", "--deployed", "--failed", "-q"},
resp: []*release.Release{
releaseMock(&releaseOptions{name: "thomas-guide", statusCode: release.Status_DELETED}),
releaseMock(&releaseOptions{name: "atlas-guide", statusCode: release.Status_DEPLOYED}),
helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide", StatusCode: release.Status_DELETED}),
helm.ReleaseMock(&helm.MockReleaseOptions{Name: "atlas-guide", StatusCode: release.Status_DEPLOYED}),
},
// Note: We're really only testing that the flags parsed correctly. Which results are returned
// depends on the backend. And until pkg/helm is done, we can't mock this.
@ -72,8 +72,8 @@ func TestListCmd(t *testing.T) {
name: "with a release, multiple flags",
args: []string{"--all", "-q"},
resp: []*release.Release{
releaseMock(&releaseOptions{name: "thomas-guide", statusCode: release.Status_DELETED}),
releaseMock(&releaseOptions{name: "atlas-guide", statusCode: release.Status_DEPLOYED}),
helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide", StatusCode: release.Status_DELETED}),
helm.ReleaseMock(&helm.MockReleaseOptions{Name: "atlas-guide", StatusCode: release.Status_DEPLOYED}),
},
// See note on previous test.
expected: "thomas-guide\natlas-guide",
@ -82,8 +82,8 @@ func TestListCmd(t *testing.T) {
name: "with a release, multiple flags, deleting",
args: []string{"--all", "-q"},
resp: []*release.Release{
releaseMock(&releaseOptions{name: "thomas-guide", statusCode: release.Status_DELETING}),
releaseMock(&releaseOptions{name: "atlas-guide", statusCode: release.Status_DEPLOYED}),
helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide", StatusCode: release.Status_DELETING}),
helm.ReleaseMock(&helm.MockReleaseOptions{Name: "atlas-guide", StatusCode: release.Status_DEPLOYED}),
},
// See note on previous test.
expected: "thomas-guide\natlas-guide",
@ -92,8 +92,8 @@ func TestListCmd(t *testing.T) {
name: "namespace defined, multiple flags",
args: []string{"--all", "-q", "--namespace test123"},
resp: []*release.Release{
releaseMock(&releaseOptions{name: "thomas-guide", namespace: "test123"}),
releaseMock(&releaseOptions{name: "atlas-guide", namespace: "test321"}),
helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide", Namespace: "test123"}),
helm.ReleaseMock(&helm.MockReleaseOptions{Name: "atlas-guide", Namespace: "test321"}),
},
// See note on previous test.
expected: "thomas-guide",
@ -102,8 +102,8 @@ func TestListCmd(t *testing.T) {
name: "with a pending release, multiple flags",
args: []string{"--all", "-q"},
resp: []*release.Release{
releaseMock(&releaseOptions{name: "thomas-guide", statusCode: release.Status_PENDING_INSTALL}),
releaseMock(&releaseOptions{name: "atlas-guide", statusCode: release.Status_DEPLOYED}),
helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide", StatusCode: release.Status_PENDING_INSTALL}),
helm.ReleaseMock(&helm.MockReleaseOptions{Name: "atlas-guide", StatusCode: release.Status_DEPLOYED}),
},
expected: "thomas-guide\natlas-guide",
},
@ -111,10 +111,10 @@ func TestListCmd(t *testing.T) {
name: "with a pending release, pending flag",
args: []string{"--pending", "-q"},
resp: []*release.Release{
releaseMock(&releaseOptions{name: "thomas-guide", statusCode: release.Status_PENDING_INSTALL}),
releaseMock(&releaseOptions{name: "wild-idea", statusCode: release.Status_PENDING_UPGRADE}),
releaseMock(&releaseOptions{name: "crazy-maps", statusCode: release.Status_PENDING_ROLLBACK}),
releaseMock(&releaseOptions{name: "atlas-guide", statusCode: release.Status_DEPLOYED}),
helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide", StatusCode: release.Status_PENDING_INSTALL}),
helm.ReleaseMock(&helm.MockReleaseOptions{Name: "wild-idea", StatusCode: release.Status_PENDING_UPGRADE}),
helm.ReleaseMock(&helm.MockReleaseOptions{Name: "crazy-maps", StatusCode: release.Status_PENDING_ROLLBACK}),
helm.ReleaseMock(&helm.MockReleaseOptions{Name: "atlas-guide", StatusCode: release.Status_DEPLOYED}),
},
expected: "thomas-guide\nwild-idea\ncrazy-maps",
},

@ -56,6 +56,7 @@ type packageCmd struct {
key string
keyring string
version string
appVersion string
destination string
dependencyUpdate bool
@ -99,6 +100,7 @@ func newPackageCmd(out io.Writer) *cobra.Command {
f.StringVar(&pkg.key, "key", "", "name of the key to use when signing. Used if --sign is true")
f.StringVar(&pkg.keyring, "keyring", defaultKeyring(), "location of a public keyring")
f.StringVar(&pkg.version, "version", "", "set the version on the chart to this semver version")
f.StringVar(&pkg.appVersion, "app-version", "", "set the appVersion on the chart to this version")
f.StringVarP(&pkg.destination, "destination", "d", ".", "location to write the chart.")
f.BoolVarP(&pkg.dependencyUpdate, "dependency-update", "u", false, `update dependencies from "requirements.yaml" to dir "charts/" before packaging`)
@ -139,6 +141,11 @@ func (p *packageCmd) run() error {
debug("Setting version to %s", p.version)
}
if p.appVersion != "" {
ch.Metadata.AppVersion = p.appVersion
debug("Setting appVersion to %s", p.appVersion)
}
if filepath.Base(path) != ch.Metadata.Name {
return fmt.Errorf("directory name (%s) and Chart.yaml name (%s) must match", filepath.Base(path), ch.Metadata.Name)
}

@ -25,6 +25,7 @@ import (
"github.com/spf13/cobra"
"k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/helm/helmpath"
"k8s.io/helm/pkg/proto/hapi/chart"
)
@ -200,6 +201,38 @@ func TestPackage(t *testing.T) {
}
}
func TestSetAppVersion(t *testing.T) {
var ch *chart.Chart
expectedAppVersion := "app-version-foo"
tmp, _ := ioutil.TempDir("", "helm-package-app-version-")
defer os.RemoveAll(tmp)
c := newPackageCmd(&bytes.Buffer{})
flags := map[string]string{
"destination": tmp,
"app-version": expectedAppVersion,
}
setFlags(c, flags)
err := c.RunE(c, []string{"testdata/testcharts/alpine"})
if err != nil {
t.Errorf("unexpected error %q", err)
}
chartPath := filepath.Join(tmp, "alpine-0.1.0.tgz")
if fi, err := os.Stat(chartPath); err != nil {
t.Errorf("expected file %q, got err %q", chartPath, err)
} else if fi.Size() == 0 {
t.Errorf("file %q has zero bytes.", chartPath)
}
ch, err = chartutil.Load(chartPath)
if err != nil {
t.Errorf("unexpected error loading packaged chart: %v", err)
}
if ch.Metadata.AppVersion != expectedAppVersion {
t.Errorf("expected app-version %q, found %q", expectedAppVersion, ch.Metadata.AppVersion)
}
}
func setFlags(cmd *cobra.Command, flags map[string]string) {
dest := cmd.Flags()
for f, v := range flags {

@ -33,11 +33,19 @@ type pluginInstallCmd struct {
out io.Writer
}
const pluginInstallDesc = `
This command allows you to install a plugin from a url to a VCS repo or a local path.
Example usage:
$ helm plugin install https://github.com/technosophos/helm-template
`
func newPluginInstallCmd(out io.Writer) *cobra.Command {
pcmd := &pluginInstallCmd{out: out}
cmd := &cobra.Command{
Use: "install [options] <path|url>...",
Short: "install one or more Helm plugins",
Long: pluginInstallDesc,
PreRunE: func(cmd *cobra.Command, args []string) error {
return pcmd.complete(args)
},

@ -86,7 +86,7 @@ func newResetCmd(client helm.Interface, out io.Writer) *cobra.Command {
// runReset uninstalls tiller from Kubernetes Cluster and deletes local config
func (d *resetCmd) run() error {
if d.kubeClient == nil {
_, c, err := getInternalKubeClient(settings.KubeContext)
c, err := getInternalKubeClient(settings.KubeContext)
if err != nil {
return fmt.Errorf("could not get kubernetes client: %s", err)
}

@ -107,7 +107,7 @@ func TestReset_deployedReleases(t *testing.T) {
var buf bytes.Buffer
resp := []*release.Release{
releaseMock(&releaseOptions{name: "atlas-guide", statusCode: release.Status_DEPLOYED}),
helm.ReleaseMock(&helm.MockReleaseOptions{Name: "atlas-guide", StatusCode: release.Status_DEPLOYED}),
}
c := &helm.FakeClient{
Rels: resp,
@ -139,7 +139,7 @@ func TestReset_forceFlag(t *testing.T) {
var buf bytes.Buffer
resp := []*release.Release{
releaseMock(&releaseOptions{name: "atlas-guide", statusCode: release.Status_DEPLOYED}),
helm.ReleaseMock(&helm.MockReleaseOptions{Name: "atlas-guide", StatusCode: release.Status_DEPLOYED}),
}
c := &helm.FakeClient{
Rels: resp,

@ -109,10 +109,17 @@ func (s *searchCmd) applyConstraint(res []*search.Result) ([]*search.Result, err
}
data := res[:0]
foundNames := map[string]bool{}
for _, r := range res {
if _, found := foundNames[r.Name]; found {
continue
}
v, err := semver.NewVersion(r.Chart.Version)
if err != nil || constraint.Check(v) {
data = append(data, r)
if !s.versions {
foundNames[r.Name] = true // If user hasn't requested all versions, only show the latest that matches
}
}
}
@ -125,9 +132,9 @@ func (s *searchCmd) formatSearchResults(res []*search.Result) string {
}
table := uitable.New()
table.MaxColWidth = 50
table.AddRow("NAME", "VERSION", "DESCRIPTION")
table.AddRow("NAME", "CHART VERSION", "APP VERSION", "DESCRIPTION")
for _, r := range res {
table.AddRow(r.Name, r.Chart.Version, r.Chart.Description)
table.AddRow(r.Name, r.Chart.Version, r.Chart.AppVersion, r.Chart.Description)
}
return table.String()
}
@ -149,7 +156,7 @@ func (s *searchCmd) buildIndex() (*search.Index, error) {
continue
}
i.AddRepo(n, ind, s.versions)
i.AddRepo(n, ind, s.versions || len(s.version) > 0)
}
return i, nil
}

@ -34,18 +34,42 @@ func TestSearchCmd(t *testing.T) {
{
name: "search for 'maria', expect one match",
args: []string{"maria"},
expect: "NAME \tVERSION\tDESCRIPTION \ntesting/mariadb\t0.3.0 \tChart for MariaDB",
expect: "NAME \tCHART VERSION\tAPP VERSION\tDESCRIPTION \ntesting/mariadb\t0.3.0 \t \tChart for MariaDB",
},
{
name: "search for 'alpine', expect two matches",
args: []string{"alpine"},
expect: "NAME \tVERSION\tDESCRIPTION \ntesting/alpine\t0.2.0 \tDeploy a basic Alpine Linux pod",
expect: "NAME \tCHART VERSION\tAPP VERSION\tDESCRIPTION \ntesting/alpine\t0.2.0 \t2.3.4 \tDeploy a basic Alpine Linux pod",
},
{
name: "search for 'alpine' with versions, expect three matches",
args: []string{"alpine"},
flags: []string{"--versions"},
expect: "NAME \tVERSION\tDESCRIPTION \ntesting/alpine\t0.2.0 \tDeploy a basic Alpine Linux pod\ntesting/alpine\t0.1.0 \tDeploy a basic Alpine Linux pod",
expect: "NAME \tCHART VERSION\tAPP VERSION\tDESCRIPTION \ntesting/alpine\t0.2.0 \t2.3.4 \tDeploy a basic Alpine Linux pod\ntesting/alpine\t0.1.0 \t1.2.3 \tDeploy a basic Alpine Linux pod",
},
{
name: "search for 'alpine' with version constraint, expect one match with version 0.1.0",
args: []string{"alpine"},
flags: []string{"--version", ">= 0.1, < 0.2"},
expect: "NAME \tCHART VERSION\tAPP VERSION\tDESCRIPTION \ntesting/alpine\t0.1.0 \t1.2.3 \tDeploy a basic Alpine Linux pod",
},
{
name: "search for 'alpine' with version constraint, expect one match with version 0.1.0",
args: []string{"alpine"},
flags: []string{"--versions", "--version", ">= 0.1, < 0.2"},
expect: "NAME \tCHART VERSION\tAPP VERSION\tDESCRIPTION \ntesting/alpine\t0.1.0 \t1.2.3 \tDeploy a basic Alpine Linux pod",
},
{
name: "search for 'alpine' with version constraint, expect one match with version 0.2.0",
args: []string{"alpine"},
flags: []string{"--version", ">= 0.1"},
expect: "NAME \tCHART VERSION\tAPP VERSION\tDESCRIPTION \ntesting/alpine\t0.2.0 \t2.3.4 \tDeploy a basic Alpine Linux pod",
},
{
name: "search for 'alpine' with version constraint and --versions, expect two matches",
args: []string{"alpine"},
flags: []string{"--versions", "--version", ">= 0.1"},
expect: "NAME \tCHART VERSION\tAPP VERSION\tDESCRIPTION \ntesting/alpine\t0.2.0 \t2.3.4 \tDeploy a basic Alpine Linux pod\ntesting/alpine\t0.1.0 \t1.2.3 \tDeploy a basic Alpine Linux pod",
},
{
name: "search for 'syzygy', expect no matches",
@ -56,7 +80,7 @@ func TestSearchCmd(t *testing.T) {
name: "search for 'alp[a-z]+', expect two matches",
args: []string{"alp[a-z]+"},
flags: []string{"--regexp"},
expect: "NAME \tVERSION\tDESCRIPTION \ntesting/alpine\t0.2.0 \tDeploy a basic Alpine Linux pod",
expect: "NAME \tCHART VERSION\tAPP VERSION\tDESCRIPTION \ntesting/alpine\t0.2.0 \t2.3.4 \tDeploy a basic Alpine Linux pod",
regexp: true,
},
{

@ -67,7 +67,7 @@ func newStatusCmd(client helm.Interface, out io.Writer) *cobra.Command {
}
status.release = args[0]
if status.client == nil {
status.client = helm.NewClient(helm.Host(settings.TillerHost))
status.client = newClient()
}
return status.run()
},

@ -21,6 +21,7 @@ import (
"fmt"
"io"
"os"
"path"
"path/filepath"
"regexp"
"strings"
@ -39,6 +40,10 @@ import (
tversion "k8s.io/helm/pkg/version"
)
const defaultDirectoryPermission = 0755
var whitespaceRegex = regexp.MustCompile(`^\s*$`)
const templateDesc = `
Render chart templates locally and display the output.
@ -64,6 +69,7 @@ type templateCmd struct {
releaseName string
renderFiles []string
kubeVersion string
outputDir string
}
func newTemplateCmd(out io.Writer) *cobra.Command {
@ -88,6 +94,7 @@ func newTemplateCmd(out io.Writer) *cobra.Command {
f.StringArrayVar(&t.values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
f.StringVar(&t.nameTemplate, "name-template", "", "specify template used to name the release")
f.StringVar(&t.kubeVersion, "kube-version", "", "override the Kubernetes version used as Capabilities.KubeVersion.Major/Minor (e.g. 1.7)")
f.StringVar(&t.outputDir, "output-dir", "", "writes the executed templates to files in output-dir instead of stdout")
return cmd
}
@ -126,6 +133,14 @@ func (t *templateCmd) run(cmd *cobra.Command, args []string) error {
}
}
// verify that output-dir exists if provided
if t.outputDir != "" {
_, err = os.Stat(t.outputDir)
if os.IsNotExist(err) {
return fmt.Errorf("output-dir '%s' does not exist", t.outputDir)
}
}
if t.namespace == "" {
t.namespace = defaultNamespace()
}
@ -248,8 +263,61 @@ func (t *templateCmd) run(cmd *cobra.Command, args []string) error {
if strings.HasPrefix(b, "_") {
continue
}
if t.outputDir != "" {
// blank template after execution
if whitespaceRegex.MatchString(data) {
continue
}
err = writeToFile(t.outputDir, m.Name, data)
if err != nil {
return err
}
continue
}
fmt.Printf("---\n# Source: %s\n", m.Name)
fmt.Println(data)
}
return nil
}
// write the <data> to <output-dir>/<name>
func writeToFile(outputDir string, name string, data string) error {
outfileName := strings.Join([]string{outputDir, name}, string(filepath.Separator))
err := ensureDirectoryForFile(outfileName)
if err != nil {
return err
}
f, err := os.Create(outfileName)
if err != nil {
return err
}
defer f.Close()
_, err = f.WriteString(fmt.Sprintf("##---\n# Source: %s\n%s", name, data))
if err != nil {
return err
}
fmt.Printf("wrote %s\n", outfileName)
return nil
}
// check if the directory exists to create file. creates if don't exists
func ensureDirectoryForFile(file string) error {
baseDir := path.Dir(file)
_, err := os.Stat(baseDir)
if err != nil && !os.IsNotExist(err) {
return err
}
err = os.MkdirAll(baseDir, defaultDirectoryPermission)
if err != nil {
return err
}
return nil
}

@ -8,6 +8,7 @@ entries:
sources:
- https://github.com/kubernetes/helm
version: 0.1.0
appVersion: 1.2.3
description: Deploy a basic Alpine Linux pod
keywords: []
maintainers: []
@ -20,6 +21,7 @@ entries:
sources:
- https://github.com/kubernetes/helm
version: 0.2.0
appVersion: 2.3.4
description: Deploy a basic Alpine Linux pod
keywords: []
maintainers: []

@ -98,8 +98,8 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command {
}
if upgrade.version == "" && upgrade.devel {
debug("setting version to >0.0.0-a")
upgrade.version = ">0.0.0-a"
debug("setting version to >0.0.0-0")
upgrade.version = ">0.0.0-0"
}
upgrade.release = args[0]
@ -111,7 +111,7 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command {
}
f := cmd.Flags()
f.VarP(&upgrade.valueFiles, "values", "f", "specify values in a YAML file (can specify multiple)")
f.VarP(&upgrade.valueFiles, "values", "f", "specify values in a YAML file or a URL(can specify multiple)")
f.BoolVar(&upgrade.dryRun, "dry-run", false, "simulate an upgrade")
f.BoolVar(&upgrade.recreate, "recreate-pods", false, "performs pods restart for the resource if applicable")
f.BoolVar(&upgrade.force, "force", false, "force resource update through delete/recreate if needed")
@ -131,7 +131,7 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command {
f.StringVar(&upgrade.certFile, "cert-file", "", "identify HTTPS client using this SSL certificate file")
f.StringVar(&upgrade.keyFile, "key-file", "", "identify HTTPS client using this SSL key file")
f.StringVar(&upgrade.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")
f.BoolVar(&upgrade.devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-a'. If --version is set, this is ignored.")
f.BoolVar(&upgrade.devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored.")
f.MarkDeprecated("disable-hooks", "use --no-hooks instead")
@ -151,7 +151,15 @@ func (u *upgradeCmd) run() error {
// The returned error is a grpc.rpcError that wraps the message from the original error.
// So we're stuck doing string matching against the wrapped error, which is nested somewhere
// inside of the grpc.rpcError message.
_, err := u.client.ReleaseHistory(u.release, helm.WithMaxHistory(1))
releaseHistory, err := u.client.ReleaseHistory(u.release, helm.WithMaxHistory(1))
if err == nil {
previousReleaseNamespace := releaseHistory.Releases[0].Namespace
if previousReleaseNamespace != u.namespace {
fmt.Fprintf(u.out, "WARNING: Namespace doesn't match with previous. Release will be deployed to %s\n", previousReleaseNamespace)
}
}
if err != nil && strings.Contains(err.Error(), driver.ErrReleaseNotFound(u.release).Error()) {
fmt.Fprintf(u.out, "Release %q does not exist. Installing it now.\n", u.release)
ic := &installCmd{

@ -28,6 +28,7 @@ import (
"k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/helm"
"k8s.io/helm/pkg/proto/hapi/chart"
"k8s.io/helm/pkg/proto/hapi/release"
)
func TestUpgradeCmd(t *testing.T) {
@ -43,9 +44,9 @@ func TestUpgradeCmd(t *testing.T) {
t.Errorf("Error creating chart for upgrade: %v", err)
}
ch, _ := chartutil.Load(chartPath)
_ = releaseMock(&releaseOptions{
name: "funny-bunny",
chart: ch,
_ = helm.ReleaseMock(&helm.MockReleaseOptions{
Name: "funny-bunny",
Chart: ch,
})
// update chart version
@ -94,61 +95,68 @@ func TestUpgradeCmd(t *testing.T) {
{
name: "upgrade a release",
args: []string{"funny-bunny", chartPath},
resp: releaseMock(&releaseOptions{name: "funny-bunny", version: 2, chart: ch}),
resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "funny-bunny", Version: 2, Chart: ch}),
expected: "Release \"funny-bunny\" has been upgraded. Happy Helming!\n",
rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "funny-bunny", Version: 2, Chart: ch})},
},
{
name: "upgrade a release with timeout",
args: []string{"funny-bunny", chartPath},
flags: []string{"--timeout", "120"},
resp: releaseMock(&releaseOptions{name: "funny-bunny", version: 3, chart: ch2}),
resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "funny-bunny", Version: 3, Chart: ch2}),
expected: "Release \"funny-bunny\" has been upgraded. Happy Helming!\n",
rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "funny-bunny", Version: 3, Chart: ch2})},
},
{
name: "upgrade a release with --reset-values",
args: []string{"funny-bunny", chartPath},
flags: []string{"--reset-values", "true"},
resp: releaseMock(&releaseOptions{name: "funny-bunny", version: 4, chart: ch2}),
resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "funny-bunny", Version: 4, Chart: ch2}),
expected: "Release \"funny-bunny\" has been upgraded. Happy Helming!\n",
rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "funny-bunny", Version: 4, Chart: ch2})},
},
{
name: "upgrade a release with --reuse-values",
args: []string{"funny-bunny", chartPath},
flags: []string{"--reuse-values", "true"},
resp: releaseMock(&releaseOptions{name: "funny-bunny", version: 5, chart: ch2}),
resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "funny-bunny", Version: 5, Chart: ch2}),
expected: "Release \"funny-bunny\" has been upgraded. Happy Helming!\n",
rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "funny-bunny", Version: 5, Chart: ch2})},
},
{
name: "install a release with 'upgrade --install'",
args: []string{"zany-bunny", chartPath},
flags: []string{"-i"},
resp: releaseMock(&releaseOptions{name: "zany-bunny", version: 1, chart: ch}),
resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "zany-bunny", Version: 1, Chart: ch}),
expected: "Release \"zany-bunny\" has been upgraded. Happy Helming!\n",
rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "zany-bunny", Version: 1, Chart: ch})},
},
{
name: "install a release with 'upgrade --install' and timeout",
args: []string{"crazy-bunny", chartPath},
flags: []string{"-i", "--timeout", "120"},
resp: releaseMock(&releaseOptions{name: "crazy-bunny", version: 1, chart: ch}),
resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "crazy-bunny", Version: 1, Chart: ch}),
expected: "Release \"crazy-bunny\" has been upgraded. Happy Helming!\n",
rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "crazy-bunny", Version: 1, Chart: ch})},
},
{
name: "upgrade a release with wait",
args: []string{"crazy-bunny", chartPath},
flags: []string{"--wait"},
resp: releaseMock(&releaseOptions{name: "crazy-bunny", version: 2, chart: ch2}),
resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "crazy-bunny", Version: 2, Chart: ch2}),
expected: "Release \"crazy-bunny\" has been upgraded. Happy Helming!\n",
rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "crazy-bunny", Version: 2, Chart: ch2})},
},
{
name: "upgrade a release with missing dependencies",
args: []string{"bonkers-bunny", missingDepsPath},
resp: releaseMock(&releaseOptions{name: "bonkers-bunny", version: 1, chart: ch3}),
resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "bonkers-bunny", Version: 1, Chart: ch3}),
err: true,
},
{
name: "upgrade a release with bad dependencies",
args: []string{"bonkers-bunny", badDepsPath},
resp: releaseMock(&releaseOptions{name: "bonkers-bunny", version: 1, chart: ch3}),
resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "bonkers-bunny", Version: 1, Chart: ch3}),
err: true,
},
}

@ -26,9 +26,9 @@ import (
"google.golang.org/grpc/grpclog"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"github.com/spf13/pflag"
"k8s.io/helm/pkg/kube"
rudderAPI "k8s.io/helm/pkg/proto/hapi/rudder"
"k8s.io/helm/pkg/rudder"
"k8s.io/helm/pkg/tiller"
"k8s.io/helm/pkg/version"
)
@ -36,24 +36,43 @@ import (
var kubeClient *kube.Client
var clientset internalclientset.Interface
type options struct {
listen string
}
func (opts *options) registerFlags() {
pflag.StringVarP(&opts.listen, "listen", "l", "127.0.0.1:10001",
"Socket for rudder grpc server (default: 127.0.0.1:10001).")
}
func (opts *options) parseFlags() {
pflag.Parse()
}
func (opts *options) regAndParseFlags() {
opts.registerFlags()
opts.parseFlags()
}
func main() {
opts := new(options)
opts.regAndParseFlags()
var err error
kubeClient = kube.New(nil)
clientset, err = kubeClient.ClientSet()
if err != nil {
grpclog.Fatalf("Cannot initialize Kubernetes connection: %s", err)
}
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", rudder.GrpcPort))
grpclog.Printf("Creating tcp socket on %s\n", opts.listen)
lis, err := net.Listen("tcp", opts.listen)
if err != nil {
grpclog.Fatalf("failed to listen: %v", err)
}
grpcServer := grpc.NewServer()
rudderAPI.RegisterReleaseModuleServiceServer(grpcServer, &ReleaseModuleServiceServer{})
grpclog.Print("Server starting")
grpclog.Printf("Starting server on %s\n", opts.listen)
grpcServer.Serve(lis)
grpclog.Print("Server started")
}
// ReleaseModuleServiceServer provides implementation for rudderAPI.ReleaseModuleServiceServer

@ -28,10 +28,12 @@ import (
"path/filepath"
"strconv"
"strings"
"time"
goprom "github.com/grpc-ecosystem/go-grpc-prometheus"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/keepalive"
"k8s.io/helm/pkg/kube"
"k8s.io/helm/pkg/proto/hapi/services"
@ -57,6 +59,7 @@ const (
storageMemory = "memory"
storageConfigMap = "configmap"
storageSecret = "secret"
probeAddr = ":44135"
traceAddr = ":44136"
@ -68,7 +71,7 @@ const (
var (
grpcAddr = flag.String("listen", ":44134", "address:port to listen on")
enableTracing = flag.Bool("trace", false, "enable rpc tracing")
store = flag.String("storage", storageConfigMap, "storage driver to use. One of 'configmap' or 'memory'")
store = flag.String("storage", storageConfigMap, "storage driver to use. One of 'configmap', 'memory', or 'secret'")
remoteReleaseModules = flag.Bool("experimental-release", false, "enable experimental release modules")
tlsEnable = flag.Bool("tls", tlsEnableEnvVarDefault(), "enable TLS")
tlsVerify = flag.Bool("tls-verify", tlsVerifyEnvVarDefault(), "enable TLS and verify remote certificate")
@ -76,6 +79,7 @@ var (
certFile = flag.String("tls-cert", tlsDefaultsFromEnv("tls-cert"), "path to TLS certificate file")
caCertFile = flag.String("tls-ca-cert", tlsDefaultsFromEnv("tls-ca-cert"), "trust certificates signed by this CA")
maxHistory = flag.Int("history-max", historyMaxFromEnv(), "maximum number of releases kept in release history, with 0 meaning no limit")
printVersion = flag.Bool("version", false, "print the version number")
// rootServer is the root gRPC server.
//
@ -91,8 +95,14 @@ var (
)
func main() {
// TODO: use spf13/cobra for tiller instead of flags
flag.Parse()
if *printVersion {
fmt.Println(version.GetVersion())
os.Exit(0)
}
if *enableTracing {
log.SetFlags(log.Lshortfile)
}
@ -117,6 +127,12 @@ func start() {
env.Releases = storage.Init(cfgmaps)
env.Releases.Log = newLogger("storage").Printf
case storageSecret:
secrets := driver.NewSecrets(clientset.Core().Secrets(namespace()))
secrets.Log = newLogger("storage/driver").Printf
env.Releases = storage.Init(secrets)
env.Releases.Log = newLogger("storage").Printf
}
if *maxHistory > 0 {
@ -141,6 +157,10 @@ func start() {
logger.Fatalf("Could not create server TLS configuration: %v", err)
}
opts = append(opts, grpc.Creds(credentials.NewTLS(cfg)))
opts = append(opts, grpc.KeepaliveParams(keepalive.ServerParameters{
MaxConnectionIdle: 10 * time.Minute,
// If needed, we can configure the max connection age
}))
}
rootServer = tiller.NewServer(opts...)
@ -218,7 +238,11 @@ func tlsOptions() tlsutil.Options {
opts := tlsutil.Options{CertFile: *certFile, KeyFile: *keyFile}
if *tlsVerify {
opts.CaCertFile = *caCertFile
opts.ClientAuth = tls.VerifyClientCertIfGiven
// We want to force the client to not only provide a cert, but to
// provide a cert that we can validate.
// http://www.bite-code.com/2015/06/25/tls-mutual-auth-in-golang/
opts.ClientAuth = tls.RequireAndVerifyClientCert
}
return opts
}

@ -16,5 +16,6 @@ may find that their internal interests override our suggestions here.
- [Labels and Annotations](labels.md): Helm has a _heritage_ of labeling and annotating.
- Kubernetes Resources:
- [Pods and Pod Specs](pods.md): See the best practices for working with pod specifications.
- [Role-Based Access Control](rbac.md): Guidance on creating and using service accounts, roles, and role bindings.
- [Third Party Resources](third_party_resources.md): Third Party Resources (TPRs) have their own associated best practices.

@ -30,12 +30,21 @@ image: "{{ .Values.redisImage }}:{{ .Values.redisTag }}"
## ImagePullPolicy
The `imagePullPolicy` should default to an empty value, but allow users to override it:
`helm create` sets the `imagePullPolicy` to `IfNotPresent` by default by doing the following in your `deployment.yaml`:
```yaml
imagePullPolicy: {{ default "" .Values.imagePullPolicy | quote }}
imagePullPolicy: {{ .Values.image.pullPolicy }}
```
And `values.yaml`:
```yaml
pullPolicy: IfNotPresent
```
Similarly, Kubernetes defaults the `imagePullPolicy` to `IfNotPresent` if it is not defined at all. If you want a value other than `IfNotPresent`, simply update the value in `values.yaml` to your desired value.
## PodTemplates Should Declare Selectors
All PodTemplate sections should specify a selector. For example:

@ -0,0 +1,28 @@
# Role-Based Access Control
This part of the Best Practices Guide discusses the creation and formatting of RBAC resources in chart manifests.
RBAC resources are:
- ServiceAccount (namespaced)
- Role (namespaced)
- ClusterRole
- RoleBinding (namespaced)
- ClusterRoleBinding
## RBAC-related values
RBAC-related values in a chart should be namespaced under an `rbac` top-level key. At a minimum this key should contain these sub-keys (explained below):
- `create`
- `serviceAccountName`
Other keys under `rbac` may also be listed and used as well.
## RBAC Resources Should be Created by Default
`rbac.create` should be a boolean value controlling whether RBAC resources are created. The default should be `true`. Users who wish to manage RBAC access controls themselves can set this value to `false` (in which case see below).
## Using RBAC Resources
`rbac.serviceAccountName` should set the name of the ServiceAccount to be used by access-controlled resources created by the chart. If `rbac.create` is true, then a ServiceAccount with this name should be created. If `rbac.create` is false, then it should not be created, but it should still be associated with the same resources so that manually-created RBAC resources created later that reference it will function correctly. (Note that this effectively makes `rbac.serviceAccountName` a required value in these charts.)

@ -36,6 +36,7 @@ Incorrect:
{{/* ... */}}
{{ end -}}
```
It is highly recommended that new charts are created via `helm create` command as the template names are automatically defined as per this best practice.
## Formatting Templates

@ -7,6 +7,7 @@ Helm provides access to files through the `.Files` object. Before we get going w
- It is okay to add extra files to your Helm chart. These files will be bundled and sent to Tiller. Be careful, though. Charts must be smaller than 1M because of the storage limitations of Kubernetes objects.
- Some files cannot be accessed through the `.Files` object, usually for security reasons.
- Files in `templates/` cannot be accessed.
- Files excluded using `.helmignore` cannot be accessed.
- Charts do not preserve UNIX mode information, so file-level permissions will have no impact on the availability of a file when it comes to the `.Files` object.
<!-- (see https://github.com/jonschlinkert/markdown-toc) -->

@ -27,7 +27,7 @@ In the previous section, we use `{{.Release.Name}}` to insert the name of a rele
- `Capabilities.TillerVersion` provides a way to look up the Tiller version. It has the following values: `SemVer`, `GitCommit`, and `GitTreeState`.
- `Template`: Contains information about the current template that is being executed
- `Name`: A namespaced filepath to the current template (e.g. `mychart/templates/mytemplate.yaml`)
- `BasePath`: The namespaced path to the templates directory of the current chart (e.g. `mychart/templates`). This can be used to [include template files](https://github.com/kubernetes/helm/blob/master/docs/charts_tips_and_tricks.md#automatically-roll-deployments-when-configmaps-or-secrets-change)
- `BasePath`: The namespaced path to the templates directory of the current chart (e.g. `mychart/templates`).
The values are available to any top-level template. As we will see later, this does not necessarily mean that they will be available _everywhere_.

@ -96,6 +96,34 @@ data:
food: "pizza"
```
Variables are not "global". They are scoped to the block in which they are declared. Earlier, we assigned `$relname` in the top level of the template. That variable will be in scope for the entire template. But in our last example, `$key` and `$val` will only be in scope inside of the `{{range...}}{{end}}` block.
Variables are normally not "global". They are scoped to the block in which they are declared. Earlier, we assigned `$relname` in the top level of the template. That variable will be in scope for the entire template. But in our last example, `$key` and `$val` will only be in scope inside of the `{{range...}}{{end}}` block.
However, there is one variable that is always global - `$` - this
variable will always point to the root context. This can be very
useful when you are looping in a range need to know the chart's release
name.
An example illustrating this:
```yaml
{{- range .Values.tlsSecrets }}
apiVersion: v1
kind: Secret
metadata:
name: {{ .name }}
labels:
# Many helm templates would use `.` below, but that will not work,
# however `$` will work here
app: {{ template "fullname" $ }}
# I cannot reference .Chart.Name, but I can do $.Chart.Name
chart: "{{ $.Chart.Name }}-{{ $.Chart.Version }}"
release: "{{ $.Release.Name }}"
heritage: "{{ $.Release.Service }}"
type: kubernetes.io/tls
data:
tls.crt: {{ .certificate }}
tls.key: {{ .key }}
---
{{- end }}
```
So far we have looked at just one template declared in just one file. But one of the powerful features of the Helm template language is its ability to declare multiple templates and use them together. We'll turn to that in the next section.

@ -319,7 +319,7 @@ refer to that value by reference. YAML refers to this as "anchoring":
```yaml
coffee: "yes, please"
favorite: &favoriteCoffee "Cappucino"
coffess:
coffees:
- Latte
- *favoriteCoffee
- Espresso
@ -339,7 +339,7 @@ YAML would be:
```YAML
coffee: yes, please
favorite: Cappucino
coffess:
coffees:
- Latte
- Cappucino
- Espresso

@ -36,6 +36,8 @@ wordpress/
Helm reserves use of the `charts/` and `templates/` directories, and of
the listed file names. Other files will be left as they are.
While the `charts` and `template` directories are optional there must be at least one chart dependency or template file for the chart to be valid.
## The Chart.yaml File
The `Chart.yaml` file is required for a chart. It contains the following fields:
@ -52,6 +54,7 @@ sources:
maintainers: # (optional)
- name: The maintainer's name (required for each maintainer)
email: The maintainer's email (optional for each maintainer)
url: A URL for the maintainer (optional for each maintainer)
engine: gotpl # The name of the template engine (optional, defaults to gotpl)
icon: A URL to an SVG or PNG image to be used as an icon (optional).
appVersion: The version of the app that this contains (optional). This needn't be SemVer.
@ -449,6 +452,45 @@ directory.
**TIP:** _To drop a dependency into your `charts/` directory, use the
`helm fetch` command_
### Operational aspects of using dependencies
The above sections explain how to specify chart dependencies, but how does this affect
chart installation using `helm install` and `helm upgrade`?
Suppose that a chart named "A" creates the following Kubernetes objects
- namespace "A-Namespace"
- statefulset "A-StatefulSet"
- service "A-Service"
Furthermore, A is dependent on chart B that creates objects
- namespace "B-Namespace"
- replicaset "B-ReplicaSet"
- service "B-Service"
After installation/upgrade of chart A a single Helm release is created/modified. The release will
create/update all of the above Kubernetes objects in the following order:
- A-Namespace
- B-Namespace
- A-StatefulSet
- B-ReplicaSet
- A-Service
- B-Service
This is because when Helm installs/upgrades charts,
the Kubernetes objects from the charts and all its dependencies are
- aggregrated into a single set; then
- sorted by type followed by name; and then
- created/updated in that order.
Hence a single release is created with all the objects for the chart and its dependencies.
The install order of Kubernetes types is given by the enumeration InstallOrder in kind_sorter.go
(see [the Helm source file](https://github.com/kubernetes/helm/blob/master/pkg/tiller/kind_sorter.go#L26).
## Templates and Values
Helm Chart templates are written in the
@ -548,9 +590,10 @@ sensitive_.
`Chart.Maintainers`.
- `Files`: A map-like object containing all non-special files in the chart. This
will not give you access to templates, but will give you access to additional
files that are present. Files can be accessed using `{{index .Files "file.name"}}`
or using the `{{.Files.Get name}}` or `{{.Files.GetString name}}` functions. You can
also access the contents of the file as `[]byte` using `{{.Files.GetBytes}}`
files that are present (unless they are excluded using `.helmignore`). Files can be
accessed using `{{index .Files "file.name"}}` or using the `{{.Files.Get name}}` or
`{{.Files.GetString name}}` functions. You can also access the contents of the file
as `[]byte` using `{{.Files.GetBytes}}`
- `Capabilities`: A map-like object that contains information about the versions
of Kubernetes (`{{.Capabilities.KubeVersion}}`, Tiller
(`{{.Capabilities.TillerVersion}}`, and the supported Kubernetes API versions

@ -18,11 +18,11 @@ We also added two special template functions: `include` and `required`. The `inc
function allows you to bring in another template, and then pass the results to other
template functions.
For example, this template snippet includes a template called `mytpl.tpl`, then
For example, this template snippet includes a template called `mytpl`, then
lowercases the result, then wraps that in double quotes.
```yaml
value: {{include "mytpl.tpl" . | lower | quote}}
value: {{include "mytpl" . | lower | quote}}
```
The `required` function allows you to declare a particular
@ -96,6 +96,35 @@ For example:
The above will render the template when .Values.foo is defined, but will fail
to render and exit when .Values.foo is undefined.
## Creating Image Pull Secrets
Image pull secrets are essentially a combination of _registry_, _username_, and _password_. You may need them in an application you are deploying, but to create them requires running _base64_ a couple of times. We can write a helper template to compose the Docker configuration file for use as the Secret's payload. Here is an example:
First, assume that the credentials are defined in the `values.yaml` file like so:
```
imageCredentials:
registry: quay.io
username: someone
password: sillyness
```
We then define our helper template as follows:
```
{{- define "imagePullSecret" }}
{{- printf "{\"auths\": {\"%s\": {\"auth\": \"%s\"}}}" .Values.imageCredentials.registry (printf "%s:%s" .Values.imageCredentials.username .Values.imageCredentials.password | b64enc) | b64enc }}
{{- end }}
```
Finally, we use the helper template in a larger template to create the Secret manifest:
```
apiVersion: v1
kind: Secret
metadata:
name: myregistrykey
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: {{ template "imagePullSecret" . }}
```
## Automatically Roll Deployments When ConfigMaps or Secrets change
Often times configmaps or secrets are injected as configuration
@ -105,9 +134,8 @@ be updated with a subsequent `helm upgrade`, but if the
deployment spec itself didn't change the application keeps running
with the old configuration resulting in an inconsistent deployment.
The `sha256sum` function can be used together with the `include`
function to ensure a deployments template section is updated if another
spec changes:
The `sha256sum` function can be used to ensure a deployment's
annotation section is updated if another file changes:
```yaml
kind: Deployment
@ -115,10 +143,13 @@ spec:
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
[...]
```
See also the `helm upgrade --recreate-pods` flag for a slightly
different way of addressing this issue.
## Tell Tiller Not To Delete a Resource
Sometimes there are resources that should not be deleted when Helm runs a
@ -200,3 +231,10 @@ cryptographic keys, and so on. These are fine to use. But be aware that
during upgrades, templates are re-executed. When a template run
generates data that differs from the last run, that will trigger an
update of that resource.
## Upgrade a release idempotently
In order to use the same command when installing and upgrading a release, use the following comand:
```shell
helm upgrade --install <release name> --values <values file> <chart directory>
```

@ -5,10 +5,9 @@ Helm and Tiller.
## Prerequisites
- Go 1.6.0 or later
- Glide 0.12.0 or later
- kubectl 1.2 or later
- A Kubernetes cluster (optional)
- The latest version of Go
- The latest version of Glide
- A Kubernetes cluster w/ kubectl (optional)
- The gRPC toolchain
- Git
- Mercurial

@ -2,7 +2,7 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "name" -}}
{{- define "alpine.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
@ -10,7 +10,7 @@ Expand the name of the chart.
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
*/}}
{{- define "fullname" -}}
{{- define "alpine.fullname" -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}

@ -1,7 +1,7 @@
apiVersion: v1
kind: Pod
metadata:
name: {{ template "fullname" . }}
name: {{ template "alpine.fullname" . }}
labels:
# The "heritage" label is used to track which tool deployed a given chart.
# It is useful for admins who want to see what releases a particular tool
@ -12,7 +12,7 @@ metadata:
release: {{ .Release.Name }}
# This makes it easy to audit chart usage.
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app: {{ template "name" . }}
app: {{ template "alpine.name" . }}
spec:
# This shows how to use a simple value. This will look for a passed-in value called restartPolicy.
restartPolicy: {{ .Values.restartPolicy }}

@ -2,7 +2,7 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "name" -}}
{{- define "nginx.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
@ -10,7 +10,7 @@ Expand the name of the chart.
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
*/}}
{{- define "fullname" -}}
{{- define "nginx.fullname" -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}

@ -2,12 +2,12 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ template "fullname" . }}
name: {{ template "nginx.fullname" . }}
labels:
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app: {{ template "name" . }}
app: {{ template "nginx.name" . }}
data:
# When the config map is mounted as a volume, these will be created as files.
index.html: {{ .Values.index | quote }}

@ -4,7 +4,7 @@ metadata:
# This uses a "fullname" template (see _helpers)
# Basing names on .Release.Name means that the same chart can be installed
# multiple times into the same namespace.
name: {{ template "fullname" . }}
name: {{ template "nginx.fullname" . }}
labels:
# The "heritage" label is used to track which tool deployed a given chart.
# It is useful for admins who want to see what releases a particular tool
@ -15,7 +15,7 @@ metadata:
release: {{ .Release.Name }}
# This makes it easy to audit chart usage.
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app: {{ template "name" . }}
app: {{ template "nginx.name" . }}
spec:
replicas: {{ .Values.replicaCount }}
template:
@ -26,11 +26,11 @@ spec:
{{ toYaml .Values.podAnnotations | indent 8 }}
{{- end }}
labels:
app: {{ template "name" . }}
app: {{ template "nginx.name" . }}
release: {{ .Release.Name }}
spec:
containers:
- name: {{ template "name" . }}
- name: {{ template "nginx.name" . }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
@ -54,4 +54,4 @@ spec:
volumes:
- name: wwwdata-volume
configMap:
name: {{ template "fullname" . }}
name: {{ template "nginx.fullname" . }}

@ -1,7 +1,7 @@
apiVersion: batch/v1
kind: Job
metadata:
name: {{ template "fullname" . }}
name: {{ template "nginx.fullname" . }}
labels:
# The "heritage" label is used to track which tool deployed a given chart.
# It is useful for admins who want to see what releases a particular tool
@ -12,7 +12,7 @@ metadata:
release: {{ .Release.Name }}
# This makes it easy to audit chart usage.
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app: {{ template "name" . }}
app: {{ template "nginx.name" . }}
annotations:
# This is what defines this resource as a hook. Without this line, the
# job is considered part of the release.
@ -20,10 +20,10 @@ metadata:
spec:
template:
metadata:
name: {{ template "fullname" . }}
name: {{ template "nginx.fullname" . }}
labels:
release: {{ .Release.Name }}
app: {{ template "name" . }}
app: {{ template "nginx.name" . }}
spec:
# This shows how to use a simple value. This will look for a passed-in value
# called restartPolicy. If it is not found, it will use the default value.

@ -3,12 +3,12 @@
apiVersion: v1
kind: Secret
metadata:
name: {{ template "fullname" . }}
name: {{ template "nginx.fullname" . }}
labels:
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app: {{ template "name" . }}
app: {{ template "nginx.name" . }}
# This declares the resource to be a hook. By convention, we also name the
# file "pre-install-XXX.yaml", but Helm itself doesn't care about file names.
annotations:

@ -1,12 +1,12 @@
apiVersion: v1
kind: Pod
metadata:
name: "{{ template "fullname" . }}-service-test"
name: "{{ template "nginx.fullname" . }}-service-test"
labels:
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app: {{ template "name" . }}
app: {{ template "nginx.name" . }}
annotations:
"helm.sh/hook": test-success
spec:
@ -14,5 +14,5 @@ spec:
- name: curl
image: radial/busyboxplus:curl
command: ['curl']
args: ['{{ template "fullname" . }}:{{ .Values.service.port }}']
args: ['{{ template "nginx.fullname" . }}:{{ .Values.service.port }}']
restartPolicy: Never

@ -6,11 +6,11 @@ metadata:
{{ toYaml .Values.service.annotations | indent 4 }}
{{- end }}
labels:
app: {{ template "name" . }}
app: {{ template "nginx.name" . }}
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
name: {{ template "fullname" . }}
name: {{ template "nginx.fullname" . }}
spec:
# Provides options for the service so chart users have the full choice
type: "{{ .Values.service.type }}"
@ -35,5 +35,5 @@ spec:
nodePort: {{ .Values.service.nodePort }}
{{- end }}
selector:
app: {{ template "name" . }}
app: {{ template "nginx.name" . }}
release: {{ .Release.Name }}

@ -33,9 +33,10 @@ Environment:
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
@ -67,4 +68,4 @@ Environment:
* [helm verify](helm_verify.md) - verify that a chart at the given path has been signed and is valid
* [helm version](helm_version.md) - print the client/server version information
###### Auto generated by spf13/cobra on 8-Aug-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -25,13 +25,14 @@ helm completion SHELL
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm](helm.md) - The Helm package manager for Kubernetes.
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -44,13 +44,14 @@ helm create NAME
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm](helm.md) - The Helm package manager for Kubernetes.
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -35,13 +35,14 @@ helm delete [flags] RELEASE_NAME [...]
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm](helm.md) - The Helm package manager for Kubernetes.
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -58,9 +58,10 @@ for this case.
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
@ -70,4 +71,4 @@ for this case.
* [helm dependency list](helm_dependency_list.md) - list the dependencies for the given chart
* [helm dependency update](helm_dependency_update.md) - update charts/ based on the contents of requirements.yaml
###### Auto generated by spf13/cobra on 11-Jul-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -31,13 +31,14 @@ helm dependency build [flags] CHART
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm dependency](helm_dependency.md) - manage a chart's dependencies
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -23,13 +23,14 @@ helm dependency list [flags] CHART
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm dependency](helm_dependency.md) - manage a chart's dependencies
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -36,13 +36,14 @@ helm dependency update [flags] CHART
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm dependency](helm_dependency.md) - manage a chart's dependencies
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -30,7 +30,7 @@ helm fetch [flags] [chart URL | repo/chartname] [...]
--ca-file string verify certificates of HTTPS-enabled servers using this CA bundle
--cert-file string identify HTTPS client using this SSL certificate file
-d, --destination string location to write the chart. If this and tardir are specified, tardir is appended to this (default ".")
--devel use development versions, too. Equivalent to version '>0.0.0-a'. If --version is set, this is ignored.
--devel use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored.
--key-file string identify HTTPS client using this SSL key file
--keyring string keyring containing public keys (default "~/.gnupg/pubring.gpg")
--prov fetch the provenance file, but don't perform verification
@ -45,13 +45,14 @@ helm fetch [flags] [chart URL | repo/chartname] [...]
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm](helm.md) - The Helm package manager for Kubernetes.
###### Auto generated by spf13/cobra on 17-Aug-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -37,9 +37,10 @@ helm get [flags] RELEASE_NAME
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
@ -49,4 +50,4 @@ helm get [flags] RELEASE_NAME
* [helm get manifest](helm_get_manifest.md) - download the manifest for a named release
* [helm get values](helm_get_values.md) - download the values file for a named release
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -19,19 +19,25 @@ helm get hooks [flags] RELEASE_NAME
```
--revision int32 get the named release with revision
--tls enable TLS for request
--tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem")
--tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem")
--tls-key string path to TLS key file (default "$HELM_HOME/key.pem")
--tls-verify enable TLS for request and verify remote
```
### Options inherited from parent commands
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm get](helm_get.md) - download a named release
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 15-Nov-2017

@ -21,19 +21,25 @@ helm get manifest [flags] RELEASE_NAME
```
--revision int32 get the named release with revision
--tls enable TLS for request
--tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem")
--tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem")
--tls-key string path to TLS key file (default "$HELM_HOME/key.pem")
--tls-verify enable TLS for request and verify remote
```
### Options inherited from parent commands
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm get](helm_get.md) - download a named release
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 15-Nov-2017

@ -18,19 +18,25 @@ helm get values [flags] RELEASE_NAME
```
-a, --all dump all (computed) values
--revision int32 get the named release with revision
--tls enable TLS for request
--tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem")
--tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem")
--tls-key string path to TLS key file (default "$HELM_HOME/key.pem")
--tls-verify enable TLS for request and verify remote
```
### Options inherited from parent commands
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm get](helm_get.md) - download a named release
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 15-Nov-2017

@ -40,13 +40,14 @@ helm history [flags] RELEASE_NAME
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm](helm.md) - The Helm package manager for Kubernetes.
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -18,13 +18,14 @@ helm home
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm](helm.md) - The Helm package manager for Kubernetes.
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -39,6 +39,9 @@ helm init
--history-max int limit the maximum number of revisions saved per release. Use 0 for no limit.
--local-repo-url string URL for local repository (default "http://127.0.0.1:8879/charts")
--net-host install Tiller with net=host
--node-selectors string labels to specify the node on which Tiller is installed (app=tiller,helm=rocks)
-o, --output OutputFormat skip installation and output Tiller's manifest in specified format (json or yaml)
--override stringArray override values for the Tiller Deployment manifest (can specify multiple or separate values with commas: key1=val1,key2=val2)
--service-account string name of service account
--skip-refresh do not refresh (download) the local repository cache
--stable-repo-url string URL for stable repository (default "https://kubernetes-charts.storage.googleapis.com")
@ -55,13 +58,14 @@ helm init
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm](helm.md) - The Helm package manager for Kubernetes.
###### Auto generated by spf13/cobra on 10-Aug-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -32,9 +32,10 @@ helm inspect [CHART]
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
@ -43,4 +44,4 @@ helm inspect [CHART]
* [helm inspect chart](helm_inspect_chart.md) - shows inspect chart
* [helm inspect values](helm_inspect_values.md) - shows inspect values
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -30,13 +30,14 @@ helm inspect chart [CHART]
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm inspect](helm_inspect.md) - inspect a chart
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -30,13 +30,14 @@ helm inspect values [CHART]
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm inspect](helm_inspect.md) - inspect a chart
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -37,21 +37,22 @@ To check the generated manifests of a release without installing the chart,
the '--debug' and '--dry-run' flags can be combined. This will still require a
round-trip to the Tiller server.
If --verify is set, the chart MUST have a provenance file, and the provenenace
fall MUST pass all verification steps.
If --verify is set, the chart MUST have a provenance file, and the provenance
file MUST pass all verification steps.
There are four different ways you can express the chart you want to install:
There are five different ways you can express the chart you want to install:
1. By chart reference: helm install stable/mariadb
2. By path to a packaged chart: helm install ./nginx-1.2.3.tgz
3. By path to an unpacked chart directory: helm install ./nginx
4. By absolute URL: helm install https://example.com/charts/nginx-1.2.3.tgz
5. By chart reference and repo url: helm install --repo https://example.com/charts/ nginx
CHART REFERENCES
A chart reference is a convenient way of reference a chart in a chart repository.
When you use a chart reference ('stable/mariadb'), Helm will look in the local
When you use a chart reference with a repo prefix ('stable/mariadb'), Helm will look in the local
configuration for a chart repository named 'stable', and will then look for a
chart in that repository whose name is 'mariadb'. It will install the latest
version of that chart unless you also supply a version number with the
@ -70,7 +71,8 @@ helm install [CHART]
```
--ca-file string verify certificates of HTTPS-enabled servers using this CA bundle
--cert-file string identify HTTPS client using this SSL certificate file
--devel use development versions, too. Equivalent to version '>0.0.0-a'. If --version is set, this is ignored.
--dep-up run helm dependency update before installing the chart
--devel use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored.
--dry-run simulate an install
--key-file string identify HTTPS client using this SSL key file
--keyring string location of public keys used for verification (default "~/.gnupg/pubring.gpg")
@ -87,7 +89,7 @@ helm install [CHART]
--tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem")
--tls-key string path to TLS key file (default "$HELM_HOME/key.pem")
--tls-verify enable TLS for request and verify remote
-f, --values valueFiles specify values in a YAML file (can specify multiple) (default [])
-f, --values valueFiles specify values in a YAML file or a URL(can specify multiple) (default [])
--verify verify the package before installing it
--version string specify the exact chart version to install. If this is not specified, the latest version is installed
--wait if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment are in a ready state before marking the release as successful. It will wait for as long as --timeout
@ -97,13 +99,14 @@ helm install [CHART]
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm](helm.md) - The Helm package manager for Kubernetes.
###### Auto generated by spf13/cobra on 15-Aug-2017
###### Auto generated by spf13/cobra on 23-Nov-2017

@ -28,13 +28,14 @@ helm lint [flags] PATH
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm](helm.md) - The Helm package manager for Kubernetes.
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -62,13 +62,14 @@ helm list [flags] [FILTER]
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm](helm.md) - The Helm package manager for Kubernetes.
###### Auto generated by spf13/cobra on 12-Jul-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -23,6 +23,7 @@ helm package [flags] [CHART_PATH] [...]
### Options
```
--app-version string set the appVersion on the chart to this version
-u, --dependency-update update dependencies from "requirements.yaml" to dir "charts/" before packaging
-d, --destination string location to write the chart. (default ".")
--key string name of the key to use when signing. Used if --sign is true
@ -36,13 +37,14 @@ helm package [flags] [CHART_PATH] [...]
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm](helm.md) - The Helm package manager for Kubernetes.
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 24-Nov-2017

@ -13,9 +13,10 @@ Manage client-side Helm plugins.
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
@ -26,4 +27,4 @@ Manage client-side Helm plugins.
* [helm plugin remove](helm_plugin_remove.md) - remove one or more Helm plugins
* [helm plugin update](helm_plugin_update.md) - update one or more Helm plugins
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -5,7 +5,12 @@ install one or more Helm plugins
### Synopsis
install one or more Helm plugins
This command allows you to install a plugin from a url to a VCS repo or a local path.
Example usage:
$ helm plugin install https://github.com/technosophos/helm-template
```
helm plugin install [options] <path|url>...
@ -21,13 +26,14 @@ helm plugin install [options] <path|url>...
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm plugin](helm_plugin.md) - add, list, or remove Helm plugins
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 20-Nov-2017

@ -15,13 +15,14 @@ helm plugin list
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm plugin](helm_plugin.md) - add, list, or remove Helm plugins
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -15,13 +15,14 @@ helm plugin remove <plugin>...
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm plugin](helm_plugin.md) - add, list, or remove Helm plugins
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -15,13 +15,14 @@ helm plugin update <plugin>...
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm plugin](helm_plugin.md) - add, list, or remove Helm plugins
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -17,9 +17,10 @@ Example usage:
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
@ -31,4 +32,4 @@ Example usage:
* [helm repo remove](helm_repo_remove.md) - remove a chart repository
* [helm repo update](helm_repo_update.md) - update information of available charts locally from chart repositories
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -24,13 +24,14 @@ helm repo add [flags] [NAME] [URL]
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm repo](helm_repo.md) - add, list, remove, update, and index chart repositories
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -31,13 +31,14 @@ helm repo index [flags] [DIR]
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm repo](helm_repo.md) - add, list, remove, update, and index chart repositories
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -15,13 +15,14 @@ helm repo list [flags]
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm repo](helm_repo.md) - add, list, remove, update, and index chart repositories
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -15,13 +15,14 @@ helm repo remove [flags] [NAME]
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm repo](helm_repo.md) - add, list, remove, update, and index chart repositories
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -21,13 +21,14 @@ helm repo update
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm repo](helm_repo.md) - add, list, remove, update, and index chart repositories
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -31,13 +31,14 @@ helm reset
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm](helm.md) - The Helm package manager for Kubernetes.
###### Auto generated by spf13/cobra on 27-Jun-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -37,13 +37,14 @@ helm rollback [flags] [RELEASE] [REVISION]
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm](helm.md) - The Helm package manager for Kubernetes.
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -28,13 +28,14 @@ helm search [keyword]
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm](helm.md) - The Helm package manager for Kubernetes.
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -36,13 +36,14 @@ helm serve
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm](helm.md) - The Helm package manager for Kubernetes.
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -35,13 +35,14 @@ helm status [flags] RELEASE_NAME
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm](helm.md) - The Helm package manager for Kubernetes.
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

@ -31,6 +31,7 @@ helm template [flags] CHART
--name-template string specify template used to name the release
--namespace string namespace to install the release into
--notes show the computed NOTES.txt file as well
--output-dir string writes the executed templates to files in output-dir instead of stdout
--set stringArray set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)
-f, --values valueFiles specify values in a YAML file (can specify multiple) (default [])
```
@ -39,13 +40,14 @@ helm template [flags] CHART
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm](helm.md) - The Helm package manager for Kubernetes.
###### Auto generated by spf13/cobra on 11-Sep-2017
###### Auto generated by spf13/cobra on 15-Nov-2017

@ -32,13 +32,14 @@ helm test [RELEASE]
```
--debug enable verbose output
--home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm")
--home string location of your Helm config. Overrides $HELM_HOME (default "~/.helm")
--host string address of Tiller. Overrides $HELM_HOST
--kube-context string name of the kubeconfig context to use
--kubeconfig string path to kubeconfig file. Overrides $KUBECONFIG
--tiller-namespace string namespace of Tiller (default "kube-system")
```
### SEE ALSO
* [helm](helm.md) - The Helm package manager for Kubernetes.
###### Auto generated by spf13/cobra on 23-Jun-2017
###### Auto generated by spf13/cobra on 7-Nov-2017

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save