From e4c5802cbc994e15f81dd62d0fdf0b55e720a926 Mon Sep 17 00:00:00 2001 From: Dmitry Shulyak Date: Fri, 18 Aug 2017 12:51:15 +0300 Subject: [PATCH 001/107] Allow to specify socket for rudder grpc server os args will be used to specify grpc server socket, either --listen or -l can be used as an argument to rudder binary --- cmd/rudder/rudder.go | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/cmd/rudder/rudder.go b/cmd/rudder/rudder.go index e1ba4736a..30ece3998 100644 --- a/cmd/rudder/rudder.go +++ b/cmd/rudder/rudder.go @@ -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 From c77a90a240e2e2822a98e71315dc79df976d7bdf Mon Sep 17 00:00:00 2001 From: xuhaigang Date: Mon, 7 Aug 2017 14:42:41 +0800 Subject: [PATCH 002/107] feat(helm):Allow remote values.yaml with -f In this feature, we can use -f option with remote files, same as kubectl accepts URLs. I add an option to send a 'get' request when read the local file failed. Closes #2642 --- cmd/helm/install.go | 26 ++++++++++++++++++++++++-- cmd/helm/upgrade.go | 2 +- docs/helm/helm_install.md | 2 +- docs/helm/helm_upgrade.md | 2 +- docs/man/man1/helm_install.1 | 2 +- docs/man/man1/helm_upgrade.1 | 2 +- 6 files changed, 29 insertions(+), 7 deletions(-) diff --git a/cmd/helm/install.go b/cmd/helm/install.go index 7e59333b6..3a81ad3c5 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -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 = ` @@ -175,7 +176,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") f.BoolVar(&inst.dryRun, "dry-run", false, "simulate an install") @@ -316,8 +317,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 } @@ -469,3 +471,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 + } +} diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go index 989d73cdd..ce3fcdaa3 100644 --- a/cmd/helm/upgrade.go +++ b/cmd/helm/upgrade.go @@ -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") diff --git a/docs/helm/helm_install.md b/docs/helm/helm_install.md index 0a4cb48e8..166ade17e 100644 --- a/docs/helm/helm_install.md +++ b/docs/helm/helm_install.md @@ -87,7 +87,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 diff --git a/docs/helm/helm_upgrade.md b/docs/helm/helm_upgrade.md index 934cadd13..0d52987d2 100644 --- a/docs/helm/helm_upgrade.md +++ b/docs/helm/helm_upgrade.md @@ -57,7 +57,7 @@ helm upgrade [RELEASE] [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 provenance of the chart before upgrading --version string specify the exact chart version to use. If this is not specified, the latest version is used --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 diff --git a/docs/man/man1/helm_install.1 b/docs/man/man1/helm_install.1 index 8fe99acb3..3c315612d 100644 --- a/docs/man/man1/helm_install.1 +++ b/docs/man/man1/helm_install.1 @@ -192,7 +192,7 @@ charts in a repository, use 'helm search'. .PP \fB\-f\fP, \fB\-\-values\fP=[] - specify values in a YAML file (can specify multiple) + specify values in a YAML file or a URL(can specify multiple) .PP \fB\-\-verify\fP[=false] diff --git a/docs/man/man1/helm_upgrade.1 b/docs/man/man1/helm_upgrade.1 index 5d5e919f6..24bba7c85 100644 --- a/docs/man/man1/helm_upgrade.1 +++ b/docs/man/man1/helm_upgrade.1 @@ -143,7 +143,7 @@ $ helm upgrade \-\-set foo=bar \-\-set foo=newbar redis ./redis .PP \fB\-f\fP, \fB\-\-values\fP=[] - specify values in a YAML file (can specify multiple) + specify values in a YAML file or a URL(can specify multiple) .PP \fB\-\-verify\fP[=false] From bed80e482c7de628ae4001e7077210f1cb3b9574 Mon Sep 17 00:00:00 2001 From: Maxim Ivanov Date: Wed, 27 Sep 2017 13:14:19 +0100 Subject: [PATCH 003/107] When looking for original resource on update/delete, ignore Apiversion, use Kind and Name only Kind can change it's APIVersion with time, such as "Deployment" which was "extensions/v1beta1" and then migrated to "apps/v1beta1" in Kube 1.6. Name, Kind and optinally Namespace are used to find relevant Info object for a original resource which is being upgraded, it safe enough, as it is uniquely identifies an object. --- pkg/kube/result.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/kube/result.go b/pkg/kube/result.go index 9f143feb5..87c7e6ac1 100644 --- a/pkg/kube/result.go +++ b/pkg/kube/result.go @@ -83,5 +83,5 @@ func (r Result) Intersect(rs Result) Result { // isMatchingInfo returns true if infos match on Name and GroupVersionKind. func isMatchingInfo(a, b *resource.Info) bool { - return a.Name == b.Name && a.Mapping.GroupVersionKind == b.Mapping.GroupVersionKind + return a.Name == b.Name && a.Mapping.GroupVersionKind.Kind == b.Mapping.GroupVersionKind.Kind } From ea0a842f746ae5960ea3a747f0a68e94187a53cd Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Fri, 29 Sep 2017 14:26:43 -0700 Subject: [PATCH 004/107] use the latest version of Go/Glide Also point out that kubectl is an optional component of the development workflow. --- docs/developers.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/developers.md b/docs/developers.md index e0aeb374a..25549537a 100644 --- a/docs/developers.md +++ b/docs/developers.md @@ -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 From a28e5dd2b30caad633834d132a61d754a0479676 Mon Sep 17 00:00:00 2001 From: Nandor Kracser Date: Tue, 3 Oct 2017 12:01:49 +0200 Subject: [PATCH 005/107] fix(helm): invoking getterConstructor returns downstream error now --- pkg/repo/chartrepo.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/repo/chartrepo.go b/pkg/repo/chartrepo.go index 97506e607..d69280223 100644 --- a/pkg/repo/chartrepo.go +++ b/pkg/repo/chartrepo.go @@ -62,7 +62,7 @@ func NewChartRepository(cfg *Entry, getters getter.Providers) (*ChartRepository, } client, err := getterConstructor(cfg.URL, cfg.CertFile, cfg.KeyFile, cfg.CAFile) if err != nil { - return nil, fmt.Errorf("Could not construct protocol handler for: %s", u.Scheme) + return nil, fmt.Errorf("Could not construct protocol handler for: %s error: %v", u.Scheme, err) } return &ChartRepository{ From dad8c6f644b618983c7b6eca8146d736c73d04fd Mon Sep 17 00:00:00 2001 From: Michal Cwienczek Date: Fri, 6 Oct 2017 16:59:11 +0200 Subject: [PATCH 006/107] Fix #2937 - helm always appends /index.yaml at the end of URL (#2988) * Closes #2937 Added required dependency to run make test in developer's guide * Fixed base URL appending when chart address is not absolute * Removed requirement from developers.md * Fixed unnecessary line breaks * Added tests for query string repo * Returning URL along with error --- pkg/downloader/chart_downloader.go | 7 ++++++- pkg/downloader/chart_downloader_test.go | 1 + .../cache/testing-querystring-index.yaml | 16 ++++++++++++++++ .../helmhome/repository/repositories.yaml | 2 ++ pkg/repo/chartrepo.go | 7 ++++++- 5 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 pkg/downloader/testdata/helmhome/repository/cache/testing-querystring-index.yaml diff --git a/pkg/downloader/chart_downloader.go b/pkg/downloader/chart_downloader.go index 15e97f6a1..a8a1b5a57 100644 --- a/pkg/downloader/chart_downloader.go +++ b/pkg/downloader/chart_downloader.go @@ -217,7 +217,12 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, ge // If the URL is relative (no scheme), prepend the chart repo's base URL if !u.IsAbs() { - u, err = url.Parse(rc.URL + "/" + u.Path) + path := u.Path + u, err = url.Parse(rc.URL) + if err != nil { + return u, r.Client, err + } + u.Path = u.Path + path return u, r.Client, err } diff --git a/pkg/downloader/chart_downloader_test.go b/pkg/downloader/chart_downloader_test.go index 4049b7979..73f9191c9 100644 --- a/pkg/downloader/chart_downloader_test.go +++ b/pkg/downloader/chart_downloader_test.go @@ -43,6 +43,7 @@ func TestResolveChartRef(t *testing.T) { {name: "reference, testing repo", ref: "testing/alpine", expect: "http://example.com/alpine-1.2.3.tgz"}, {name: "reference, version, testing repo", ref: "testing/alpine", version: "0.2.0", expect: "http://example.com/alpine-0.2.0.tgz"}, {name: "reference, version, malformed repo", ref: "malformed/alpine", version: "1.2.3", expect: "http://dl.example.com/alpine-1.2.3.tgz"}, + {name: "reference, querystring repo", ref: "testing-querystring/alpine", expect: "http://example.com/alpine-1.2.3.tgz?key=value"}, {name: "full URL, HTTPS, irrelevant version", ref: "https://example.com/foo-1.2.3.tgz", version: "0.1.0", expect: "https://example.com/foo-1.2.3.tgz", fail: true}, {name: "full URL, file", ref: "file:///foo-1.2.3.tgz", fail: true}, {name: "invalid", ref: "invalid-1.2.3", fail: true}, diff --git a/pkg/downloader/testdata/helmhome/repository/cache/testing-querystring-index.yaml b/pkg/downloader/testdata/helmhome/repository/cache/testing-querystring-index.yaml new file mode 100644 index 000000000..1956e9f83 --- /dev/null +++ b/pkg/downloader/testdata/helmhome/repository/cache/testing-querystring-index.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +entries: + alpine: + - name: alpine + urls: + - alpine-1.2.3.tgz + checksum: 0e6661f193211d7a5206918d42f5c2a9470b737d + home: https://k8s.io/helm + sources: + - https://github.com/kubernetes/helm + version: 1.2.3 + description: Deploy a basic Alpine Linux pod + keywords: [] + maintainers: [] + engine: "" + icon: "" diff --git a/pkg/downloader/testdata/helmhome/repository/repositories.yaml b/pkg/downloader/testdata/helmhome/repository/repositories.yaml index 9b0cfe972..68efb461a 100644 --- a/pkg/downloader/testdata/helmhome/repository/repositories.yaml +++ b/pkg/downloader/testdata/helmhome/repository/repositories.yaml @@ -10,3 +10,5 @@ repositories: url: "http://example.com/charts" - name: malformed url: "http://dl.example.com" + - name: testing-querystring + url: "http://example.com?key=value" \ No newline at end of file diff --git a/pkg/repo/chartrepo.go b/pkg/repo/chartrepo.go index 97506e607..e7283dc10 100644 --- a/pkg/repo/chartrepo.go +++ b/pkg/repo/chartrepo.go @@ -110,8 +110,13 @@ func (r *ChartRepository) Load() error { // is for pre-2.2.0 repo files. func (r *ChartRepository) DownloadIndexFile(cachePath string) error { var indexURL string + parsedURL, err := url.Parse(r.Config.URL) + if err != nil { + return err + } + parsedURL.Path = strings.TrimSuffix(parsedURL.Path, "/") + "/index.yaml" - indexURL = strings.TrimSuffix(r.Config.URL, "/") + "/index.yaml" + indexURL = parsedURL.String() resp, err := r.Client.Get(indexURL) if err != nil { return err From 67af4998ded798fb602ec16770a72213c063985a Mon Sep 17 00:00:00 2001 From: Dhilip Date: Fri, 6 Oct 2017 20:34:53 +0530 Subject: [PATCH 007/107] =?UTF-8?q?helm=20create=20all=20defined=20templat?= =?UTF-8?q?e=20names=20should=20be=20namespaced=20=E2=80=A6=20(#2845)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * helm create all defined template names should be namespaced https://docs.helm.sh/chart_best_practices/#names-of-defined-templates * Update Doc * Update example --- docs/chart_best_practices/templates.md | 1 + docs/examples/alpine/templates/_helpers.tpl | 4 +- .../examples/alpine/templates/alpine-pod.yaml | 4 +- docs/examples/nginx/templates/_helpers.tpl | 4 +- docs/examples/nginx/templates/configmap.yaml | 4 +- docs/examples/nginx/templates/deployment.yaml | 10 ++--- .../nginx/templates/post-install-job.yaml | 8 ++-- .../nginx/templates/pre-install-secret.yaml | 4 +- .../nginx/templates/service-test.yaml | 6 +-- docs/examples/nginx/templates/service.yaml | 6 +-- pkg/chartutil/create.go | 41 ++++++++++--------- 11 files changed, 47 insertions(+), 45 deletions(-) diff --git a/docs/chart_best_practices/templates.md b/docs/chart_best_practices/templates.md index db1259246..c9995ea0a 100644 --- a/docs/chart_best_practices/templates.md +++ b/docs/chart_best_practices/templates.md @@ -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 diff --git a/docs/examples/alpine/templates/_helpers.tpl b/docs/examples/alpine/templates/_helpers.tpl index f0d83d2ed..3e9c25bed 100644 --- a/docs/examples/alpine/templates/_helpers.tpl +++ b/docs/examples/alpine/templates/_helpers.tpl @@ -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 -}} diff --git a/docs/examples/alpine/templates/alpine-pod.yaml b/docs/examples/alpine/templates/alpine-pod.yaml index 14995675e..da9caef78 100644 --- a/docs/examples/alpine/templates/alpine-pod.yaml +++ b/docs/examples/alpine/templates/alpine-pod.yaml @@ -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 }} diff --git a/docs/examples/nginx/templates/_helpers.tpl b/docs/examples/nginx/templates/_helpers.tpl index f0d83d2ed..2ec6ba757 100644 --- a/docs/examples/nginx/templates/_helpers.tpl +++ b/docs/examples/nginx/templates/_helpers.tpl @@ -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 -}} diff --git a/docs/examples/nginx/templates/configmap.yaml b/docs/examples/nginx/templates/configmap.yaml index 641e62ea4..b90d6c0c7 100644 --- a/docs/examples/nginx/templates/configmap.yaml +++ b/docs/examples/nginx/templates/configmap.yaml @@ -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 }} diff --git a/docs/examples/nginx/templates/deployment.yaml b/docs/examples/nginx/templates/deployment.yaml index ca929c278..5fa2633ea 100644 --- a/docs/examples/nginx/templates/deployment.yaml +++ b/docs/examples/nginx/templates/deployment.yaml @@ -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" . }} diff --git a/docs/examples/nginx/templates/post-install-job.yaml b/docs/examples/nginx/templates/post-install-job.yaml index 06e7024f2..9ec90cd0a 100644 --- a/docs/examples/nginx/templates/post-install-job.yaml +++ b/docs/examples/nginx/templates/post-install-job.yaml @@ -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. diff --git a/docs/examples/nginx/templates/pre-install-secret.yaml b/docs/examples/nginx/templates/pre-install-secret.yaml index 405f4e531..6392f9684 100644 --- a/docs/examples/nginx/templates/pre-install-secret.yaml +++ b/docs/examples/nginx/templates/pre-install-secret.yaml @@ -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: diff --git a/docs/examples/nginx/templates/service-test.yaml b/docs/examples/nginx/templates/service-test.yaml index 107b19a79..3913ead9c 100644 --- a/docs/examples/nginx/templates/service-test.yaml +++ b/docs/examples/nginx/templates/service-test.yaml @@ -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 diff --git a/docs/examples/nginx/templates/service.yaml b/docs/examples/nginx/templates/service.yaml index bad29b14e..1481e34f0 100644 --- a/docs/examples/nginx/templates/service.yaml +++ b/docs/examples/nginx/templates/service.yaml @@ -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 }} diff --git a/pkg/chartutil/create.go b/pkg/chartutil/create.go index fe06e14e0..5fb3834ef 100644 --- a/pkg/chartutil/create.go +++ b/pkg/chartutil/create.go @@ -21,6 +21,7 @@ import ( "io/ioutil" "os" "path/filepath" + "strings" "k8s.io/helm/pkg/proto/hapi/chart" ) @@ -111,14 +112,14 @@ const defaultIgnore = `# Patterns to ignore when building packages. ` const defaultIngress = `{{- if .Values.ingress.enabled -}} -{{- $serviceName := include "fullname" . -}} +{{- $serviceName := include ".fullname" . -}} {{- $servicePort := .Values.service.externalPort -}} apiVersion: extensions/v1beta1 kind: Ingress metadata: - name: {{ template "fullname" . }} + name: {{ template ".fullname" . }} labels: - app: {{ template "name" . }} + app: {{ template ".name" . }} chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} @@ -147,9 +148,9 @@ spec: const defaultDeployment = `apiVersion: extensions/v1beta1 kind: Deployment metadata: - name: {{ template "fullname" . }} + name: {{ template ".fullname" . }} labels: - app: {{ template "name" . }} + app: {{ template ".name" . }} chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} @@ -158,7 +159,7 @@ spec: template: metadata: labels: - app: {{ template "name" . }} + app: {{ template ".name" . }} release: {{ .Release.Name }} spec: containers: @@ -186,9 +187,9 @@ spec: const defaultService = `apiVersion: v1 kind: Service metadata: - name: {{ template "fullname" . }} + name: {{ template ".fullname" . }} labels: - app: {{ template "name" . }} + app: {{ template ".name" . }} chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} @@ -200,7 +201,7 @@ spec: protocol: TCP name: {{ .Values.service.name }} selector: - app: {{ template "name" . }} + app: {{ template ".name" . }} release: {{ .Release.Name }} ` @@ -210,16 +211,16 @@ const defaultNotes = `1. Get the application URL by running these commands: http://{{ . }} {{- end }} {{- else if contains "NodePort" .Values.service.type }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "fullname" . }}) + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template ".fullname" . }}) export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") echo http://$NODE_IP:$NODE_PORT {{- else if contains "LoadBalancer" .Values.service.type }} NOTE: It may take a few minutes for the LoadBalancer IP to be available. - You can watch the status of by running 'kubectl get svc -w {{ template "fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + You can watch the status of by running 'kubectl get svc -w {{ template ".fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template ".fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') echo http://$SERVICE_IP:{{ .Values.service.externalPort }} {{- else if contains "ClusterIP" .Values.service.type }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template ".name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") echo "Visit http://127.0.0.1:8080 to use your application" kubectl port-forward $POD_NAME 8080:{{ .Values.service.internalPort }} {{- end }} @@ -229,7 +230,7 @@ const defaultHelpers = `{{/* vim: set filetype=mustache: */}} {{/* Expand the name of the chart. */}} -{{- define "name" -}} +{{- define ".name" -}} {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} {{- end -}} @@ -237,7 +238,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 ".fullname" -}} {{- $name := default .Chart.Name .Values.nameOverride -}} {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} {{- end -}} @@ -318,27 +319,27 @@ func Create(chartfile *chart.Metadata, dir string) (string, error) { { // ingress.yaml path: filepath.Join(cdir, TemplatesDir, IngressFileName), - content: []byte(defaultIngress), + content: []byte(strings.Replace(defaultIngress, "", chartfile.Name, -1)), }, { // deployment.yaml path: filepath.Join(cdir, TemplatesDir, DeploymentName), - content: []byte(defaultDeployment), + content: []byte(strings.Replace(defaultDeployment, "", chartfile.Name, -1)), }, { // service.yaml path: filepath.Join(cdir, TemplatesDir, ServiceName), - content: []byte(defaultService), + content: []byte(strings.Replace(defaultService, "", chartfile.Name, -1)), }, { // NOTES.txt path: filepath.Join(cdir, TemplatesDir, NotesName), - content: []byte(defaultNotes), + content: []byte(strings.Replace(defaultNotes, "", chartfile.Name, -1)), }, { // _helpers.tpl path: filepath.Join(cdir, TemplatesDir, HelpersName), - content: []byte(defaultHelpers), + content: []byte(strings.Replace(defaultHelpers, "", chartfile.Name, -1)), }, } From b27b11a2806eb5134c92a09796850ec7100b1871 Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Fri, 6 Oct 2017 14:05:32 -0400 Subject: [PATCH 008/107] fix(semver): fixed edge cases that do not match prerelease >0.0.0-a does not match pre-releases on 0.0.0 that start with a capital letter or number. This has to do with the ordering of code points. Numbers and capital letters come before lowercase letters. >0.0.0-0 should match all valid pre-releases on 0.0.0. According to the spec, "Numeric identifiers MUST NOT include leading zeroes." A 0 is also the lowest code point for all the allowed characters in a pre-release --- cmd/helm/fetch.go | 6 +++--- cmd/helm/install.go | 6 +++--- cmd/helm/upgrade.go | 6 +++--- docs/helm/helm_fetch.md | 2 +- docs/helm/helm_install.md | 2 +- docs/helm/helm_upgrade.md | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/cmd/helm/fetch.go b/cmd/helm/fetch.go index 70b99ae62..9c1f25614 100644 --- a/cmd/helm/fetch.go +++ b/cmd/helm/fetch.go @@ -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 } diff --git a/cmd/helm/install.go b/cmd/helm/install.go index 0c21050b1..f1b644f2d 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -159,8 +159,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, @@ -192,7 +192,7 @@ 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.") return cmd } diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go index 4b852198a..5a713e06e 100644 --- a/cmd/helm/upgrade.go +++ b/cmd/helm/upgrade.go @@ -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] @@ -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") diff --git a/docs/helm/helm_fetch.md b/docs/helm/helm_fetch.md index 56996774e..6bb3279c4 100644 --- a/docs/helm/helm_fetch.md +++ b/docs/helm/helm_fetch.md @@ -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 diff --git a/docs/helm/helm_install.md b/docs/helm/helm_install.md index a8f00e434..f90b76876 100644 --- a/docs/helm/helm_install.md +++ b/docs/helm/helm_install.md @@ -70,7 +70,7 @@ 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. + --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") diff --git a/docs/helm/helm_upgrade.md b/docs/helm/helm_upgrade.md index fdf95854f..f44e0521a 100644 --- a/docs/helm/helm_upgrade.md +++ b/docs/helm/helm_upgrade.md @@ -38,7 +38,7 @@ helm upgrade [RELEASE] [CHART] ``` --ca-file string verify certificates of HTTPS-enabled servers using this CA bundle --cert-file string identify HTTPS client using this SSL certificate file - --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. --dry-run simulate an upgrade --force force resource update through delete/recreate if needed -i, --install if a release by this name doesn't already exist, run an install From 9af1018bd3180d3878941f5fd8691955e1f69438 Mon Sep 17 00:00:00 2001 From: Remington Reackhof Date: Mon, 11 Sep 2017 15:36:48 -0400 Subject: [PATCH 009/107] Add secrets storage backend for releases --- cmd/tiller/tiller.go | 9 +- pkg/storage/driver/cfgmaps.go | 63 ------- pkg/storage/driver/mock_test.go | 78 +++++++++ pkg/storage/driver/secrets.go | 258 +++++++++++++++++++++++++++++ pkg/storage/driver/secrets_test.go | 186 +++++++++++++++++++++ pkg/storage/driver/util.go | 85 ++++++++++ 6 files changed, 615 insertions(+), 64 deletions(-) create mode 100644 pkg/storage/driver/secrets.go create mode 100644 pkg/storage/driver/secrets_test.go create mode 100644 pkg/storage/driver/util.go diff --git a/cmd/tiller/tiller.go b/cmd/tiller/tiller.go index 2a4cf066e..f18ce6c3d 100644 --- a/cmd/tiller/tiller.go +++ b/cmd/tiller/tiller.go @@ -57,6 +57,7 @@ const ( storageMemory = "memory" storageConfigMap = "configmap" + storageSecret = "secret" probeAddr = ":44135" traceAddr = ":44136" @@ -68,7 +69,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") @@ -117,6 +118,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 { diff --git a/pkg/storage/driver/cfgmaps.go b/pkg/storage/driver/cfgmaps.go index 6d1c8f222..63c03a1d2 100644 --- a/pkg/storage/driver/cfgmaps.go +++ b/pkg/storage/driver/cfgmaps.go @@ -17,16 +17,11 @@ limitations under the License. package driver // import "k8s.io/helm/pkg/storage/driver" import ( - "bytes" - "compress/gzip" - "encoding/base64" "fmt" - "io/ioutil" "strconv" "strings" "time" - "github.com/golang/protobuf/proto" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" kblabels "k8s.io/apimachinery/pkg/labels" @@ -42,10 +37,6 @@ var _ Driver = (*ConfigMaps)(nil) // ConfigMapsDriverName is the string name of the driver. const ConfigMapsDriverName = "ConfigMap" -var b64 = base64.StdEncoding - -var magicGzip = []byte{0x1f, 0x8b, 0x08} - // ConfigMaps is a wrapper around an implementation of a kubernetes // ConfigMapsInterface. type ConfigMaps struct { @@ -265,57 +256,3 @@ func newConfigMapsObject(key string, rls *rspb.Release, lbs labels) (*api.Config Data: map[string]string{"release": s}, }, nil } - -// encodeRelease encodes a release returning a base64 encoded -// gzipped binary protobuf encoding representation, or error. -func encodeRelease(rls *rspb.Release) (string, error) { - b, err := proto.Marshal(rls) - if err != nil { - return "", err - } - var buf bytes.Buffer - w, err := gzip.NewWriterLevel(&buf, gzip.BestCompression) - if err != nil { - return "", err - } - if _, err = w.Write(b); err != nil { - return "", err - } - w.Close() - - return b64.EncodeToString(buf.Bytes()), nil -} - -// decodeRelease decodes the bytes in data into a release -// type. Data must contain a base64 encoded string of a -// valid protobuf encoding of a release, otherwise -// an error is returned. -func decodeRelease(data string) (*rspb.Release, error) { - // base64 decode string - b, err := b64.DecodeString(data) - if err != nil { - return nil, err - } - - // For backwards compatibility with releases that were stored before - // compression was introduced we skip decompression if the - // gzip magic header is not found - if bytes.Equal(b[0:3], magicGzip) { - r, err := gzip.NewReader(bytes.NewReader(b)) - if err != nil { - return nil, err - } - b2, err := ioutil.ReadAll(r) - if err != nil { - return nil, err - } - b = b2 - } - - var rls rspb.Release - // unmarshal protobuf bytes - if err := proto.Unmarshal(b, &rls); err != nil { - return nil, err - } - return &rls, nil -} diff --git a/pkg/storage/driver/mock_test.go b/pkg/storage/driver/mock_test.go index 40174106d..e9f00a40a 100644 --- a/pkg/storage/driver/mock_test.go +++ b/pkg/storage/driver/mock_test.go @@ -142,3 +142,81 @@ func (mock *MockConfigMapsInterface) Delete(name string, opts *metav1.DeleteOpti delete(mock.objects, name) return nil } + +// newTestFixture initializes a MockSecretsInterface. +// Secrets are created for each release provided. +func newTestFixtureSecrets(t *testing.T, releases ...*rspb.Release) *Secrets { + var mock MockSecretsInterface + mock.Init(t, releases...) + + return NewSecrets(&mock) +} + +// MockSecretsInterface mocks a kubernetes SecretsInterface +type MockSecretsInterface struct { + internalversion.SecretInterface + + objects map[string]*api.Secret +} + +// Init initializes the MockSecretsInterface with the set of releases. +func (mock *MockSecretsInterface) Init(t *testing.T, releases ...*rspb.Release) { + mock.objects = map[string]*api.Secret{} + + for _, rls := range releases { + objkey := testKey(rls.Name, rls.Version) + + secret, err := newSecretsObject(objkey, rls, nil) + if err != nil { + t.Fatalf("Failed to create secret: %s", err) + } + mock.objects[objkey] = secret + } +} + +// Get returns the Secret by name. +func (mock *MockSecretsInterface) Get(name string, options metav1.GetOptions) (*api.Secret, error) { + object, ok := mock.objects[name] + if !ok { + return nil, apierrors.NewNotFound(api.Resource("tests"), name) + } + return object, nil +} + +// List returns the a of Secret. +func (mock *MockSecretsInterface) List(opts metav1.ListOptions) (*api.SecretList, error) { + var list api.SecretList + for _, secret := range mock.objects { + list.Items = append(list.Items, *secret) + } + return &list, nil +} + +// Create creates a new Secret. +func (mock *MockSecretsInterface) Create(secret *api.Secret) (*api.Secret, error) { + name := secret.ObjectMeta.Name + if object, ok := mock.objects[name]; ok { + return object, apierrors.NewAlreadyExists(api.Resource("tests"), name) + } + mock.objects[name] = secret + return secret, nil +} + +// Update updates a Secret. +func (mock *MockSecretsInterface) Update(secret *api.Secret) (*api.Secret, error) { + name := secret.ObjectMeta.Name + if _, ok := mock.objects[name]; !ok { + return nil, apierrors.NewNotFound(api.Resource("tests"), name) + } + mock.objects[name] = secret + return secret, nil +} + +// Delete deletes a Secret by name. +func (mock *MockSecretsInterface) Delete(name string, opts *metav1.DeleteOptions) error { + if _, ok := mock.objects[name]; !ok { + return apierrors.NewNotFound(api.Resource("tests"), name) + } + delete(mock.objects, name) + return nil +} diff --git a/pkg/storage/driver/secrets.go b/pkg/storage/driver/secrets.go new file mode 100644 index 000000000..f81b475c0 --- /dev/null +++ b/pkg/storage/driver/secrets.go @@ -0,0 +1,258 @@ +/* +Copyright 2017 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package driver // import "k8s.io/helm/pkg/storage/driver" + +import ( + "fmt" + "strconv" + "strings" + "time" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + kblabels "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/util/validation" + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion" + + rspb "k8s.io/helm/pkg/proto/hapi/release" +) + +var _ Driver = (*Secrets)(nil) + +// SecretsDriverName is the string name of the driver. +const SecretsDriverName = "Secret" + +// Secrets is a wrapper around an implementation of a kubernetes +// SecretsInterface. +type Secrets struct { + impl internalversion.SecretInterface + Log func(string, ...interface{}) +} + +// NewSecrets initializes a new Secrets wrapping an implmenetation of +// the kubernetes SecretsInterface. +func NewSecrets(impl internalversion.SecretInterface) *Secrets { + return &Secrets{ + impl: impl, + Log: func(_ string, _ ...interface{}) {}, + } +} + +// Name returns the name of the driver. +func (secrets *Secrets) Name() string { + return SecretsDriverName +} + +// Get fetches the release named by key. The corresponding release is returned +// or error if not found. +func (secrets *Secrets) Get(key string) (*rspb.Release, error) { + // fetch the secret holding the release named by key + obj, err := secrets.impl.Get(key, metav1.GetOptions{}) + if err != nil { + if apierrors.IsNotFound(err) { + return nil, ErrReleaseNotFound(key) + } + + secrets.Log("get: failed to get %q: %s", key, err) + return nil, err + } + // found the secret, decode the base64 data string + r, err := decodeRelease(string(obj.Data["release"])) + if err != nil { + secrets.Log("get: failed to decode data %q: %s", key, err) + return nil, err + } + // return the release object + return r, nil +} + +// List fetches all releases and returns the list releases such +// that filter(release) == true. An error is returned if the +// secret fails to retrieve the releases. +func (secrets *Secrets) List(filter func(*rspb.Release) bool) ([]*rspb.Release, error) { + lsel := kblabels.Set{"OWNER": "TILLER"}.AsSelector() + opts := metav1.ListOptions{LabelSelector: lsel.String()} + + list, err := secrets.impl.List(opts) + if err != nil { + secrets.Log("list: failed to list: %s", err) + return nil, err + } + + var results []*rspb.Release + + // iterate over the secrets object list + // and decode each release + for _, item := range list.Items { + rls, err := decodeRelease(string(item.Data["release"])) + if err != nil { + secrets.Log("list: failed to decode release: %v: %s", item, err) + continue + } + if filter(rls) { + results = append(results, rls) + } + } + return results, nil +} + +// Query fetches all releases that match the provided map of labels. +// An error is returned if the secret fails to retrieve the releases. +func (secrets *Secrets) Query(labels map[string]string) ([]*rspb.Release, error) { + ls := kblabels.Set{} + for k, v := range labels { + if errs := validation.IsValidLabelValue(v); len(errs) != 0 { + return nil, fmt.Errorf("invalid label value: %q: %s", v, strings.Join(errs, "; ")) + } + ls[k] = v + } + + opts := metav1.ListOptions{LabelSelector: ls.AsSelector().String()} + + list, err := secrets.impl.List(opts) + if err != nil { + secrets.Log("query: failed to query with labels: %s", err) + return nil, err + } + + if len(list.Items) == 0 { + return nil, ErrReleaseNotFound(labels["NAME"]) + } + + var results []*rspb.Release + for _, item := range list.Items { + rls, err := decodeRelease(string(item.Data["release"])) + if err != nil { + secrets.Log("query: failed to decode release: %s", err) + continue + } + results = append(results, rls) + } + return results, nil +} + +// Create creates a new Secret holding the release. If the +// Secret already exists, ErrReleaseExists is returned. +func (secrets *Secrets) Create(key string, rls *rspb.Release) error { + // set labels for secrets object meta data + var lbs labels + + lbs.init() + lbs.set("CREATED_AT", strconv.Itoa(int(time.Now().Unix()))) + + // create a new secret to hold the release + obj, err := newSecretsObject(key, rls, lbs) + if err != nil { + secrets.Log("create: failed to encode release %q: %s", rls.Name, err) + return err + } + // push the secret object out into the kubiverse + if _, err := secrets.impl.Create(obj); err != nil { + if apierrors.IsAlreadyExists(err) { + return ErrReleaseExists(rls.Name) + } + + secrets.Log("create: failed to create: %s", err) + return err + } + return nil +} + +// Update updates the Secret holding the release. If not found +// the Secret is created to hold the release. +func (secrets *Secrets) Update(key string, rls *rspb.Release) error { + // set labels for secrets object meta data + var lbs labels + + lbs.init() + lbs.set("MODIFIED_AT", strconv.Itoa(int(time.Now().Unix()))) + + // create a new secret object to hold the release + obj, err := newSecretsObject(key, rls, lbs) + if err != nil { + secrets.Log("update: failed to encode release %q: %s", rls.Name, err) + return err + } + // push the secret object out into the kubiverse + _, err = secrets.impl.Update(obj) + if err != nil { + secrets.Log("update: failed to update: %s", err) + return err + } + return nil +} + +// Delete deletes the Secret holding the release named by key. +func (secrets *Secrets) Delete(key string) (rls *rspb.Release, err error) { + // fetch the release to check existence + if rls, err = secrets.Get(key); err != nil { + if apierrors.IsNotFound(err) { + return nil, ErrReleaseExists(rls.Name) + } + + secrets.Log("delete: failed to get release %q: %s", key, err) + return nil, err + } + // delete the release + if err = secrets.impl.Delete(key, &metav1.DeleteOptions{}); err != nil { + return rls, err + } + return rls, nil +} + +// newSecretsObject constructs a kubernetes Secret object +// to store a release. Each secret data entry is the base64 +// encoded string of a release's binary protobuf encoding. +// +// The following labels are used within each secret: +// +// "MODIFIED_AT" - timestamp indicating when this secret was last modified. (set in Update) +// "CREATED_AT" - timestamp indicating when this secret was created. (set in Create) +// "VERSION" - version of the release. +// "STATUS" - status of the release (see proto/hapi/release.status.pb.go for variants) +// "OWNER" - owner of the secret, currently "TILLER". +// "NAME" - name of the release. +// +func newSecretsObject(key string, rls *rspb.Release, lbs labels) (*api.Secret, error) { + const owner = "TILLER" + + // encode the release + s, err := encodeRelease(rls) + if err != nil { + return nil, err + } + + if lbs == nil { + lbs.init() + } + + // apply labels + lbs.set("NAME", rls.Name) + lbs.set("OWNER", owner) + lbs.set("STATUS", rspb.Status_Code_name[int32(rls.Info.Status.Code)]) + lbs.set("VERSION", strconv.Itoa(int(rls.Version))) + + // create and return secret object + return &api.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: key, + Labels: lbs.toMap(), + }, + Data: map[string][]byte{"release": []byte(s)}, + }, nil +} diff --git a/pkg/storage/driver/secrets_test.go b/pkg/storage/driver/secrets_test.go new file mode 100644 index 000000000..2441560c3 --- /dev/null +++ b/pkg/storage/driver/secrets_test.go @@ -0,0 +1,186 @@ +/* +Copyright 2017 The Kubernetes Authors All rights reserved. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package driver + +import ( + "encoding/base64" + "reflect" + "testing" + + "github.com/gogo/protobuf/proto" + "k8s.io/kubernetes/pkg/api" + + rspb "k8s.io/helm/pkg/proto/hapi/release" +) + +func TestSecretName(t *testing.T) { + c := newTestFixtureSecrets(t) + if c.Name() != SecretsDriverName { + t.Errorf("Expected name to be %q, got %q", SecretsDriverName, c.Name()) + } +} + +func TestSecretGet(t *testing.T) { + vers := int32(1) + name := "smug-pigeon" + namespace := "default" + key := testKey(name, vers) + rel := releaseStub(name, vers, namespace, rspb.Status_DEPLOYED) + + secrets := newTestFixtureSecrets(t, []*rspb.Release{rel}...) + + // get release with key + got, err := secrets.Get(key) + if err != nil { + t.Fatalf("Failed to get release: %s", err) + } + // compare fetched release with original + if !reflect.DeepEqual(rel, got) { + t.Errorf("Expected {%q}, got {%q}", rel, got) + } +} + +func TestUNcompressedSecretGet(t *testing.T) { + vers := int32(1) + name := "smug-pigeon" + namespace := "default" + key := testKey(name, vers) + rel := releaseStub(name, vers, namespace, rspb.Status_DEPLOYED) + + // Create a test fixture which contains an uncompressed release + secret, err := newSecretsObject(key, rel, nil) + if err != nil { + t.Fatalf("Failed to create secret: %s", err) + } + b, err := proto.Marshal(rel) + if err != nil { + t.Fatalf("Failed to marshal release: %s", err) + } + secret.Data["release"] = []byte(base64.StdEncoding.EncodeToString(b)) + var mock MockSecretsInterface + mock.objects = map[string]*api.Secret{key: secret} + secrets := NewSecrets(&mock) + + // get release with key + got, err := secrets.Get(key) + if err != nil { + t.Fatalf("Failed to get release: %s", err) + } + // compare fetched release with original + if !reflect.DeepEqual(rel, got) { + t.Errorf("Expected {%q}, got {%q}", rel, got) + } +} + +func TestSecretList(t *testing.T) { + secrets := newTestFixtureSecrets(t, []*rspb.Release{ + releaseStub("key-1", 1, "default", rspb.Status_DELETED), + releaseStub("key-2", 1, "default", rspb.Status_DELETED), + releaseStub("key-3", 1, "default", rspb.Status_DEPLOYED), + releaseStub("key-4", 1, "default", rspb.Status_DEPLOYED), + releaseStub("key-5", 1, "default", rspb.Status_SUPERSEDED), + releaseStub("key-6", 1, "default", rspb.Status_SUPERSEDED), + }...) + + // list all deleted releases + del, err := secrets.List(func(rel *rspb.Release) bool { + return rel.Info.Status.Code == rspb.Status_DELETED + }) + // check + if err != nil { + t.Errorf("Failed to list deleted: %s", err) + } + if len(del) != 2 { + t.Errorf("Expected 2 deleted, got %d:\n%v\n", len(del), del) + } + + // list all deployed releases + dpl, err := secrets.List(func(rel *rspb.Release) bool { + return rel.Info.Status.Code == rspb.Status_DEPLOYED + }) + // check + if err != nil { + t.Errorf("Failed to list deployed: %s", err) + } + if len(dpl) != 2 { + t.Errorf("Expected 2 deployed, got %d", len(dpl)) + } + + // list all superseded releases + ssd, err := secrets.List(func(rel *rspb.Release) bool { + return rel.Info.Status.Code == rspb.Status_SUPERSEDED + }) + // check + if err != nil { + t.Errorf("Failed to list superseded: %s", err) + } + if len(ssd) != 2 { + t.Errorf("Expected 2 superseded, got %d", len(ssd)) + } +} + +func TestSecretCreate(t *testing.T) { + secrets := newTestFixtureSecrets(t) + + vers := int32(1) + name := "smug-pigeon" + namespace := "default" + key := testKey(name, vers) + rel := releaseStub(name, vers, namespace, rspb.Status_DEPLOYED) + + // store the release in a secret + if err := secrets.Create(key, rel); err != nil { + t.Fatalf("Failed to create release with key %q: %s", key, err) + } + + // get the release back + got, err := secrets.Get(key) + if err != nil { + t.Fatalf("Failed to get release with key %q: %s", key, err) + } + + // compare created release with original + if !reflect.DeepEqual(rel, got) { + t.Errorf("Expected {%q}, got {%q}", rel, got) + } +} + +func TestSecretUpdate(t *testing.T) { + vers := int32(1) + name := "smug-pigeon" + namespace := "default" + key := testKey(name, vers) + rel := releaseStub(name, vers, namespace, rspb.Status_DEPLOYED) + + secrets := newTestFixtureSecrets(t, []*rspb.Release{rel}...) + + // modify release status code + rel.Info.Status.Code = rspb.Status_SUPERSEDED + + // perform the update + if err := secrets.Update(key, rel); err != nil { + t.Fatalf("Failed to update release: %s", err) + } + + // fetch the updated release + got, err := secrets.Get(key) + if err != nil { + t.Fatalf("Failed to get release with key %q: %s", key, err) + } + + // check release has actually been updated by comparing modified fields + if rel.Info.Status.Code != got.Info.Status.Code { + t.Errorf("Expected status %s, got status %s", rel.Info.Status.Code, got.Info.Status.Code) + } +} diff --git a/pkg/storage/driver/util.go b/pkg/storage/driver/util.go new file mode 100644 index 000000000..65fb17e7c --- /dev/null +++ b/pkg/storage/driver/util.go @@ -0,0 +1,85 @@ +/* +Copyright 2017 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package driver // import "k8s.io/helm/pkg/storage/driver" + +import ( + "bytes" + "compress/gzip" + "encoding/base64" + "io/ioutil" + + "github.com/golang/protobuf/proto" + rspb "k8s.io/helm/pkg/proto/hapi/release" +) + +var b64 = base64.StdEncoding + +var magicGzip = []byte{0x1f, 0x8b, 0x08} + +// encodeRelease encodes a release returning a base64 encoded +// gzipped binary protobuf encoding representation, or error. +func encodeRelease(rls *rspb.Release) (string, error) { + b, err := proto.Marshal(rls) + if err != nil { + return "", err + } + var buf bytes.Buffer + w, err := gzip.NewWriterLevel(&buf, gzip.BestCompression) + if err != nil { + return "", err + } + if _, err = w.Write(b); err != nil { + return "", err + } + w.Close() + + return b64.EncodeToString(buf.Bytes()), nil +} + +// decodeRelease decodes the bytes in data into a release +// type. Data must contain a base64 encoded string of a +// valid protobuf encoding of a release, otherwise +// an error is returned. +func decodeRelease(data string) (*rspb.Release, error) { + // base64 decode string + b, err := b64.DecodeString(data) + if err != nil { + return nil, err + } + + // For backwards compatibility with releases that were stored before + // compression was introduced we skip decompression if the + // gzip magic header is not found + if bytes.Equal(b[0:3], magicGzip) { + r, err := gzip.NewReader(bytes.NewReader(b)) + if err != nil { + return nil, err + } + b2, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + b = b2 + } + + var rls rspb.Release + // unmarshal protobuf bytes + if err := proto.Unmarshal(b, &rls); err != nil { + return nil, err + } + return &rls, nil +} From 29c3b5276f0290d21d43ef45ad0230e45b460b27 Mon Sep 17 00:00:00 2001 From: Taylor Thomas Date: Mon, 9 Oct 2017 18:38:06 -0700 Subject: [PATCH 010/107] fix(tiller): Adds CRD ordering This adds CRD ordering into the explicit kind sorter list Closes #2925 --- pkg/tiller/kind_sorter.go | 2 ++ pkg/tiller/kind_sorter_test.go | 16 ++++++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/pkg/tiller/kind_sorter.go b/pkg/tiller/kind_sorter.go index 964c01549..f367e65c8 100644 --- a/pkg/tiller/kind_sorter.go +++ b/pkg/tiller/kind_sorter.go @@ -36,6 +36,7 @@ var InstallOrder SortOrder = []string{ "PersistentVolume", "PersistentVolumeClaim", "ServiceAccount", + "CustomResourceDefinition", "ClusterRole", "ClusterRoleBinding", "Role", @@ -72,6 +73,7 @@ var UninstallOrder SortOrder = []string{ "Role", "ClusterRoleBinding", "ClusterRole", + "CustomResourceDefinition", "ServiceAccount", "PersistentVolumeClaim", "PersistentVolume", diff --git a/pkg/tiller/kind_sorter_test.go b/pkg/tiller/kind_sorter_test.go index 975db0563..ef7296e89 100644 --- a/pkg/tiller/kind_sorter_test.go +++ b/pkg/tiller/kind_sorter_test.go @@ -41,6 +41,10 @@ func TestKindSorter(t *testing.T) { Name: "u", Head: &util.SimpleHead{Kind: "CronJob"}, }, + { + Name: "2", + Head: &util.SimpleHead{Kind: "CustomResourceDefinition"}, + }, { Name: "n", Head: &util.SimpleHead{Kind: "DaemonSet"}, @@ -49,10 +53,6 @@ func TestKindSorter(t *testing.T) { Name: "r", Head: &util.SimpleHead{Kind: "Deployment"}, }, - { - Name: "1", - Head: &util.SimpleHead{Kind: "StorageClass"}, - }, { Name: "!", Head: &util.SimpleHead{Kind: "HonkyTonkSet"}, @@ -121,6 +121,10 @@ func TestKindSorter(t *testing.T) { Name: "s", Head: &util.SimpleHead{Kind: "StatefulSet"}, }, + { + Name: "1", + Head: &util.SimpleHead{Kind: "StorageClass"}, + }, { Name: "w", Head: &util.SimpleHead{Kind: "APIService"}, @@ -132,8 +136,8 @@ func TestKindSorter(t *testing.T) { order SortOrder expected string }{ - {"install", InstallOrder, "abcde1fghijklmnopqrstuvw!"}, - {"uninstall", UninstallOrder, "wvmutsrqponlkjihgf1edcba!"}, + {"install", InstallOrder, "abcde1fgh2ijklmnopqrstuvw!"}, + {"uninstall", UninstallOrder, "wvmutsrqponlkji2hgf1edcba!"}, } { var buf bytes.Buffer t.Run(test.description, func(t *testing.T) { From 16c579f3a303b6df30cf90c4d96d346ddd2e9c5e Mon Sep 17 00:00:00 2001 From: Justin Scott Date: Wed, 7 Jun 2017 11:10:19 -0700 Subject: [PATCH 011/107] feat(helm): Add --node-selectors and --output flags to helm init This feature enables users to specify more control over where Tiller pod lands by allowing "node-selectors" to be specified. Alternatively, the "--output" flag will skip install and dump Tiller's raw Deployment manifest to stdout so user may alter it as they see fit (probably with a JSON manipulation tool like jq). Closes #2299 --- cmd/helm/init.go | 74 ++++++++++++++---- cmd/helm/init_test.go | 52 +++++++++++++ cmd/helm/installer/install.go | 80 ++++++++++++++++--- cmd/helm/installer/install_test.go | 109 +++++++++++++++++++++++++- cmd/helm/installer/options.go | 49 ++++++++++++ docs/helm/helm_init.md | 5 +- docs/install.md | 121 +++++++++++++++++++++++++++++ 7 files changed, 461 insertions(+), 29 deletions(-) diff --git a/cmd/helm/init.go b/cmd/helm/init.go index 163653692..21381a0f6 100644 --- a/cmd/helm/init.go +++ b/cmd/helm/init.go @@ -17,6 +17,8 @@ limitations under the License. package main import ( + "bytes" + "encoding/json" "errors" "fmt" "io" @@ -26,6 +28,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" @@ -120,6 +123,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 } @@ -160,31 +167,66 @@ 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 { - // YAML starting document boundary marker - if _, err := fmt.Fprintln(w, "---"); err != nil { - return err - } + writeYAMLManifest := func(apiVersion, kind, body string, first, last bool) error { + w := i.out + if !first { + // YAML starting document boundary marker + if _, err := fmt.Fprintln(w, "---"); err != nil { + return err } - if _, err := fmt.Fprintln(w, "apiVersion:", apiVersion); err != nil { + } + if _, err := fmt.Fprintln(w, "apiVersion:", apiVersion); err != nil { + return err + } + if _, err := fmt.Fprintln(w, "kind:", kind); err != nil { + return err + } + if _, err := fmt.Fprint(w, body); err != nil { + return err + } + if !last { + return nil + } + // YAML ending document boundary marker + _, err := fmt.Fprintln(w, "...") + return err + } + if len(i.opts.Output) > 0 { + var body string + var 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 } - if _, err := fmt.Fprintln(w, "kind:", kind); err != nil { + 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 := fmt.Fprint(w, body); err != nil { + if _, err = i.out.Write(out.Bytes()); err != nil { return err } - if !last { - return nil + + return nil + case "yaml": + if err := writeYAMLManifest("extensions/v1beta1", "Deployment", body, true, false); err != nil { + return err } - // YAML ending document boundary marker - _, err := fmt.Fprintln(w, "...") - return err + return nil + default: + return fmt.Errorf("unknown output format: %q", i.opts.Output) } + } + if settings.Debug { var body string var err error diff --git a/cmd/helm/init_test.go b/cmd/helm/init_test.go index 6547e2342..a5770f698 100644 --- a/cmd/helm/init_test.go +++ b/cmd/helm/init_test.go @@ -35,6 +35,8 @@ import ( "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()) + } + } + +} diff --git a/cmd/helm/installer/install.go b/cmd/helm/installer/install.go index c3f9eb484..b20169e05 100644 --- a/cmd/helm/installer/install.go +++ b/cmd/helm/installer/install.go @@ -19,6 +19,7 @@ package installer // import "k8s.io/helm/cmd/helm/installer" import ( "fmt" "io/ioutil" + "strings" "github.com/ghodss/yaml" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -29,6 +30,7 @@ import ( 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, @@ -166,10 +195,8 @@ func generateDeployment(opts *Options) *v1beta1.Deployment { }, }, }, - HostNetwork: opts.EnableHostNetwork, - NodeSelector: map[string]string{ - "beta.kubernetes.io/os": "linux", - }, + HostNetwork: opts.EnableHostNetwork, + NodeSelector: nodeSelectors, }, }, }, @@ -205,7 +232,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 { diff --git a/cmd/helm/installer/install_test.go b/cmd/helm/installer/install_test.go index 431e72b5b..23a4a7a1d 100644 --- a/cmd/helm/installer/install_test.go +++ b/cmd/helm/installer/install_test.go @@ -30,6 +30,7 @@ import ( "k8s.io/client-go/pkg/apis/extensions/v1beta1" testcore "k8s.io/client-go/testing" + "k8s.io/helm/pkg/chartutil" "k8s.io/helm/pkg/version" ) @@ -330,7 +331,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 +372,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 +420,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) + } + } + } +} diff --git a/cmd/helm/installer/options.go b/cmd/helm/installer/options.go index 7567c86e8..e03482172 100644 --- a/cmd/helm/installer/options.go +++ b/cmd/helm/installer/options.go @@ -20,6 +20,7 @@ import ( "fmt" "k8s.io/client-go/pkg/api/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) +} diff --git a/docs/helm/helm_init.md b/docs/helm/helm_init.md index 2d224c7f1..0085f6cde 100644 --- a/docs/helm/helm_init.md +++ b/docs/helm/helm_init.md @@ -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") @@ -64,4 +67,4 @@ helm init ### 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 10-Oct-2017 diff --git a/docs/install.md b/docs/install.md index af5d57a7b..618b5332c 100755 --- a/docs/install.md +++ b/docs/install.md @@ -197,6 +197,127 @@ Tiller can then be re-installed from the client with: $ helm init ``` +## Advanced Usage + +`helm init` provides additional flags for modifying Tiller's deployment +manifest before it is installed. + +### Using `--node-selectors` + +The `--node-selectors` flag allows us to specify the node labels required +for scheduling the Tiller pod. + +The example below will create the specified label under the nodeSelector +property. + +``` +helm init --node-selectors "beta.kubernetes.io/os"="linux" +``` + +The installed deployment manifest will contain our node selector label. + +``` +... +spec: + template: + spec: + nodeSelector: + beta.kubernetes.io/os: linux +... +``` + + +### Using `--override` + +`--override` allows you to specify properties of Tiller's +deployment manifest. Unlike the `--set` command used elsewhere in Helm, +`helm init --override` manipulates the specified properties of the final +manifest (there is no "values" file). Therefore you may specify any valid +value for any valid property in the deployment manifest. + +#### Override annotation + +In the example below we use `--override` to add the revision property and set +its value to 1. + +``` +helm init --set metadata.annotations."deployment\.kubernetes\.io/revision"="1" +``` +Output: + +``` +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + annotations: + deployment.kubernetes.io/revision: "1" +... +``` + +#### Override affinity + +In the example below we set properties for node affinity. Multiple +`--override` commands may be combined to modify different properties of the +same list item. + +``` +helm init --override "spec.template.spec.affinity.nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].weight"="1" --override "spec.template.spec.affinity.nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].preference.matchExpressions[0].key"="e2e-az-name" +``` + +The specified properties are combined into the +"preferredDuringSchedulingIgnoredDuringExecution" property's first +list item. + +``` +... +spec: + strategy: {} + template: + ... + spec: + affinity: + nodeAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - preference: + matchExpressions: + - key: e2e-az-name + operator: "" + weight: 1 +... +``` + +### Using `--output` + +The `--output` flag allows us skip the installation of Tiller's deployment +manifest and simply output the deployment manifest to stdout in either +JSON or YAML format. The output may then be modified with tools like `jq` +and installed manually with `kubectl`. + +In the example below we execute `helm init` with the `--output json` flag. + +``` +helm init --output json +``` + +The Tiller installation is skipped and the manifest is output to stdout +in JSON format. + +``` +"apiVersion": "extensions/v1beta1", +"kind": "Deployment", +"metadata": { + "creationTimestamp": null, + "labels": { + "app": "helm", + "name": "tiller" + }, + "name": "tiller-deploy", + "namespace": "kube-system" +}, +... +``` + + ## Conclusion In most cases, installation is as simple as getting a pre-built `helm` binary From 3bc7c44f059e8ff433ced7b4c46a195ed16f3543 Mon Sep 17 00:00:00 2001 From: Brad Bowman Date: Wed, 11 Oct 2017 11:16:01 -0600 Subject: [PATCH 012/107] Make ReleaseContent and ReleaseStatus respect release names in the fake client --- pkg/helm/fake.go | 27 ++++++---- pkg/helm/fake_test.go | 116 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+), 10 deletions(-) create mode 100644 pkg/helm/fake_test.go diff --git a/pkg/helm/fake.go b/pkg/helm/fake.go index c66777673..8f5ff25c2 100644 --- a/pkg/helm/fake.go +++ b/pkg/helm/fake.go @@ -88,15 +88,18 @@ func (c *FakeClient) RollbackRelease(rlsName string, opts ...RollbackOption) (*r return nil, nil } -// ReleaseStatus returns a release status response with info from the first release in the fake -// release client +// ReleaseStatus returns a release status response with info from the matching release name in the fake release client. func (c *FakeClient) ReleaseStatus(rlsName string, opts ...StatusOption) (*rls.GetReleaseStatusResponse, error) { - if c.Rels[0] != nil { - return &rls.GetReleaseStatusResponse{ - Name: c.Rels[0].Name, - Info: c.Rels[0].Info, - Namespace: c.Rels[0].Namespace, - }, nil + if len(c.Rels) > 0 { + for _, release := range c.Rels { + if release.Name == rlsName { + return &rls.GetReleaseStatusResponse{ + Name: release.Name, + Info: release.Info, + Namespace: release.Namespace, + }, nil + } + } } return nil, fmt.Errorf("No such release: %s", rlsName) } @@ -104,8 +107,12 @@ func (c *FakeClient) ReleaseStatus(rlsName string, opts ...StatusOption) (*rls.G // ReleaseContent returns the configuration for the first release in the fake release client func (c *FakeClient) ReleaseContent(rlsName string, opts ...ContentOption) (resp *rls.GetReleaseContentResponse, err error) { if len(c.Rels) > 0 { - resp = &rls.GetReleaseContentResponse{ - Release: c.Rels[0], + for _, release := range c.Rels { + if release.Name == rlsName { + resp = &rls.GetReleaseContentResponse{ + Release: release, + } + } } } return resp, c.Err diff --git a/pkg/helm/fake_test.go b/pkg/helm/fake_test.go new file mode 100644 index 000000000..ee48a97b1 --- /dev/null +++ b/pkg/helm/fake_test.go @@ -0,0 +1,116 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package helm + +import ( + "reflect" + "testing" + + "k8s.io/helm/pkg/proto/hapi/release" + rls "k8s.io/helm/pkg/proto/hapi/services" +) + +func TestFakeClient_ReleaseStatus(t *testing.T) { + releasePresent := &release.Release{Name: "release-present", Namespace: "default"} + releaseNotPresent := &release.Release{Name: "release-not-present", Namespace: "default"} + + type fields struct { + Rels []*release.Release + } + type args struct { + rlsName string + opts []StatusOption + } + tests := []struct { + name string + fields fields + args args + want *rls.GetReleaseStatusResponse + wantErr bool + }{ + { + name: "Get a single release that exists", + fields: fields{ + Rels: []*release.Release{ + releasePresent, + }, + }, + args: args{ + rlsName: releasePresent.Name, + opts: nil, + }, + want: &rls.GetReleaseStatusResponse{ + Name: releasePresent.Name, + Info: releasePresent.Info, + Namespace: releasePresent.Namespace, + }, + + wantErr: false, + }, + { + name: "Get a release that does not exist", + fields: fields{ + Rels: []*release.Release{ + releasePresent, + }, + }, + args: args{ + rlsName: releaseNotPresent.Name, + opts: nil, + }, + want: nil, + wantErr: true, + }, + { + name: "Get a single release that exists from list", + fields: fields{ + Rels: []*release.Release{ + &release.Release{Name: "angry-dolphin", Namespace: "default"}, + &release.Release{Name: "trepid-tapir", Namespace: "default"}, + releasePresent, + }, + }, + args: args{ + rlsName: releasePresent.Name, + opts: nil, + }, + want: &rls.GetReleaseStatusResponse{ + Name: releasePresent.Name, + Info: releasePresent.Info, + Namespace: releasePresent.Namespace, + }, + + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &FakeClient{ + Rels: tt.fields.Rels, + } + got, err := c.ReleaseStatus(tt.args.rlsName, tt.args.opts...) + if (err != nil) != tt.wantErr { + t.Errorf("FakeClient.ReleaseStatus() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("FakeClient.ReleaseStatus() = %v, want %v", got, tt.want) + } + }) + } +} From 76b70ec70f54e6950bba0121b7aa865978afea79 Mon Sep 17 00:00:00 2001 From: Brad Bowman Date: Wed, 11 Oct 2017 11:33:02 -0600 Subject: [PATCH 013/107] gofmt -s --- pkg/helm/fake_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/helm/fake_test.go b/pkg/helm/fake_test.go index ee48a97b1..50580275c 100644 --- a/pkg/helm/fake_test.go +++ b/pkg/helm/fake_test.go @@ -79,8 +79,8 @@ func TestFakeClient_ReleaseStatus(t *testing.T) { name: "Get a single release that exists from list", fields: fields{ Rels: []*release.Release{ - &release.Release{Name: "angry-dolphin", Namespace: "default"}, - &release.Release{Name: "trepid-tapir", Namespace: "default"}, + {Name: "angry-dolphin", Namespace: "default"}, + {Name: "trepid-tapir", Namespace: "default"}, releasePresent, }, }, From 61f2b24dcad426a64cf59c38961e50ef14668b8c Mon Sep 17 00:00:00 2001 From: Brad Bowman Date: Wed, 11 Oct 2017 11:41:34 -0600 Subject: [PATCH 014/107] Update comment for accuracy --- pkg/helm/fake.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/helm/fake.go b/pkg/helm/fake.go index 8f5ff25c2..3be56293f 100644 --- a/pkg/helm/fake.go +++ b/pkg/helm/fake.go @@ -104,7 +104,7 @@ func (c *FakeClient) ReleaseStatus(rlsName string, opts ...StatusOption) (*rls.G return nil, fmt.Errorf("No such release: %s", rlsName) } -// ReleaseContent returns the configuration for the first release in the fake release client +// ReleaseContent returns the configuration for the matching release name in the fake release client. func (c *FakeClient) ReleaseContent(rlsName string, opts ...ContentOption) (resp *rls.GetReleaseContentResponse, err error) { if len(c.Rels) > 0 { for _, release := range c.Rels { From cab3057ee36ea13d08c492d90c1cf80a799f06fa Mon Sep 17 00:00:00 2001 From: Brad Bowman Date: Wed, 11 Oct 2017 14:43:27 -0600 Subject: [PATCH 015/107] Add support for all CRUD operations + test coverage for delete and install --- pkg/helm/fake.go | 118 +++++++++++++++++++--------- pkg/helm/fake_test.go | 173 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 256 insertions(+), 35 deletions(-) diff --git a/pkg/helm/fake.go b/pkg/helm/fake.go index 3be56293f..2a9c3cee3 100644 --- a/pkg/helm/fake.go +++ b/pkg/helm/fake.go @@ -17,9 +17,12 @@ limitations under the License. package helm // import "k8s.io/helm/pkg/helm" import ( + "errors" "fmt" + "strings" "sync" + "github.com/technosophos/moniker" "k8s.io/helm/pkg/proto/hapi/chart" "k8s.io/helm/pkg/proto/hapi/release" rls "k8s.io/helm/pkg/proto/hapi/services" @@ -30,7 +33,15 @@ import ( type FakeClient struct { Rels []*release.Release Responses map[string]release.TestRun_Status - Err error + Opts options +} + +// Option returns the fake release client +func (c *FakeClient) Option(opts ...Option) Interface { + for _, opt := range opts { + opt(&c.Opts) + } + return c } var _ Interface = &FakeClient{} @@ -42,31 +53,66 @@ func (c *FakeClient) ListReleases(opts ...ReleaseListOption) (*rls.ListReleasesR Count: int64(len(c.Rels)), Releases: c.Rels, } - return resp, c.Err + return resp, nil } // InstallRelease returns a response with the first Release on the fake release client func (c *FakeClient) InstallRelease(chStr, ns string, opts ...InstallOption) (*rls.InstallReleaseResponse, error) { - return &rls.InstallReleaseResponse{ - Release: c.Rels[0], - }, nil + chart := &chart.Chart{} + return c.InstallReleaseFromChart(chart, ns, opts...) } // InstallReleaseFromChart returns a response with the first Release on the fake release client func (c *FakeClient) InstallReleaseFromChart(chart *chart.Chart, ns string, opts ...InstallOption) (*rls.InstallReleaseResponse, error) { + for _, opt := range opts { + opt(&c.Opts) + } + + releaseName := c.Opts.instReq.Name + if releaseName == "" { + for i := 0; i < 5; i++ { + namer := moniker.New() + name := namer.NameSep("-") + if len(name) > 53 { + name = name[:53] + } + if _, err := c.ReleaseStatus(name, nil); strings.Contains(err.Error(), "No such release") { + releaseName = name + break + } + } + } + + // Check to see if the release already exists. + rel, err := c.ReleaseStatus(releaseName, nil) + if err == nil && rel != nil { + return nil, errors.New("cannot re-use a name that is still in use") + } + + release := &release.Release{ + Name: releaseName, + Namespace: ns, + } + + c.Rels = append(c.Rels, release) + return &rls.InstallReleaseResponse{ - Release: c.Rels[0], + Release: release, }, nil } // DeleteRelease returns nil, nil func (c *FakeClient) DeleteRelease(rlsName string, opts ...DeleteOption) (*rls.UninstallReleaseResponse, error) { - return nil, nil -} + for i, rel := range c.Rels { + if rel.Name == rlsName { + c.Rels = append(c.Rels[:i], c.Rels[i+1:]...) + return &rls.UninstallReleaseResponse{ + Release: rel, + }, nil + } + } -// UpdateRelease returns nil, nil -func (c *FakeClient) UpdateRelease(rlsName string, chStr string, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error) { - return nil, nil + return nil, fmt.Errorf("No such release: %s", rlsName) } // GetVersion returns a fake version @@ -78,9 +124,20 @@ func (c *FakeClient) GetVersion(opts ...VersionOption) (*rls.GetVersionResponse, }, nil } +// UpdateRelease returns nil, nil +func (c *FakeClient) UpdateRelease(rlsName string, chStr string, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error) { + return c.UpdateReleaseFromChart(rlsName, &chart.Chart{}, opts...) +} + // UpdateReleaseFromChart returns nil, nil func (c *FakeClient) UpdateReleaseFromChart(rlsName string, chart *chart.Chart, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error) { - return nil, nil + // Check to see if the release already exists. + rel, err := c.ReleaseContent(rlsName, nil) + if err != nil { + return nil, err + } + + return &rls.UpdateReleaseResponse{Release: rel.Release}, nil } // RollbackRelease returns nil, nil @@ -90,15 +147,13 @@ func (c *FakeClient) RollbackRelease(rlsName string, opts ...RollbackOption) (*r // ReleaseStatus returns a release status response with info from the matching release name in the fake release client. func (c *FakeClient) ReleaseStatus(rlsName string, opts ...StatusOption) (*rls.GetReleaseStatusResponse, error) { - if len(c.Rels) > 0 { - for _, release := range c.Rels { - if release.Name == rlsName { - return &rls.GetReleaseStatusResponse{ - Name: release.Name, - Info: release.Info, - Namespace: release.Namespace, - }, nil - } + for _, rel := range c.Rels { + if rel.Name == rlsName { + return &rls.GetReleaseStatusResponse{ + Name: rel.Name, + Info: rel.Info, + Namespace: rel.Namespace, + }, nil } } return nil, fmt.Errorf("No such release: %s", rlsName) @@ -106,21 +161,19 @@ func (c *FakeClient) ReleaseStatus(rlsName string, opts ...StatusOption) (*rls.G // ReleaseContent returns the configuration for the matching release name in the fake release client. func (c *FakeClient) ReleaseContent(rlsName string, opts ...ContentOption) (resp *rls.GetReleaseContentResponse, err error) { - if len(c.Rels) > 0 { - for _, release := range c.Rels { - if release.Name == rlsName { - resp = &rls.GetReleaseContentResponse{ - Release: release, - } - } + for _, rel := range c.Rels { + if rel.Name == rlsName { + return &rls.GetReleaseContentResponse{ + Release: rel, + }, nil } } - return resp, c.Err + return resp, fmt.Errorf("No such release: %s", rlsName) } // ReleaseHistory returns a release's revision history. func (c *FakeClient) ReleaseHistory(rlsName string, opts ...HistoryOption) (*rls.GetHistoryResponse, error) { - return &rls.GetHistoryResponse{Releases: c.Rels}, c.Err + return &rls.GetHistoryResponse{Releases: c.Rels}, nil } // RunReleaseTest executes a pre-defined tests on a release @@ -147,8 +200,3 @@ func (c *FakeClient) RunReleaseTest(rlsName string, opts ...ReleaseTestOption) ( return results, errc } - -// Option returns the fake release client -func (c *FakeClient) Option(opt ...Option) Interface { - return c -} diff --git a/pkg/helm/fake_test.go b/pkg/helm/fake_test.go index 50580275c..7a83064b5 100644 --- a/pkg/helm/fake_test.go +++ b/pkg/helm/fake_test.go @@ -20,6 +20,7 @@ import ( "reflect" "testing" + "k8s.io/helm/pkg/proto/hapi/chart" "k8s.io/helm/pkg/proto/hapi/release" rls "k8s.io/helm/pkg/proto/hapi/services" ) @@ -114,3 +115,175 @@ func TestFakeClient_ReleaseStatus(t *testing.T) { }) } } + +func TestFakeClient_InstallReleaseFromChart(t *testing.T) { + installChart := &chart.Chart{} + type fields struct { + Rels []*release.Release + } + type args struct { + ns string + opts []InstallOption + } + tests := []struct { + name string + fields fields + args args + want *rls.InstallReleaseResponse + relsAfter []*release.Release + wantErr bool + }{ + { + name: "Add release to an empty list.", + fields: fields{ + Rels: []*release.Release{}, + }, + args: args{ + ns: "default", + opts: []InstallOption{ReleaseName("new-release")}, + }, + want: &rls.InstallReleaseResponse{ + Release: &release.Release{ + Name: "new-release", + Namespace: "default", + }, + }, + relsAfter: []*release.Release{ + {Name: "new-release", Namespace: "default"}, + }, + wantErr: false, + }, + { + name: "Try to add a release where the name already exists.", + fields: fields{ + Rels: []*release.Release{ + &release.Release{ + Name: "new-release", + Namespace: "default", + }, + }, + }, + args: args{ + ns: "default", + opts: []InstallOption{ReleaseName("new-release")}, + }, + relsAfter: []*release.Release{ + { + Name: "new-release", + Namespace: "default", + }, + }, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &FakeClient{ + Rels: tt.fields.Rels, + } + got, err := c.InstallReleaseFromChart(installChart, tt.args.ns, tt.args.opts...) + if (err != nil) != tt.wantErr { + t.Errorf("FakeClient.InstallReleaseFromChart() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("FakeClient.InstallReleaseFromChart() = %v, want %v", got, tt.want) + } + if !reflect.DeepEqual(c.Rels, tt.relsAfter) { + t.Errorf("FakeClient.InstallReleaseFromChart() rels = %v, expected %v", got, tt.relsAfter) + } + }) + } +} + +func TestFakeClient_DeleteRelease(t *testing.T) { + type fields struct { + Rels []*release.Release + } + type args struct { + rlsName string + opts []DeleteOption + } + tests := []struct { + name string + fields fields + args args + want *rls.UninstallReleaseResponse + relsAfter []*release.Release + wantErr bool + }{ + { + name: "Delete a release that exists.", + fields: fields{ + Rels: []*release.Release{ + { + Name: "angry-dolphin", + }, + { + Name: "trepid-tapir", + }, + }, + }, + args: args{ + rlsName: "trepid-tapir", + opts: []DeleteOption{}, + }, + relsAfter: []*release.Release{ + { + Name: "angry-dolphin", + }, + }, + want: &rls.UninstallReleaseResponse{ + Release: &release.Release{Name: "trepid-tapir"}, + }, + wantErr: false, + }, + { + name: "Delete a release that does not exist.", + fields: fields{ + Rels: []*release.Release{ + { + Name: "angry-dolphin", + }, + { + Name: "trepid-tapir", + }, + }, + }, + args: args{ + rlsName: "release-that-does-not-exists", + opts: []DeleteOption{}, + }, + relsAfter: []*release.Release{ + { + Name: "angry-dolphin", + }, + { + Name: "trepid-tapir", + }, + }, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &FakeClient{ + Rels: tt.fields.Rels, + } + got, err := c.DeleteRelease(tt.args.rlsName, tt.args.opts...) + if (err != nil) != tt.wantErr { + t.Errorf("FakeClient.DeleteRelease() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("FakeClient.DeleteRelease() = %v, want %v", got, tt.want) + } + + if !reflect.DeepEqual(c.Rels, tt.relsAfter) { + t.Errorf("FakeClient.InstallReleaseFromChart() rels = %v, expected %v", got, tt.relsAfter) + } + }) + } +} From 8d5cf13f69461d5b8748cfa26043ad1b4060d830 Mon Sep 17 00:00:00 2001 From: Brad Bowman Date: Wed, 11 Oct 2017 14:46:07 -0600 Subject: [PATCH 016/107] Add test case for deleting the only existing item --- pkg/helm/fake_test.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/pkg/helm/fake_test.go b/pkg/helm/fake_test.go index 7a83064b5..ee60648c0 100644 --- a/pkg/helm/fake_test.go +++ b/pkg/helm/fake_test.go @@ -266,6 +266,25 @@ func TestFakeClient_DeleteRelease(t *testing.T) { want: nil, wantErr: true, }, + { + name: "Delete when only 1 item exists.", + fields: fields{ + Rels: []*release.Release{ + { + Name: "trepid-tapir", + }, + }, + }, + args: args{ + rlsName: "trepid-tapir", + opts: []DeleteOption{}, + }, + relsAfter: []*release.Release{}, + want: &rls.UninstallReleaseResponse{ + Release: &release.Release{Name: "trepid-tapir"}, + }, + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From 2b43ecd405238a476729f192ab18349a4dcbdc98 Mon Sep 17 00:00:00 2001 From: Adam Reese Date: Wed, 11 Oct 2017 15:05:27 -0700 Subject: [PATCH 017/107] ref(*): kubernetes v1.8 support --- cmd/helm/helm.go | 8 +- cmd/helm/init_test.go | 4 +- cmd/helm/installer/install.go | 4 +- cmd/helm/installer/install_test.go | 4 +- cmd/helm/installer/options.go | 2 +- cmd/helm/installer/uninstall.go | 2 +- cmd/helm/reset.go | 2 +- glide.lock | 447 ++++++++++++++----- glide.yaml | 32 +- pkg/helm/portforwarder/pod.go | 2 +- pkg/helm/portforwarder/portforwarder.go | 2 +- pkg/helm/portforwarder/portforwarder_test.go | 2 +- pkg/kube/client.go | 28 +- pkg/kube/client_test.go | 2 +- pkg/kube/tunnel.go | 6 +- pkg/kube/wait.go | 53 +-- 16 files changed, 392 insertions(+), 208 deletions(-) diff --git a/cmd/helm/helm.go b/cmd/helm/helm.go index 6fe08b07e..4d3a9ae83 100644 --- a/cmd/helm/helm.go +++ b/cmd/helm/helm.go @@ -239,16 +239,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. diff --git a/cmd/helm/init_test.go b/cmd/helm/init_test.go index a5770f698..4513315b7 100644 --- a/cmd/helm/init_test.go +++ b/cmd/helm/init_test.go @@ -27,12 +27,12 @@ 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" diff --git a/cmd/helm/installer/install.go b/cmd/helm/installer/install.go index b20169e05..c3d970726 100644 --- a/cmd/helm/installer/install.go +++ b/cmd/helm/installer/install.go @@ -22,14 +22,14 @@ import ( "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" ) diff --git a/cmd/helm/installer/install_test.go b/cmd/helm/installer/install_test.go index 23a4a7a1d..f0ee61853 100644 --- a/cmd/helm/installer/install_test.go +++ b/cmd/helm/installer/install_test.go @@ -23,11 +23,11 @@ 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" diff --git a/cmd/helm/installer/options.go b/cmd/helm/installer/options.go index e03482172..6ea60935a 100644 --- a/cmd/helm/installer/options.go +++ b/cmd/helm/installer/options.go @@ -19,7 +19,7 @@ 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" ) diff --git a/cmd/helm/installer/uninstall.go b/cmd/helm/installer/uninstall.go index 3d0710969..818827ddb 100644 --- a/cmd/helm/installer/uninstall.go +++ b/cmd/helm/installer/uninstall.go @@ -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" diff --git a/cmd/helm/reset.go b/cmd/helm/reset.go index cc0415061..707c3d0be 100644 --- a/cmd/helm/reset.go +++ b/cmd/helm/reset.go @@ -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) } diff --git a/glide.lock b/glide.lock index c368466fb..06ee4088b 100644 --- a/glide.lock +++ b/glide.lock @@ -1,14 +1,22 @@ -hash: 0759b118eb4017d612af767460cdec467d6f78013ad1efff1c82676f1df84a75 -updated: 2017-09-26T15:21:30.833774-07:00 +hash: f5e472b397d20aaa131c8eada3966fdbbf65457073bd1ee8fb8b349bf39c522a +updated: 2017-10-09T13:32:53.067503253-07:00 imports: - name: cloud.google.com/go version: 3b1ae45394a234c385be014e9a488f2bb6eef821 + subpackages: + - compute/metadata + - internal - name: github.com/aokoli/goutils version: 9c37978a95bd5c709a15883b6242714ea6709e64 - name: github.com/asaskevich/govalidator version: 7664702784775e51966f0885f5cd27435916517b - name: github.com/Azure/go-autorest version: 58f6f26e200fa5dfb40c9cd1c83f3e2c860d779d + subpackages: + - autorest + - autorest/adal + - autorest/azure + - autorest/date - name: github.com/beorn7/perks version: 3ac7bf7a47d159a033b107610db8a1b6575507a4 subpackages: @@ -22,42 +30,59 @@ imports: subpackages: - md2man - name: github.com/davecgh/go-spew - version: 5215b55f46b2b919f50a1df0eaa5886afe4e3b3d + version: 782f4967f2dc4564575ca782fe2d04090b5faca8 subpackages: - spew - name: github.com/dgrijalva/jwt-go version: 01aeca54ebda6e0fbfafd0a524d234159c05ec20 - name: github.com/docker/distribution - version: 03efb43768979f4d2ea5187bef995656441829e5 + version: edc3ab29cdff8694dd6feb85cfeb4b5f1b38ed9c subpackages: - - digest + - digestset - reference -- name: github.com/docker/engine-api - version: dea108d3aa0c67d7162a3fd8aa65f38a430019fd - subpackages: +- name: github.com/docker/docker + version: 4f3616fb1c112e206b88cb7a9922bf49067a7756 + subpackages: + - api + - api/types + - api/types/blkiodev + - api/types/container + - api/types/events + - api/types/filters + - api/types/image + - api/types/mount + - api/types/network + - api/types/registry + - api/types/strslice + - api/types/swarm + - api/types/swarm/runtime + - api/types/time + - api/types/versions + - api/types/volume - client - - client/transport - - client/transport/cancellable - - types - - types/blkiodev - - types/container - - types/filters - - types/network - - types/reference - - types/registry - - types/strslice - - types/time - - types/versions + - pkg/ioutils + - pkg/jsonlog + - pkg/jsonmessage + - pkg/longpath + - pkg/mount + - pkg/stdcopy + - pkg/symlink + - pkg/system + - pkg/term + - pkg/term/windows + - pkg/tlsconfig - name: github.com/docker/go-connections - version: f549a9393d05688dff0992ef3efd8bbe6c628aeb + version: 3ede32e2033de7505e6500d6c868c2b9ed9f169d subpackages: - nat - sockets - tlsconfig - name: github.com/docker/go-units - version: e30f1e79f3cd72542f2026ceec18d3bd67ab859c + version: 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1 - name: github.com/docker/spdystream version: 449fdfce4d962303d702fec724ef0ad181c92528 + subpackages: + - spdy - name: github.com/emicklei/go-restful version: ff4f55a206334ef123e4f79bbf348980da81ca46 subpackages: @@ -65,27 +90,19 @@ imports: - name: github.com/emicklei/go-restful-swagger12 version: dcef7f55730566d41eae5db10e7d6981829720f6 - name: github.com/evanphx/json-patch - version: ba18e35c5c1b36ef6334cad706eb681153d2d379 + version: 944e07253867aacae43c04b2e6a239005443f33a - name: github.com/exponent-io/jsonpath version: d6023ce2651d8eafb5c75bb0c7167536102ec9f5 - name: github.com/fatih/camelcase version: f6a740d52f961c60348ebb109adde9f4635d7540 - name: github.com/ghodss/yaml version: 73d445a93680fa1a78ae23a5839bad48f32ba1ee -- name: github.com/go-openapi/analysis - version: b44dc874b601d9e4e2f6e19140e794ba24bead3b -- name: github.com/go-openapi/errors - version: d24ebc2075bad502fac3a8ae27aa6dd58e1952dc - name: github.com/go-openapi/jsonpointer version: 46af16f9f7b149af66e5d1bd010e3574dc06de98 - name: github.com/go-openapi/jsonreference version: 13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272 -- name: github.com/go-openapi/loads - version: 18441dfa706d924a39a030ee2c3b1d8d81917b38 - name: github.com/go-openapi/spec version: 6aced65f8501fe1217321abf0749d354824ba2ff -- name: github.com/go-openapi/strfmt - version: d65c7fdb29eca313476e529628176fe17e58c488 - name: github.com/go-openapi/swag version: 1d0bd113de87027671077d3c71eb3ac5d7dbba72 - name: github.com/gobwas/glob @@ -101,31 +118,8 @@ imports: - name: github.com/gogo/protobuf version: c0656edd0d9eab7c66d1eb0c568f9039345796f7 subpackages: - - gogoproto - - plugin/compare - - plugin/defaultcheck - - plugin/description - - plugin/embedcheck - - plugin/enumstringer - - plugin/equal - - plugin/face - - plugin/gostring - - plugin/marshalto - - plugin/oneofcheck - - plugin/populate - - plugin/size - - plugin/stringer - - plugin/testgen - - plugin/union - - plugin/unmarshal - proto - - protoc-gen-gogo/descriptor - - protoc-gen-gogo/generator - - protoc-gen-gogo/grpc - - protoc-gen-gogo/plugin - sortkeys - - vanity - - vanity/command - name: github.com/golang/glog version: 44145f04b68cf362d9c4df2182967c2275eaefed - name: github.com/golang/groupcache @@ -136,27 +130,54 @@ imports: version: 4bd1920723d7b7c925de087aa32e2187708897f7 subpackages: - proto + - ptypes - ptypes/any + - ptypes/duration - ptypes/timestamp +- name: github.com/google/btree + version: 7d79101e329e5a3adf994758c578dab82b90c017 - name: github.com/google/gofuzz version: 44d81051d367757e1c7c6a5a86423ece9afcf63c +- name: github.com/googleapis/gnostic + version: 0c5108395e2debce0d731cf0287ddf7242066aba + subpackages: + - OpenAPIv2 + - compiler + - extensions +- name: github.com/gophercloud/gophercloud + version: 2bf16b94fdd9b01557c4d076e567fe5cbbe5a961 + subpackages: + - openstack + - openstack/identity/v2/tenants + - openstack/identity/v2/tokens + - openstack/identity/v3/tokens + - openstack/utils + - pagination - name: github.com/gosuri/uitable version: 36ee7e946282a3fb1cfecd476ddc9b35d8847e42 subpackages: - util/strutil - util/wordwrap +- name: github.com/gregjones/httpcache + version: 787624de3eb7bd915c329cba748687a3b22666a6 + subpackages: + - diskcache - name: github.com/grpc-ecosystem/go-grpc-prometheus - version: 2500245aa6110c562d17020fb31a2c133d737799 + version: 0c1b191dbfe51efdabe3c14b9f6f3b96429e0722 - name: github.com/hashicorp/golang-lru version: a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4 + subpackages: + - simplelru - name: github.com/howeyc/gopass - version: 3ca23474a7c7203e0a0a070fd33508f6efdb9b3d + version: bf9dde6d0d2c004a008c27aaee91170c786f6db8 - name: github.com/huandu/xstrings version: 3959339b333561bf62a38b424fd41517c2c90f40 - name: github.com/imdario/mergo version: 6633656539c1639d9d78127b7d47c622b5d7b6dc - name: github.com/inconshreveable/mousetrap version: 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 +- name: github.com/json-iterator/go + version: 36b14963da70d11297d313183d7e6388c8510e1e - name: github.com/juju/ratelimit version: 5b9ff866471762aa2ab2dced63c9fb6f53921342 - name: github.com/mailru/easyjson @@ -168,7 +189,7 @@ imports: - name: github.com/Masterminds/semver version: 517734cc7d6470c0d07130e40fd40bdeb9bcd3fd - name: github.com/Masterminds/sprig - version: 4c164950cd0a8d3724ddb78982e2c56dc7f47112 + version: efda631a76d70875162cdc25ffa0d0164bf69758 - name: github.com/Masterminds/vcs version: 3084677c2c188840777bff30054f2b553729d329 - name: github.com/mattn/go-runewidth @@ -177,12 +198,19 @@ imports: version: fc2b8d3a73c4867e51861bbdd5ae3c1f0869dd6a subpackages: - pbutil -- name: github.com/mitchellh/mapstructure - version: 740c764bc6149d3f1806231418adb9f52c11bcbf - name: github.com/naoina/go-stringutil version: 6b638e95a32d0c1131db0e7fe83775cbea4a0d0b +- name: github.com/opencontainers/go-digest + version: a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb +- name: github.com/opencontainers/image-spec + version: 372ad780f63454fbbbbcc7cf80e5b90245c13e13 + subpackages: + - specs-go + - specs-go/v1 - name: github.com/pborman/uuid version: ca53cad383cad2479bbba7f7a1a05797ec1386e4 +- name: github.com/peterbourgon/diskv + version: 5f041e8faa004a95c88a202771f4cc3e991971e6 - name: github.com/prometheus/client_golang version: c5b7fccd204277076155f10851dad72b76a49317 subpackages: @@ -219,14 +247,13 @@ imports: - name: github.com/spf13/pflag version: 9ff6c6923cfffbcd502984b8e0c80539a94968b7 - name: github.com/technosophos/moniker - version: 9f956786b91d9786ca11aa5be6104542fa911546 + version: ab470f5e105a44d0c87ea21bacd6a335c4816d83 - name: github.com/ugorji/go version: ded73eae5db7e7a0ef6f55aace87a2873c5d2b74 subpackages: - codec - - codec/codecgen - name: golang.org/x/crypto - version: d172538b2cfce0c13cee31e647d0367aa8cd2486 + version: 81e90905daefcd6fd217b62423c0908922eadb30 subpackages: - cast5 - openpgp @@ -240,9 +267,10 @@ imports: - scrypt - ssh/terminal - name: golang.org/x/net - version: f2499483f923065a842d38eb4c7f1927e6fc6e6d + version: 1c05540f6879653db88113bc4a2b70aec4bd491f subpackages: - context + - context/ctxhttp - http2 - http2/hpack - idna @@ -251,18 +279,25 @@ imports: - trace - name: golang.org/x/oauth2 version: a6bd8cefa1811bd24b86f8902872e4e8225f74c4 + subpackages: + - google + - internal + - jws + - jwt - name: golang.org/x/sys version: 8f0908ab3b2457e2e15403d3697c9ef5cb4b57a9 subpackages: - unix + - windows - name: golang.org/x/text - version: 2910a502d2bf9e43193af9d68ca516529614eed3 + version: b19bf474d317b857955b12035d2c5acb57ce8b01 subpackages: - cases - encoding - encoding/internal - encoding/internal/identifier - encoding/unicode + - internal - internal/tag - internal/utf8internal - language @@ -273,6 +308,18 @@ imports: - unicode/bidi - unicode/norm - width +- name: google.golang.org/appengine + version: 12d5545dc1cfa6047a286d5e853841b6471f4c19 + subpackages: + - internal + - internal/app_identity + - internal/base + - internal/datastore + - internal/log + - internal/modules + - internal/remote_api + - internal/urlfetch + - urlfetch - name: google.golang.org/grpc version: 8050b9cbc271307e5a716a9d782803d09b0d6f2d subpackages: @@ -289,23 +336,105 @@ imports: - transport - name: gopkg.in/inf.v0 version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4 -- name: gopkg.in/mgo.v2 - version: 3f83fa5005286a7fe593b055f0d7771a7dce4655 - subpackages: - - bson - name: gopkg.in/yaml.v2 version: 53feefa2559fb8dfa8d81baad31be332c97d6c77 - name: k8s.io/api - version: 4fe9229aaa9d704f8a2a21cdcd50de2bbb6e1b57 - subpackages: + version: cadaf100c0a3dd6b254f320d6d651df079ec8e0a + subpackages: + - admission/v1alpha1 + - admissionregistration/v1alpha1 + - apps/v1beta1 + - apps/v1beta2 + - authentication/v1 + - authentication/v1beta1 + - authorization/v1 + - authorization/v1beta1 + - autoscaling/v1 + - autoscaling/v2beta1 + - batch/v1 + - batch/v1beta1 + - batch/v2alpha1 + - certificates/v1beta1 - core/v1 + - extensions/v1beta1 + - imagepolicy/v1alpha1 + - networking/v1 + - policy/v1beta1 + - rbac/v1 + - rbac/v1alpha1 + - rbac/v1beta1 + - scheduling/v1alpha1 + - settings/v1alpha1 + - storage/v1 + - storage/v1beta1 +- name: k8s.io/apiextensions-apiserver + version: a5bbfd114a9b122acd741c61d88c84812375d9e1 + subpackages: + - pkg/features +- name: k8s.io/apimachinery + version: 3b05bbfa0a45413bfa184edbf9af617e277962fb + subpackages: + - pkg/api/equality + - pkg/api/errors + - pkg/api/meta + - pkg/api/resource + - pkg/api/validation + - pkg/apimachinery + - pkg/apimachinery/announced + - pkg/apimachinery/registered + - pkg/apis/meta/internalversion + - pkg/apis/meta/v1 + - pkg/apis/meta/v1/unstructured + - pkg/apis/meta/v1/validation + - pkg/apis/meta/v1alpha1 + - pkg/conversion + - pkg/conversion/queryparams + - pkg/conversion/unstructured + - pkg/fields + - pkg/labels + - pkg/runtime + - pkg/runtime/schema + - pkg/runtime/serializer + - pkg/runtime/serializer/json + - pkg/runtime/serializer/protobuf + - pkg/runtime/serializer/recognizer + - pkg/runtime/serializer/streaming + - pkg/runtime/serializer/versioning + - pkg/selection + - pkg/types + - pkg/util/cache + - pkg/util/clock + - pkg/util/diff + - pkg/util/errors + - pkg/util/framer + - pkg/util/httpstream + - pkg/util/httpstream/spdy + - pkg/util/intstr + - pkg/util/json + - pkg/util/mergepatch + - pkg/util/net + - pkg/util/rand + - pkg/util/runtime + - pkg/util/sets + - pkg/util/strategicpatch + - pkg/util/uuid + - pkg/util/validation + - pkg/util/validation/field + - pkg/util/wait + - pkg/util/yaml + - pkg/version + - pkg/watch + - third_party/forked/golang/json + - third_party/forked/golang/netutil + - third_party/forked/golang/reflect - name: k8s.io/apiserver - version: 2308857ad3b8b18abf74ff734853973eda9da94d + version: c1e53d745d0fe45bf7d5d44697e6eface25fceca subpackages: - pkg/admission - pkg/apis/apiserver - pkg/apis/apiserver/install - pkg/apis/apiserver/v1alpha1 + - pkg/apis/audit - pkg/authentication/authenticator - pkg/authentication/serviceaccount - pkg/authentication/user @@ -313,20 +442,118 @@ imports: - pkg/features - pkg/util/feature - pkg/util/flag +- name: k8s.io/client-go + version: 82aa063804cf055e16e8911250f888bc216e8b61 + subpackages: + - discovery + - discovery/fake + - dynamic + - informers/apps/v1beta1 + - informers/core/v1 + - informers/extensions/v1beta1 + - informers/internalinterfaces + - kubernetes + - kubernetes/fake + - kubernetes/scheme + - kubernetes/typed/admissionregistration/v1alpha1 + - kubernetes/typed/admissionregistration/v1alpha1/fake + - kubernetes/typed/apps/v1beta1 + - kubernetes/typed/apps/v1beta1/fake + - kubernetes/typed/apps/v1beta2 + - kubernetes/typed/apps/v1beta2/fake + - kubernetes/typed/authentication/v1 + - kubernetes/typed/authentication/v1/fake + - kubernetes/typed/authentication/v1beta1 + - kubernetes/typed/authentication/v1beta1/fake + - kubernetes/typed/authorization/v1 + - kubernetes/typed/authorization/v1/fake + - kubernetes/typed/authorization/v1beta1 + - kubernetes/typed/authorization/v1beta1/fake + - kubernetes/typed/autoscaling/v1 + - kubernetes/typed/autoscaling/v1/fake + - kubernetes/typed/autoscaling/v2beta1 + - kubernetes/typed/autoscaling/v2beta1/fake + - kubernetes/typed/batch/v1 + - kubernetes/typed/batch/v1/fake + - kubernetes/typed/batch/v1beta1 + - kubernetes/typed/batch/v1beta1/fake + - kubernetes/typed/batch/v2alpha1 + - kubernetes/typed/batch/v2alpha1/fake + - kubernetes/typed/certificates/v1beta1 + - kubernetes/typed/certificates/v1beta1/fake + - kubernetes/typed/core/v1 + - kubernetes/typed/core/v1/fake + - kubernetes/typed/extensions/v1beta1 + - kubernetes/typed/extensions/v1beta1/fake + - kubernetes/typed/networking/v1 + - kubernetes/typed/networking/v1/fake + - kubernetes/typed/policy/v1beta1 + - kubernetes/typed/policy/v1beta1/fake + - kubernetes/typed/rbac/v1 + - kubernetes/typed/rbac/v1/fake + - kubernetes/typed/rbac/v1alpha1 + - kubernetes/typed/rbac/v1alpha1/fake + - kubernetes/typed/rbac/v1beta1 + - kubernetes/typed/rbac/v1beta1/fake + - kubernetes/typed/scheduling/v1alpha1 + - kubernetes/typed/scheduling/v1alpha1/fake + - kubernetes/typed/settings/v1alpha1 + - kubernetes/typed/settings/v1alpha1/fake + - kubernetes/typed/storage/v1 + - kubernetes/typed/storage/v1/fake + - kubernetes/typed/storage/v1beta1 + - kubernetes/typed/storage/v1beta1/fake + - listers/apps/v1beta1 + - listers/core/v1 + - listers/extensions/v1beta1 + - pkg/version + - plugin/pkg/client/auth + - plugin/pkg/client/auth/azure + - plugin/pkg/client/auth/gcp + - plugin/pkg/client/auth/oidc + - plugin/pkg/client/auth/openstack + - rest + - rest/fake + - rest/watch + - testing + - third_party/forked/golang/template + - tools/auth + - tools/cache + - tools/clientcmd + - tools/clientcmd/api + - tools/clientcmd/api/latest + - tools/clientcmd/api/v1 + - tools/metrics + - tools/pager + - tools/portforward + - tools/record + - tools/reference + - transport + - transport/spdy + - util/cert + - util/flowcontrol + - util/homedir + - util/integer + - util/jsonpath + - util/retry + - util/workqueue +- name: k8s.io/kube-openapi + version: 868f2f29720b192240e18284659231b440f9cda5 + subpackages: + - pkg/common - name: k8s.io/kubernetes - version: d3faa3f8f2e85c8089e80a661955626ae24abf80 + version: 0b9efaeb34a2fc51ff8e4d34ad9bc6375459c4a4 subpackages: - - cmd/kubeadm/app/apis/kubeadm - federation/apis/federation - federation/apis/federation/install - federation/apis/federation/v1beta1 - - federation/client/clientset_generated/federation_internalclientset - - federation/client/clientset_generated/federation_internalclientset/scheme - - federation/client/clientset_generated/federation_internalclientset/typed/autoscaling/internalversion - - federation/client/clientset_generated/federation_internalclientset/typed/batch/internalversion - - federation/client/clientset_generated/federation_internalclientset/typed/core/internalversion - - federation/client/clientset_generated/federation_internalclientset/typed/extensions/internalversion - - federation/client/clientset_generated/federation_internalclientset/typed/federation/internalversion + - federation/client/clientset_generated/federation_clientset + - federation/client/clientset_generated/federation_clientset/scheme + - federation/client/clientset_generated/federation_clientset/typed/autoscaling/v1 + - federation/client/clientset_generated/federation_clientset/typed/batch/v1 + - federation/client/clientset_generated/federation_clientset/typed/core/v1 + - federation/client/clientset_generated/federation_clientset/typed/extensions/v1beta1 + - federation/client/clientset_generated/federation_clientset/typed/federation/v1beta1 - pkg/api - pkg/api/events - pkg/api/helper @@ -342,7 +569,6 @@ imports: - pkg/api/v1/helper - pkg/api/v1/helper/qos - pkg/api/v1/pod - - pkg/api/v1/ref - pkg/api/validation - pkg/apis/admission - pkg/apis/admission/install @@ -353,6 +579,7 @@ imports: - pkg/apis/apps - pkg/apis/apps/install - pkg/apis/apps/v1beta1 + - pkg/apis/apps/v1beta2 - pkg/apis/authentication - pkg/apis/authentication/install - pkg/apis/authentication/v1 @@ -364,10 +591,11 @@ imports: - pkg/apis/autoscaling - pkg/apis/autoscaling/install - pkg/apis/autoscaling/v1 - - pkg/apis/autoscaling/v2alpha1 + - pkg/apis/autoscaling/v2beta1 - pkg/apis/batch - pkg/apis/batch/install - pkg/apis/batch/v1 + - pkg/apis/batch/v1beta1 - pkg/apis/batch/v2alpha1 - pkg/apis/certificates - pkg/apis/certificates/install @@ -389,8 +617,12 @@ imports: - pkg/apis/policy/v1beta1 - pkg/apis/rbac - pkg/apis/rbac/install + - pkg/apis/rbac/v1 - pkg/apis/rbac/v1alpha1 - pkg/apis/rbac/v1beta1 + - pkg/apis/scheduling + - pkg/apis/scheduling/install + - pkg/apis/scheduling/v1alpha1 - pkg/apis/settings - pkg/apis/settings/install - pkg/apis/settings/v1alpha1 @@ -400,28 +632,6 @@ imports: - pkg/apis/storage/v1 - pkg/apis/storage/v1beta1 - pkg/capabilities - - pkg/client/clientset_generated/clientset - - pkg/client/clientset_generated/clientset/scheme - - pkg/client/clientset_generated/clientset/typed/admissionregistration/v1alpha1 - - pkg/client/clientset_generated/clientset/typed/apps/v1beta1 - - pkg/client/clientset_generated/clientset/typed/authentication/v1 - - pkg/client/clientset_generated/clientset/typed/authentication/v1beta1 - - pkg/client/clientset_generated/clientset/typed/authorization/v1 - - pkg/client/clientset_generated/clientset/typed/authorization/v1beta1 - - pkg/client/clientset_generated/clientset/typed/autoscaling/v1 - - pkg/client/clientset_generated/clientset/typed/autoscaling/v2alpha1 - - pkg/client/clientset_generated/clientset/typed/batch/v1 - - pkg/client/clientset_generated/clientset/typed/batch/v2alpha1 - - pkg/client/clientset_generated/clientset/typed/certificates/v1beta1 - - pkg/client/clientset_generated/clientset/typed/core/v1 - - pkg/client/clientset_generated/clientset/typed/extensions/v1beta1 - - pkg/client/clientset_generated/clientset/typed/networking/v1 - - pkg/client/clientset_generated/clientset/typed/policy/v1beta1 - - pkg/client/clientset_generated/clientset/typed/rbac/v1alpha1 - - pkg/client/clientset_generated/clientset/typed/rbac/v1beta1 - - pkg/client/clientset_generated/clientset/typed/settings/v1alpha1 - - pkg/client/clientset_generated/clientset/typed/storage/v1 - - pkg/client/clientset_generated/clientset/typed/storage/v1beta1 - pkg/client/clientset_generated/internalclientset - pkg/client/clientset_generated/internalclientset/fake - pkg/client/clientset_generated/internalclientset/scheme @@ -449,24 +659,19 @@ imports: - pkg/client/clientset_generated/internalclientset/typed/policy/internalversion/fake - pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion - pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion/fake + - pkg/client/clientset_generated/internalclientset/typed/scheduling/internalversion + - pkg/client/clientset_generated/internalclientset/typed/scheduling/internalversion/fake - pkg/client/clientset_generated/internalclientset/typed/settings/internalversion - pkg/client/clientset_generated/internalclientset/typed/settings/internalversion/fake - pkg/client/clientset_generated/internalclientset/typed/storage/internalversion - pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/fake - - pkg/client/informers/informers_generated/externalversions/apps/v1beta1 - - pkg/client/informers/informers_generated/externalversions/core/v1 - - pkg/client/informers/informers_generated/externalversions/extensions/v1beta1 - - pkg/client/informers/informers_generated/externalversions/internalinterfaces - - pkg/client/leaderelection/resourcelock - - pkg/client/listers/apps/v1beta1 - - pkg/client/listers/core/v1 - - pkg/client/listers/extensions/v1beta1 - - pkg/client/retry - pkg/client/unversioned - pkg/controller - pkg/controller/daemon - pkg/controller/daemon/util - pkg/controller/deployment/util + - pkg/controller/history + - pkg/controller/statefulset - pkg/credentialprovider - pkg/features - pkg/fieldpath @@ -474,9 +679,13 @@ imports: - pkg/kubectl/cmd/testing - pkg/kubectl/cmd/util - pkg/kubectl/cmd/util/openapi + - pkg/kubectl/cmd/util/openapi/validation - pkg/kubectl/plugins - pkg/kubectl/resource - pkg/kubectl/util + - pkg/kubectl/util/hash + - pkg/kubectl/util/slice + - pkg/kubectl/validation - pkg/kubelet/apis - pkg/kubelet/qos - pkg/kubelet/types @@ -486,16 +695,18 @@ imports: - pkg/registry/rbac/validation - pkg/security/apparmor - pkg/serviceaccount - - pkg/util - - pkg/util/exec + - pkg/util/file - pkg/util/hash + - pkg/util/io - pkg/util/labels - pkg/util/metrics - pkg/util/mount - pkg/util/net/sets - pkg/util/node - pkg/util/parsers + - pkg/util/pointer - pkg/util/slice + - pkg/util/taints - pkg/version - pkg/volume/util - pkg/watch/json @@ -505,6 +716,7 @@ imports: - plugin/pkg/scheduler/api - plugin/pkg/scheduler/schedulercache - plugin/pkg/scheduler/util + - staging/src/k8s.io/apimachinery/pkg/util/rand - name: k8s.io/metrics version: 8efbc8e22d00b9c600afec5f1c14073fd2412fce subpackages: @@ -513,6 +725,11 @@ imports: - pkg/client/clientset_generated/clientset - pkg/client/clientset_generated/clientset/scheme - pkg/client/clientset_generated/clientset/typed/metrics/v1alpha1 +- name: k8s.io/utils + version: 9fdc871a36f37980dd85f96d576b20d564cc0784 + subpackages: + - exec + - exec/testing - name: vbom.ml/util version: db5cfe13f5cc80a4990d98e2e1b0707a4d1a5394 repo: https://github.com/fvbommel/util.git diff --git a/glide.yaml b/glide.yaml index 6b231c417..5aa459ca5 100644 --- a/glide.yaml +++ b/glide.yaml @@ -28,7 +28,7 @@ import: - package: google.golang.org/grpc version: 1.2.1 - package: k8s.io/kubernetes - version: ~1.7.0 + version: ~1.8.0 - package: github.com/gosuri/uitable - package: github.com/asaskevich/govalidator version: ^4.0.0 @@ -48,37 +48,7 @@ import: - package: vbom.ml/util repo: https://github.com/fvbommel/util.git vcs: git -- package: github.com/docker/distribution - version: ~2.4.0 -# hacks for kubernetes v1.7 -- package: cloud.google.com/go -- package: github.com/Azure/go-autorest - version: v8.0.0 -- package: github.com/dgrijalva/jwt-go -- package: github.com/docker/spdystream -- package: github.com/go-openapi/analysis - version: b44dc874b601d9e4e2f6e19140e794ba24bead3b -- package: github.com/go-openapi/errors - version: d24ebc2075bad502fac3a8ae27aa6dd58e1952dc -- package: github.com/go-openapi/loads - version: 18441dfa706d924a39a030ee2c3b1d8d81917b38 -- package: github.com/go-openapi/spec - version: 6aced65f8501fe1217321abf0749d354824ba2ff -- package: github.com/google/gofuzz -- package: github.com/hashicorp/golang-lru -- package: github.com/howeyc/gopass -- package: github.com/juju/ratelimit - version: 5b9ff866471762aa2ab2dced63c9fb6f53921342 -- package: github.com/pborman/uuid -- package: golang.org/x/oauth2 -- package: gopkg.in/inf.v0 -- package: github.com/go-openapi/strfmt -- package: github.com/mitchellh/mapstructure -- package: gopkg.in/mgo.v2/bson -ignore: - - k8s.io/client-go - - k8s.io/apimachinery testImports: - package: github.com/stretchr/testify version: ^1.1.4 diff --git a/pkg/helm/portforwarder/pod.go b/pkg/helm/portforwarder/pod.go index e20d644ea..7c2355204 100644 --- a/pkg/helm/portforwarder/pod.go +++ b/pkg/helm/portforwarder/pod.go @@ -17,7 +17,7 @@ limitations under the License. package portforwarder import ( - "k8s.io/client-go/pkg/api/v1" + "k8s.io/api/core/v1" ) // These functions are adapted from the "kubernetes" repository's file diff --git a/pkg/helm/portforwarder/portforwarder.go b/pkg/helm/portforwarder/portforwarder.go index 617da7a13..87f697a74 100644 --- a/pkg/helm/portforwarder/portforwarder.go +++ b/pkg/helm/portforwarder/portforwarder.go @@ -19,11 +19,11 @@ package portforwarder import ( "fmt" + "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/client-go/kubernetes" corev1 "k8s.io/client-go/kubernetes/typed/core/v1" - "k8s.io/client-go/pkg/api/v1" "k8s.io/client-go/rest" "k8s.io/helm/pkg/kube" diff --git a/pkg/helm/portforwarder/portforwarder_test.go b/pkg/helm/portforwarder/portforwarder_test.go index f98e1f011..b9e90afa8 100644 --- a/pkg/helm/portforwarder/portforwarder_test.go +++ b/pkg/helm/portforwarder/portforwarder_test.go @@ -19,9 +19,9 @@ package portforwarder import ( "testing" + "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes/fake" - "k8s.io/client-go/pkg/api/v1" ) func mockTillerPod() v1.Pod { diff --git a/pkg/kube/client.go b/pkg/kube/client.go index a642ebc05..798434da4 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -27,6 +27,10 @@ import ( "time" jsonpatch "github.com/evanphx/json-patch" + apps "k8s.io/api/apps/v1beta2" + batch "k8s.io/api/batch/v1" + "k8s.io/api/core/v1" + "k8s.io/api/extensions/v1beta1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -40,15 +44,12 @@ import ( "k8s.io/client-go/tools/clientcmd" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/helper" - "k8s.io/kubernetes/pkg/api/v1" - apps "k8s.io/kubernetes/pkg/apis/apps/v1beta1" batchinternal "k8s.io/kubernetes/pkg/apis/batch" - batch "k8s.io/kubernetes/pkg/apis/batch/v1" - "k8s.io/kubernetes/pkg/apis/extensions/v1beta1" conditions "k8s.io/kubernetes/pkg/client/unversioned" "k8s.io/kubernetes/pkg/kubectl" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "k8s.io/kubernetes/pkg/kubectl/resource" + "k8s.io/kubernetes/pkg/kubectl/validation" "k8s.io/kubernetes/pkg/printers" ) @@ -103,13 +104,9 @@ func (c *Client) Create(namespace string, reader io.Reader, timeout int64, shoul } func (c *Client) newBuilder(namespace string, reader io.Reader) *resource.Result { - schema, err := c.Validator(true, c.SchemaCacheDir) - if err != nil { - c.Log("warning: failed to load schema: %s", err) - } return c.NewBuilder(true). ContinueOnError(). - Schema(schema). + Schema(c.validator()). NamespaceParam(namespace). DefaultNamespace(). Stream(reader, ""). @@ -117,20 +114,25 @@ func (c *Client) newBuilder(namespace string, reader io.Reader) *resource.Result Do() } -// BuildUnstructured validates for Kubernetes objects and returns unstructured infos. -func (c *Client) BuildUnstructured(namespace string, reader io.Reader) (Result, error) { - schema, err := c.Validator(true, c.SchemaCacheDir) +func (c *Client) validator() validation.Schema { + const openapi = false // only works on v1.8 clusters + schema, err := c.Validator(true, openapi, c.SchemaCacheDir) if err != nil { c.Log("warning: failed to load schema: %s", err) } + return schema +} +// BuildUnstructured validates for Kubernetes objects and returns unstructured infos. +func (c *Client) BuildUnstructured(namespace string, reader io.Reader) (Result, error) { var result Result + b, err := c.NewUnstructuredBuilder(true) if err != nil { return result, err } result, err = b.ContinueOnError(). - Schema(schema). + Schema(c.validator()). NamespaceParam(namespace). DefaultNamespace(). Stream(reader, ""). diff --git a/pkg/kube/client_test.go b/pkg/kube/client_test.go index 889a12f72..f8432f102 100644 --- a/pkg/kube/client_test.go +++ b/pkg/kube/client_test.go @@ -35,11 +35,11 @@ import ( "k8s.io/client-go/rest/fake" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/testapi" - "k8s.io/kubernetes/pkg/api/validation" "k8s.io/kubernetes/pkg/kubectl" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "k8s.io/kubernetes/pkg/kubectl/resource" + "k8s.io/kubernetes/pkg/kubectl/validation" "k8s.io/kubernetes/pkg/printers" watchjson "k8s.io/kubernetes/pkg/watch/json" ) diff --git a/pkg/kube/tunnel.go b/pkg/kube/tunnel.go index 9c8f31e60..6da0c4594 100644 --- a/pkg/kube/tunnel.go +++ b/pkg/kube/tunnel.go @@ -21,11 +21,12 @@ import ( "io" "io/ioutil" "net" + "net/http" "strconv" "k8s.io/client-go/rest" "k8s.io/client-go/tools/portforward" - "k8s.io/client-go/tools/remotecommand" + "k8s.io/client-go/transport/spdy" ) // Tunnel describes a ssh-like tunnel to a kubernetes pod @@ -71,10 +72,11 @@ func (t *Tunnel) ForwardPort() error { Name(t.PodName). SubResource("portforward").URL() - dialer, err := remotecommand.NewExecutor(t.config, "POST", u) + transport, upgrader, err := spdy.RoundTripperFor(t.config) if err != nil { return err } + dialer := spdy.NewDialer(upgrader, &http.Client{Transport: transport}, "POST", u) local, err := getAvailablePort() if err != nil { diff --git a/pkg/kube/wait.go b/pkg/kube/wait.go index 99a9bb15e..63e7c4a65 100644 --- a/pkg/kube/wait.go +++ b/pkg/kube/wait.go @@ -19,20 +19,18 @@ package kube // import "k8s.io/helm/pkg/kube" import ( "time" + appsv1beta1 "k8s.io/api/apps/v1beta1" + appsv1beta2 "k8s.io/api/apps/v1beta2" + "k8s.io/api/core/v1" + extensions "k8s.io/api/extensions/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/kubernetes/pkg/api/v1" + "k8s.io/client-go/kubernetes" "k8s.io/kubernetes/pkg/api/v1/helper" podutil "k8s.io/kubernetes/pkg/api/v1/pod" - apps "k8s.io/kubernetes/pkg/apis/apps/v1beta1" - extensions "k8s.io/kubernetes/pkg/apis/extensions/v1beta1" - "k8s.io/kubernetes/pkg/client/clientset_generated/clientset" - core "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/typed/core/v1" - extensionsclient "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/typed/extensions/v1beta1" - internalclientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" deploymentutil "k8s.io/kubernetes/pkg/controller/deployment/util" ) @@ -47,11 +45,10 @@ type deployment struct { func (c *Client) waitForResources(timeout time.Duration, created Result) error { c.Log("beginning wait for %d resources with timeout of %v", len(created), timeout) - cs, err := c.ClientSet() + kcs, err := c.KubernetesClientSet() if err != nil { return err } - client := versionedClientsetForDeployment(cs) return wait.Poll(2*time.Second, timeout, func() (bool, error) { pods := []v1.Pod{} services := []v1.Service{} @@ -64,24 +61,24 @@ func (c *Client) waitForResources(timeout time.Duration, created Result) error { } switch value := obj.(type) { case (*v1.ReplicationController): - list, err := getPods(client, value.Namespace, value.Spec.Selector) + list, err := getPods(kcs, value.Namespace, value.Spec.Selector) if err != nil { return false, err } pods = append(pods, list...) case (*v1.Pod): - pod, err := client.Core().Pods(value.Namespace).Get(value.Name, metav1.GetOptions{}) + pod, err := kcs.Core().Pods(value.Namespace).Get(value.Name, metav1.GetOptions{}) if err != nil { return false, err } pods = append(pods, *pod) case (*extensions.Deployment): - currentDeployment, err := client.Extensions().Deployments(value.Namespace).Get(value.Name, metav1.GetOptions{}) + currentDeployment, err := kcs.Extensions().Deployments(value.Namespace).Get(value.Name, metav1.GetOptions{}) if err != nil { return false, err } // Find RS associated with deployment - newReplicaSet, err := deploymentutil.GetNewReplicaSet(currentDeployment, client) + newReplicaSet, err := deploymentutil.GetNewReplicaSet(currentDeployment, kcs.ExtensionsV1beta1()) if err != nil || newReplicaSet == nil { return false, err } @@ -91,31 +88,37 @@ func (c *Client) waitForResources(timeout time.Duration, created Result) error { } deployments = append(deployments, newDeployment) case (*extensions.DaemonSet): - list, err := getPods(client, value.Namespace, value.Spec.Selector.MatchLabels) + list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) if err != nil { return false, err } pods = append(pods, list...) - case (*apps.StatefulSet): - list, err := getPods(client, value.Namespace, value.Spec.Selector.MatchLabels) + case (*appsv1beta1.StatefulSet): + list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) + if err != nil { + return false, err + } + pods = append(pods, list...) + case (*appsv1beta2.StatefulSet): + list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) if err != nil { return false, err } pods = append(pods, list...) case (*extensions.ReplicaSet): - list, err := getPods(client, value.Namespace, value.Spec.Selector.MatchLabels) + list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) if err != nil { return false, err } pods = append(pods, list...) case (*v1.PersistentVolumeClaim): - claim, err := client.Core().PersistentVolumeClaims(value.Namespace).Get(value.Name, metav1.GetOptions{}) + claim, err := kcs.Core().PersistentVolumeClaims(value.Namespace).Get(value.Name, metav1.GetOptions{}) if err != nil { return false, err } pvc = append(pvc, *claim) case (*v1.Service): - svc, err := client.Core().Services(value.Namespace).Get(value.Name, metav1.GetOptions{}) + svc, err := kcs.Core().Services(value.Namespace).Get(value.Name, metav1.GetOptions{}) if err != nil { return false, err } @@ -178,20 +181,10 @@ func (c *Client) deploymentsReady(deployments []deployment) bool { return true } -func getPods(client clientset.Interface, namespace string, selector map[string]string) ([]v1.Pod, error) { +func getPods(client kubernetes.Interface, namespace string, selector map[string]string) ([]v1.Pod, error) { list, err := client.Core().Pods(namespace).List(metav1.ListOptions{ FieldSelector: fields.Everything().String(), LabelSelector: labels.Set(selector).AsSelector().String(), }) return list.Items, err } - -func versionedClientsetForDeployment(internalClient internalclientset.Interface) clientset.Interface { - if internalClient == nil { - return &clientset.Clientset{} - } - return &clientset.Clientset{ - CoreV1Client: core.New(internalClient.Core().RESTClient()), - ExtensionsV1beta1Client: extensionsclient.New(internalClient.Extensions().RESTClient()), - } -} From e974ab31d8aa70ab68c1571abb8e5bbf06d7b270 Mon Sep 17 00:00:00 2001 From: Brad Bowman Date: Wed, 11 Oct 2017 17:23:31 -0600 Subject: [PATCH 018/107] [fakeclient-releasestatus] Move ReleaseMock and associates into helm package and update tests to use them --- pkg/helm/fake.go | 122 +++++++++++++++++++++++++++++++++--------- pkg/helm/fake_test.go | 61 +++++++-------------- 2 files changed, 114 insertions(+), 69 deletions(-) diff --git a/pkg/helm/fake.go b/pkg/helm/fake.go index 2a9c3cee3..8d809f658 100644 --- a/pkg/helm/fake.go +++ b/pkg/helm/fake.go @@ -19,10 +19,10 @@ package helm // import "k8s.io/helm/pkg/helm" import ( "errors" "fmt" - "strings" + "math/rand" "sync" - "github.com/technosophos/moniker" + "github.com/golang/protobuf/ptypes/timestamp" "k8s.io/helm/pkg/proto/hapi/chart" "k8s.io/helm/pkg/proto/hapi/release" rls "k8s.io/helm/pkg/proto/hapi/services" @@ -56,32 +56,19 @@ func (c *FakeClient) ListReleases(opts ...ReleaseListOption) (*rls.ListReleasesR return resp, nil } -// InstallRelease returns a response with the first Release on the fake release client +// InstallRelease creates a new release and returns a InstallReleaseResponse containing that release func (c *FakeClient) InstallRelease(chStr, ns string, opts ...InstallOption) (*rls.InstallReleaseResponse, error) { chart := &chart.Chart{} return c.InstallReleaseFromChart(chart, ns, opts...) } -// InstallReleaseFromChart returns a response with the first Release on the fake release client +// InstallReleaseFromChart adds a new MockRelease to the fake client and returns a InstallReleaseResponse containing that release func (c *FakeClient) InstallReleaseFromChart(chart *chart.Chart, ns string, opts ...InstallOption) (*rls.InstallReleaseResponse, error) { for _, opt := range opts { opt(&c.Opts) } releaseName := c.Opts.instReq.Name - if releaseName == "" { - for i := 0; i < 5; i++ { - namer := moniker.New() - name := namer.NameSep("-") - if len(name) > 53 { - name = name[:53] - } - if _, err := c.ReleaseStatus(name, nil); strings.Contains(err.Error(), "No such release") { - releaseName = name - break - } - } - } // Check to see if the release already exists. rel, err := c.ReleaseStatus(releaseName, nil) @@ -89,11 +76,7 @@ func (c *FakeClient) InstallReleaseFromChart(chart *chart.Chart, ns string, opts return nil, errors.New("cannot re-use a name that is still in use") } - release := &release.Release{ - Name: releaseName, - Namespace: ns, - } - + release := ReleaseMock(&MockReleaseOptions{Name: releaseName, Namespace: ns}) c.Rels = append(c.Rels, release) return &rls.InstallReleaseResponse{ @@ -101,7 +84,7 @@ func (c *FakeClient) InstallReleaseFromChart(chart *chart.Chart, ns string, opts }, nil } -// DeleteRelease returns nil, nil +// DeleteRelease deletes a release from the FakeClient func (c *FakeClient) DeleteRelease(rlsName string, opts ...DeleteOption) (*rls.UninstallReleaseResponse, error) { for i, rel := range c.Rels { if rel.Name == rlsName { @@ -124,12 +107,12 @@ func (c *FakeClient) GetVersion(opts ...VersionOption) (*rls.GetVersionResponse, }, nil } -// UpdateRelease returns nil, nil +// UpdateRelease returns an UpdateReleaseResponse containing the updated release, if it exists func (c *FakeClient) UpdateRelease(rlsName string, chStr string, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error) { return c.UpdateReleaseFromChart(rlsName, &chart.Chart{}, opts...) } -// UpdateReleaseFromChart returns nil, nil +// UpdateReleaseFromChart returns an UpdateReleaseResponse containing the updated release, if it exists func (c *FakeClient) UpdateReleaseFromChart(rlsName string, chart *chart.Chart, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error) { // Check to see if the release already exists. rel, err := c.ReleaseContent(rlsName, nil) @@ -145,7 +128,7 @@ func (c *FakeClient) RollbackRelease(rlsName string, opts ...RollbackOption) (*r return nil, nil } -// ReleaseStatus returns a release status response with info from the matching release name in the fake release client. +// ReleaseStatus returns a release status response with info from the matching release name. func (c *FakeClient) ReleaseStatus(rlsName string, opts ...StatusOption) (*rls.GetReleaseStatusResponse, error) { for _, rel := range c.Rels { if rel.Name == rlsName { @@ -200,3 +183,90 @@ func (c *FakeClient) RunReleaseTest(rlsName string, opts ...ReleaseTestOption) ( return results, errc } + +// MockHookTemplate is the hook template used for all mock release objects. +var MockHookTemplate = `apiVersion: v1 +kind: Job +metadata: + annotations: + "helm.sh/hooks": pre-install +` + +// MockManifest is the manifest used for all mock release objects. +var MockManifest = `apiVersion: v1 +kind: Secret +metadata: + name: fixture +` + +// MockReleaseOptions allows for user-configurable options on mock release objects. +type MockReleaseOptions struct { + Name string + Version int32 + Chart *chart.Chart + StatusCode release.Status_Code + Namespace string +} + +// ReleaseMock creates a mock release object based on options set by MockReleaseOptions. This function should typically not be used outside of testing. +func ReleaseMock(opts *MockReleaseOptions) *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, + } +} diff --git a/pkg/helm/fake_test.go b/pkg/helm/fake_test.go index ee60648c0..9c0a53759 100644 --- a/pkg/helm/fake_test.go +++ b/pkg/helm/fake_test.go @@ -26,8 +26,8 @@ import ( ) func TestFakeClient_ReleaseStatus(t *testing.T) { - releasePresent := &release.Release{Name: "release-present", Namespace: "default"} - releaseNotPresent := &release.Release{Name: "release-not-present", Namespace: "default"} + releasePresent := ReleaseMock(&MockReleaseOptions{Name: "release-present"}) + releaseNotPresent := ReleaseMock(&MockReleaseOptions{Name: "release-not-present"}) type fields struct { Rels []*release.Release @@ -80,8 +80,8 @@ func TestFakeClient_ReleaseStatus(t *testing.T) { name: "Get a single release that exists from list", fields: fields{ Rels: []*release.Release{ - {Name: "angry-dolphin", Namespace: "default"}, - {Name: "trepid-tapir", Namespace: "default"}, + ReleaseMock(&MockReleaseOptions{Name: "angry-dolphin", Namespace: "default"}), + ReleaseMock(&MockReleaseOptions{Name: "trepid-tapir", Namespace: "default"}), releasePresent, }, }, @@ -143,13 +143,10 @@ func TestFakeClient_InstallReleaseFromChart(t *testing.T) { opts: []InstallOption{ReleaseName("new-release")}, }, want: &rls.InstallReleaseResponse{ - Release: &release.Release{ - Name: "new-release", - Namespace: "default", - }, + Release: ReleaseMock(&MockReleaseOptions{Name: "new-release"}), }, relsAfter: []*release.Release{ - {Name: "new-release", Namespace: "default"}, + ReleaseMock(&MockReleaseOptions{Name: "new-release"}), }, wantErr: false, }, @@ -157,10 +154,7 @@ func TestFakeClient_InstallReleaseFromChart(t *testing.T) { name: "Try to add a release where the name already exists.", fields: fields{ Rels: []*release.Release{ - &release.Release{ - Name: "new-release", - Namespace: "default", - }, + ReleaseMock(&MockReleaseOptions{Name: "new-release"}), }, }, args: args{ @@ -168,10 +162,7 @@ func TestFakeClient_InstallReleaseFromChart(t *testing.T) { opts: []InstallOption{ReleaseName("new-release")}, }, relsAfter: []*release.Release{ - { - Name: "new-release", - Namespace: "default", - }, + ReleaseMock(&MockReleaseOptions{Name: "new-release"}), }, want: nil, wantErr: true, @@ -217,12 +208,8 @@ func TestFakeClient_DeleteRelease(t *testing.T) { name: "Delete a release that exists.", fields: fields{ Rels: []*release.Release{ - { - Name: "angry-dolphin", - }, - { - Name: "trepid-tapir", - }, + ReleaseMock(&MockReleaseOptions{Name: "angry-dolphin"}), + ReleaseMock(&MockReleaseOptions{Name: "trepid-tapir"}), }, }, args: args{ @@ -230,12 +217,10 @@ func TestFakeClient_DeleteRelease(t *testing.T) { opts: []DeleteOption{}, }, relsAfter: []*release.Release{ - { - Name: "angry-dolphin", - }, + ReleaseMock(&MockReleaseOptions{Name: "angry-dolphin"}), }, want: &rls.UninstallReleaseResponse{ - Release: &release.Release{Name: "trepid-tapir"}, + Release: ReleaseMock(&MockReleaseOptions{Name: "trepid-tapir"}), }, wantErr: false, }, @@ -243,12 +228,8 @@ func TestFakeClient_DeleteRelease(t *testing.T) { name: "Delete a release that does not exist.", fields: fields{ Rels: []*release.Release{ - { - Name: "angry-dolphin", - }, - { - Name: "trepid-tapir", - }, + ReleaseMock(&MockReleaseOptions{Name: "angry-dolphin"}), + ReleaseMock(&MockReleaseOptions{Name: "trepid-tapir"}), }, }, args: args{ @@ -256,12 +237,8 @@ func TestFakeClient_DeleteRelease(t *testing.T) { opts: []DeleteOption{}, }, relsAfter: []*release.Release{ - { - Name: "angry-dolphin", - }, - { - Name: "trepid-tapir", - }, + ReleaseMock(&MockReleaseOptions{Name: "angry-dolphin"}), + ReleaseMock(&MockReleaseOptions{Name: "trepid-tapir"}), }, want: nil, wantErr: true, @@ -270,9 +247,7 @@ func TestFakeClient_DeleteRelease(t *testing.T) { name: "Delete when only 1 item exists.", fields: fields{ Rels: []*release.Release{ - { - Name: "trepid-tapir", - }, + ReleaseMock(&MockReleaseOptions{Name: "trepid-tapir"}), }, }, args: args{ @@ -281,7 +256,7 @@ func TestFakeClient_DeleteRelease(t *testing.T) { }, relsAfter: []*release.Release{}, want: &rls.UninstallReleaseResponse{ - Release: &release.Release{Name: "trepid-tapir"}, + Release: ReleaseMock(&MockReleaseOptions{Name: "trepid-tapir"}), }, wantErr: false, }, From 14510866d55a519fedb19240f76f97600361b13d Mon Sep 17 00:00:00 2001 From: Brad Bowman Date: Wed, 11 Oct 2017 17:24:46 -0600 Subject: [PATCH 019/107] Update cmd tests to use ReleaseMock and assocaites from the helm package --- cmd/helm/delete_test.go | 13 +++-- cmd/helm/get_hooks_test.go | 6 ++- cmd/helm/get_manifest_test.go | 6 ++- cmd/helm/get_test.go | 6 ++- cmd/helm/get_values_test.go | 4 +- cmd/helm/helm_test.go | 92 ++--------------------------------- cmd/helm/history_test.go | 8 +-- cmd/helm/list_test.go | 36 +++++++------- cmd/helm/reset_test.go | 4 +- cmd/helm/status_test.go | 10 ++-- cmd/helm/upgrade_test.go | 32 +++++++----- 11 files changed, 78 insertions(+), 139 deletions(-) diff --git a/cmd/helm/delete_test.go b/cmd/helm/delete_test.go index 4f1bd29a6..829d17906 100644 --- a/cmd/helm/delete_test.go +++ b/cmd/helm/delete_test.go @@ -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", diff --git a/cmd/helm/get_hooks_test.go b/cmd/helm/get_hooks_test.go index 3e6132fbf..e578c2533 100644 --- a/cmd/helm/get_hooks_test.go +++ b/cmd/helm/get_hooks_test.go @@ -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", diff --git a/cmd/helm/get_manifest_test.go b/cmd/helm/get_manifest_test.go index 4ba80e2ad..286b5628a 100644 --- a/cmd/helm/get_manifest_test.go +++ b/cmd/helm/get_manifest_test.go @@ -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", diff --git a/cmd/helm/get_test.go b/cmd/helm/get_test.go index 23b82c04d..a6e72987a 100644 --- a/cmd/helm/get_test.go +++ b/cmd/helm/get_test.go @@ -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", diff --git a/cmd/helm/get_values_test.go b/cmd/helm/get_values_test.go index 4032253fe..30b2ba4b8 100644 --- a/cmd/helm/get_values_test.go +++ b/cmd/helm/get_values_test.go @@ -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", diff --git a/cmd/helm/helm_test.go b/cmd/helm/helm_test.go index 2a2af1359..7d74d66b7 100644 --- a/cmd/helm/helm_test.go +++ b/cmd/helm/helm_test.go @@ -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) { diff --git a/cmd/helm/history_test.go b/cmd/helm/history_test.go index 3ff4b4a89..f193f6314 100644 --- a/cmd/helm/history_test.go +++ b/cmd/helm/history_test.go @@ -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, }) } diff --git a/cmd/helm/list_test.go b/cmd/helm/list_test.go index 5660eb26a..587a7c39c 100644 --- a/cmd/helm/list_test.go +++ b/cmd/helm/list_test.go @@ -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", }, diff --git a/cmd/helm/reset_test.go b/cmd/helm/reset_test.go index d6febd132..b036e25c9 100644 --- a/cmd/helm/reset_test.go +++ b/cmd/helm/reset_test.go @@ -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, diff --git a/cmd/helm/status_test.go b/cmd/helm/status_test.go index a1aaea5a3..9bf6d3bc0 100644 --- a/cmd/helm/status_test.go +++ b/cmd/helm/status_test.go @@ -52,7 +52,7 @@ func TestStatusCmd(t *testing.T) { name: "get status of a deployed release", args: []string{"flummoxed-chickadee"}, expected: outputWithStatus("DEPLOYED\n\n"), - rel: releaseMockWithStatus(&release.Status{ + rel: ReleaseMockWithStatus(&release.Status{ Code: release.Status_DEPLOYED, }), }, @@ -60,7 +60,7 @@ func TestStatusCmd(t *testing.T) { name: "get status of a deployed release with notes", args: []string{"flummoxed-chickadee"}, expected: outputWithStatus("DEPLOYED\n\nNOTES:\nrelease notes\n"), - rel: releaseMockWithStatus(&release.Status{ + rel: ReleaseMockWithStatus(&release.Status{ Code: release.Status_DEPLOYED, Notes: "release notes", }), @@ -69,7 +69,7 @@ func TestStatusCmd(t *testing.T) { name: "get status of a deployed release with resources", args: []string{"flummoxed-chickadee"}, expected: outputWithStatus("DEPLOYED\n\nRESOURCES:\nresource A\nresource B\n\n"), - rel: releaseMockWithStatus(&release.Status{ + rel: ReleaseMockWithStatus(&release.Status{ Code: release.Status_DEPLOYED, Resources: "resource A\nresource B\n", }), @@ -82,7 +82,7 @@ func TestStatusCmd(t *testing.T) { "TEST \tSTATUS \tINFO \tSTARTED \tCOMPLETED \n" + fmt.Sprintf("test run 1\tSUCCESS \textra info\t%s\t%s\n", dateString, dateString) + fmt.Sprintf("test run 2\tFAILURE \t \t%s\t%s\n", dateString, dateString)), - rel: releaseMockWithStatus(&release.Status{ + rel: ReleaseMockWithStatus(&release.Status{ Code: release.Status_DEPLOYED, LastTestSuiteRun: &release.TestSuite{ StartedAt: &date, @@ -138,7 +138,7 @@ func outputWithStatus(status string) string { status) } -func releaseMockWithStatus(status *release.Status) *release.Release { +func ReleaseMockWithStatus(status *release.Status) *release.Release { return &release.Release{ Name: "flummoxed-chickadee", Info: &release.Info{ diff --git a/cmd/helm/upgrade_test.go b/cmd/helm/upgrade_test.go index 1c5d1c856..187d3593e 100644 --- a/cmd/helm/upgrade_test.go +++ b/cmd/helm/upgrade_test.go @@ -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, }, } From 2bc97cfc839a542735a798bc7c24f1921387509f Mon Sep 17 00:00:00 2001 From: Brad Bowman Date: Wed, 11 Oct 2017 17:26:16 -0600 Subject: [PATCH 020/107] Update install tests to use ReleaseMock and associates from the helm package. Also fix release names to match expected reponse values --- cmd/helm/install_test.go | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/cmd/helm/install_test.go b/cmd/helm/install_test.go index c68deb482..aa828c6ce 100644 --- a/cmd/helm/install_test.go +++ b/cmd/helm/install_test.go @@ -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. { From ab049ddb7bb7a3b5fd0e8d400d6fadb4f9b0d37a Mon Sep 17 00:00:00 2001 From: Brad Bowman Date: Wed, 11 Oct 2017 17:34:49 -0600 Subject: [PATCH 021/107] move releaseMockWithStatus back to private --- cmd/helm/status_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cmd/helm/status_test.go b/cmd/helm/status_test.go index 9bf6d3bc0..a1aaea5a3 100644 --- a/cmd/helm/status_test.go +++ b/cmd/helm/status_test.go @@ -52,7 +52,7 @@ func TestStatusCmd(t *testing.T) { name: "get status of a deployed release", args: []string{"flummoxed-chickadee"}, expected: outputWithStatus("DEPLOYED\n\n"), - rel: ReleaseMockWithStatus(&release.Status{ + rel: releaseMockWithStatus(&release.Status{ Code: release.Status_DEPLOYED, }), }, @@ -60,7 +60,7 @@ func TestStatusCmd(t *testing.T) { name: "get status of a deployed release with notes", args: []string{"flummoxed-chickadee"}, expected: outputWithStatus("DEPLOYED\n\nNOTES:\nrelease notes\n"), - rel: ReleaseMockWithStatus(&release.Status{ + rel: releaseMockWithStatus(&release.Status{ Code: release.Status_DEPLOYED, Notes: "release notes", }), @@ -69,7 +69,7 @@ func TestStatusCmd(t *testing.T) { name: "get status of a deployed release with resources", args: []string{"flummoxed-chickadee"}, expected: outputWithStatus("DEPLOYED\n\nRESOURCES:\nresource A\nresource B\n\n"), - rel: ReleaseMockWithStatus(&release.Status{ + rel: releaseMockWithStatus(&release.Status{ Code: release.Status_DEPLOYED, Resources: "resource A\nresource B\n", }), @@ -82,7 +82,7 @@ func TestStatusCmd(t *testing.T) { "TEST \tSTATUS \tINFO \tSTARTED \tCOMPLETED \n" + fmt.Sprintf("test run 1\tSUCCESS \textra info\t%s\t%s\n", dateString, dateString) + fmt.Sprintf("test run 2\tFAILURE \t \t%s\t%s\n", dateString, dateString)), - rel: ReleaseMockWithStatus(&release.Status{ + rel: releaseMockWithStatus(&release.Status{ Code: release.Status_DEPLOYED, LastTestSuiteRun: &release.TestSuite{ StartedAt: &date, @@ -138,7 +138,7 @@ func outputWithStatus(status string) string { status) } -func ReleaseMockWithStatus(status *release.Status) *release.Release { +func releaseMockWithStatus(status *release.Status) *release.Release { return &release.Release{ Name: "flummoxed-chickadee", Info: &release.Info{ From 1aeeed0478ce39b9cc7437a1ee8bfdd90b2518a6 Mon Sep 17 00:00:00 2001 From: Matt Butcher Date: Fri, 6 Oct 2017 09:26:26 -0600 Subject: [PATCH 022/107] chore(sprig): bump sprig to 2.14.0 --- glide.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/glide.yaml b/glide.yaml index 5aa459ca5..8db44744f 100644 --- a/glide.yaml +++ b/glide.yaml @@ -14,7 +14,7 @@ import: - package: github.com/imdario/mergo version: 6633656539c1639d9d78127b7d47c622b5d7b6dc - package: github.com/Masterminds/sprig - version: ^2.13 + version: ^2.14 - package: github.com/ghodss/yaml - package: github.com/Masterminds/semver version: ~1.3.1 From e1703923031e29373c65c99ccddf195ea1e7aa96 Mon Sep 17 00:00:00 2001 From: Michael Venezia Date: Thu, 12 Oct 2017 16:09:46 -0400 Subject: [PATCH 023/107] Adding how to add an image pull secret in helm (#3022) Document how to add an image pull secret in Helm Provide an example of how to take an image registry, user name, and password and prepare a Secret that can be used by a pod to pull a protected container image. --- docs/charts_tips_and_tricks.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/docs/charts_tips_and_tricks.md b/docs/charts_tips_and_tricks.md index 0ed1ab83e..885c30085 100644 --- a/docs/charts_tips_and_tricks.md +++ b/docs/charts_tips_and_tricks.md @@ -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 From 4f107cc48affe82e42049323a91a03b84e00a01c Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Thu, 12 Oct 2017 13:27:20 -0700 Subject: [PATCH 024/107] pin golang.org/x/sys to master fixes issues seen in master with `make build-cross` for windows --- glide.lock | 6 +++--- glide.yaml | 8 +++++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/glide.lock b/glide.lock index 06ee4088b..cb17642e4 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: f5e472b397d20aaa131c8eada3966fdbbf65457073bd1ee8fb8b349bf39c522a -updated: 2017-10-09T13:32:53.067503253-07:00 +hash: 650f1d4cd9e9dc5ba76480a5465923ce1bbd11b8fa956b644aaf975e8f7e1f33 +updated: 2017-10-12T13:08:50.435765-07:00 imports: - name: cloud.google.com/go version: 3b1ae45394a234c385be014e9a488f2bb6eef821 @@ -285,7 +285,7 @@ imports: - jws - jwt - name: golang.org/x/sys - version: 8f0908ab3b2457e2e15403d3697c9ef5cb4b57a9 + version: 43eea11bc92608addb41b8a406b0407495c106f6 subpackages: - unix - windows diff --git a/glide.yaml b/glide.yaml index 5aa459ca5..feb03a69a 100644 --- a/glide.yaml +++ b/glide.yaml @@ -28,13 +28,19 @@ import: - package: google.golang.org/grpc version: 1.2.1 - package: k8s.io/kubernetes - version: ~1.8.0 + version: 1.8.0 - package: github.com/gosuri/uitable - package: github.com/asaskevich/govalidator version: ^4.0.0 - package: golang.org/x/crypto subpackages: - openpgp + # pin version of golang.org/x/sys that is compatible with golang.org/x/crypto +- package: golang.org/x/sys + version: 43eea11 + subpackages: + - unix + - windows - package: github.com/gobwas/glob version: ^0.2.1 - package: github.com/evanphx/json-patch From 4b9b780421159bda253f765c838a2af3b10b18b3 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Thu, 12 Oct 2017 15:26:51 -0700 Subject: [PATCH 025/107] add comment on k8s 1.8.1 deps being hosed --- glide.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/glide.yaml b/glide.yaml index feb03a69a..f89e940fe 100644 --- a/glide.yaml +++ b/glide.yaml @@ -27,6 +27,8 @@ import: - ptypes/timestamp - package: google.golang.org/grpc version: 1.2.1 + # 1.8.1 libs are hosed and need some manual intervention, so pinning to 1.8.0 for now + # so others aren't getting errors when running `glide up` - package: k8s.io/kubernetes version: 1.8.0 - package: github.com/gosuri/uitable From 5e10814eb6c5cf05dcb9d8e0b8fe9c9fa6ffa2f0 Mon Sep 17 00:00:00 2001 From: Taylor Thomas Date: Thu, 12 Oct 2017 18:45:37 -0700 Subject: [PATCH 026/107] docs(tiller): Adds documentation for secret backend Adds documentation for running `tiller` with the new secrets backend added in #2721 --- docs/install.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/install.md b/docs/install.md index 618b5332c..ea51afd89 100755 --- a/docs/install.md +++ b/docs/install.md @@ -317,6 +317,23 @@ in JSON format. ... ``` +### Storage backends +By default, `tiller` stores release information in `ConfigMaps` in the namespace +where it is running. As of Helm 2.7.0, there is now a beta storage backend that +uses `Secrets` for storing release information. This was added for additional +security in protecting charts in conjunction with the release of `Secret` +encryption in Kubernetes. + +To enable the secrets backend, you'll need to init Tiller with the following +options: + +```shell +helm init --override 'spec.template.spec.containers[0].command'='{/tiller,--storage=secret}' +``` + +Currently, if you want to switch from the default backend to the secrets +backend, you'll have to do the migration for this on your own. When this backend +graduates from beta, there will be a more official path of migration ## Conclusion From bbad3c574eb03b8430df8f41921624d0cbc3dcc0 Mon Sep 17 00:00:00 2001 From: Edward Medvedev Date: Sun, 15 Oct 2017 20:29:13 +0200 Subject: [PATCH 027/107] Fix a small typo in `yaml_techniques.md` Fix a typo: `coffess`. --- docs/chart_template_guide/yaml_techniques.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/chart_template_guide/yaml_techniques.md b/docs/chart_template_guide/yaml_techniques.md index ccada54c0..44c41f903 100644 --- a/docs/chart_template_guide/yaml_techniques.md +++ b/docs/chart_template_guide/yaml_techniques.md @@ -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 From 67ed2cfc1ec4bca37214534166111df77b9d9e0c Mon Sep 17 00:00:00 2001 From: John Iacona Date: Wed, 18 Oct 2017 16:06:14 +0100 Subject: [PATCH 028/107] Update using_helm.md Add explanation of persistence behavior of `--set` --- docs/using_helm.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/using_helm.md b/docs/using_helm.md index 77e4cffc2..6bf3b2bcc 100755 --- a/docs/using_helm.md +++ b/docs/using_helm.md @@ -230,6 +230,10 @@ There are two ways to pass configuration data during install: - `--set`: Specify overrides on the command line. If both are used, `--set` values are merged into `--values` with higher precedence. +Overrides specified with `--set` are persisted in a configmap. Values that have been +`--set` can be viewed for a given release with `helm get values `. +Values that have been `--set` can be cleared by running `helm upgrade` with `--reset-values` +specified. #### The Format and Limitations of `--set` From f98b0fcdebd79300e6e87a4db4c609dfbdd390f2 Mon Sep 17 00:00:00 2001 From: Drew Hunt Date: Wed, 18 Oct 2017 12:33:19 -0700 Subject: [PATCH 029/107] Working on Fedora release 25 - kubeadm v1.7.0 - kubelet v1.8.1 Tested: - Installing/deleting Chart - Chart upgrade and Chart rollback --- docs/kubernetes_distros.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/kubernetes_distros.md b/docs/kubernetes_distros.md index bea1e8075..7b5382893 100644 --- a/docs/kubernetes_distros.md +++ b/docs/kubernetes_distros.md @@ -27,7 +27,7 @@ Kubernetes bootstrapped with `kubeadm` is known to work on the following Linux distributions: - Ubuntu 16.04 -- CAN SOMEONE CONFIRM ON FEDORA? +- Fedora release 25 Some versions of Helm (v2.0.0-beta2) require you to `export KUBECONFIG=/etc/kubernetes/admin.conf` or create a `~/.kube/config`. From 79d51c5cfe64109a2d25d07af669c431c1300097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Bra=C5=84ski?= Date: Thu, 19 Oct 2017 08:14:28 +0200 Subject: [PATCH 030/107] Update README.md There should be a colon because it precedes an explanation or an enumeration, or list. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 66cb8579a..8faf4f24b 100644 --- a/README.md +++ b/README.md @@ -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 From d43d5ab4529a80cb8944762ab8dd15d111af6df6 Mon Sep 17 00:00:00 2001 From: Johan Lyheden Date: Thu, 19 Oct 2017 09:38:11 +0200 Subject: [PATCH 031/107] Add plugin installer from http archive --- pkg/plugin/installer/http_installer.go | 203 ++++++++++++++++++++ pkg/plugin/installer/http_installer_test.go | 103 ++++++++++ pkg/plugin/installer/installer.go | 15 ++ 3 files changed, 321 insertions(+) create mode 100644 pkg/plugin/installer/http_installer.go create mode 100644 pkg/plugin/installer/http_installer_test.go diff --git a/pkg/plugin/installer/http_installer.go b/pkg/plugin/installer/http_installer.go new file mode 100644 index 000000000..cbe877777 --- /dev/null +++ b/pkg/plugin/installer/http_installer.go @@ -0,0 +1,203 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package installer // import "k8s.io/helm/pkg/plugin/installer" + +import ( + "k8s.io/helm/pkg/helm/helmpath" + "path/filepath" + "k8s.io/helm/pkg/getter" + "k8s.io/helm/pkg/helm/environment" + "k8s.io/helm/pkg/plugin/cache" + "compress/gzip" + "archive/tar" + "io" + "os" + "fmt" + "strings" + "bytes" + "regexp" +) + +type HttpInstaller struct { + CacheDir string + PluginName string + base + extractor Extractor + getter getter.Getter +} + +type TarGzExtractor struct {} + +type Extractor interface { + Extract(buffer *bytes.Buffer, targetDir string) error +} + +var Extractors = map[string]Extractor { + ".tar.gz": &TarGzExtractor{}, + ".tgz": &TarGzExtractor{}, +} + +// NewExtractor creates a new extractor matching the source file name +func NewExtractor(source string) (Extractor, error) { + for suffix, extractor := range Extractors { + if strings.HasSuffix(source, suffix) { + return extractor, nil + } + } + return nil, fmt.Errorf("no extractor implemented yet for %s", source) +} + +// NewHttpInstaller creates a new HttpInstaller. +func NewHttpInstaller(source string, home helmpath.Home) (*HttpInstaller, error) { + + key, err := cache.Key(source) + if err != nil { + return nil, err + } + + extractor, err := NewExtractor(source) + if err != nil { + return nil, err + } + + getConstructor, err := getter.ByScheme("http", environment.EnvSettings{}) + if err != nil { + return nil, err + } + + get, err := getConstructor.New(source,"", "", "") + if err != nil { + return nil, err + } + + i := &HttpInstaller{ + CacheDir: home.Path("cache", "plugins", key), + PluginName: stripPluginName(filepath.Base(source)), + base: newBase(source, home), + extractor: extractor, + getter: get, + } + return i, nil +} + +// helper that relies on some sort of convention for plugin name (plugin-name-) +func stripPluginName(name string) string { + var strippedName string + for suffix := range Extractors { + if strings.HasSuffix(name, suffix) { + strippedName = strings.TrimSuffix(name, suffix) + break + } + } + re := regexp.MustCompile(`(.*)-[0-9]+\..*`) + return re.ReplaceAllString(strippedName, `$1`) +} + +// Install() downloads and extracts the tarball into the cache directory and creates a symlink to the plugin directory in $HELM_HOME. +// +// Implements Installer. +func (i *HttpInstaller) Install() error { + + pluginData, err := i.getter.Get(i.Source) + if err != nil { + return err + } + + err = i.extractor.Extract(pluginData, i.CacheDir) + if err != nil { + return err + } + + if !isPlugin(i.CacheDir) { + return ErrMissingMetadata + } + + src, err := filepath.Abs(i.CacheDir) + if err != nil { + return err + } + + return i.link(src) +} + +// Update updates a local repository +// Not implemented for now since tarball most likely will be packaged by version +func (i *HttpInstaller) Update() error { + return fmt.Errorf("method Update() not implemented for HttpInstaller") +} + +// Override link because we want to use HttpInstaller.Path() not base.Path() +func (i *HttpInstaller) link(from string) error { + debug("symlinking %s to %s", from, i.Path()) + return os.Symlink(from, i.Path()) +} + +// Override Path() because we want to join on the plugin name not the file name +func (i HttpInstaller) Path() string { + if i.base.Source == "" { + return "" + } + return filepath.Join(i.base.HelmHome.Plugins(), i.PluginName) +} + +// Extracts tar.gz archive +// +// Implements Extractor. +func (g *TarGzExtractor) Extract(buffer *bytes.Buffer, targetDir string) error { + uncompressedStream, err := gzip.NewReader(buffer) + if err != nil { + return err + } + + tarReader := tar.NewReader(uncompressedStream) + + os.MkdirAll(targetDir, 0755) + + for true { + header, err := tarReader.Next() + + if err == io.EOF { + break + } + + if err != nil { + return err + } + + path := filepath.Join(targetDir, header.Name) + + switch header.Typeflag { + case tar.TypeDir: + if err := os.Mkdir(path, 0755); err != nil { + return err + } + case tar.TypeReg: + outFile, err := os.Create(path) + if err != nil { + return err + } + defer outFile.Close() + if _, err := io.Copy(outFile, tarReader); err != nil { + return err + } + default: + return fmt.Errorf("unknown type: %s in %s", header.Typeflag, header.Name) + } + } + + return nil + +} \ No newline at end of file diff --git a/pkg/plugin/installer/http_installer_test.go b/pkg/plugin/installer/http_installer_test.go new file mode 100644 index 000000000..730c33af5 --- /dev/null +++ b/pkg/plugin/installer/http_installer_test.go @@ -0,0 +1,103 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package installer // import "k8s.io/helm/pkg/plugin/installer" + +import ( + "testing" + "io/ioutil" + "os" + "k8s.io/helm/pkg/helm/helmpath" + "bytes" + "encoding/base64" +) + +var _ Installer = new(HttpInstaller) + +// Fake http client +type TestHttpGetter struct { + MockResponse *bytes.Buffer +} + +func (t *TestHttpGetter) Get(href string) (*bytes.Buffer, error) { return t.MockResponse, nil } + +// Fake plugin tarball data +var fakePluginB64 = "H4sIAKRj51kAA+3UX0vCUBgGcC9jn+Iwuk3Peza3GeyiUlJQkcogCOzgli7dJm4TvYk+a5+k479UqquUCJ/fLs549sLO2TnvWnJa9aXnjwujYdYLovxMhsPcfnHOLdNkOXthM/IVQQYjg2yyLLJ4kXGhLp5j0z3P41tZksqxmspL3B/O+j/XtZu1y8rdYzkOZRCxduKPk53ny6Wwz/GfIIf1As8lxzGJSmoHNLJZphKHG4YpTCE0wVk3DULfpSJ3DMMqkj3P5JfMYLdX1Vr9Ie/5E5cstcdC8K04iGLX5HaJuKpWL17F0TCIBi5pf/0pjtLhun5j3f9v6r7wfnI/H0eNp9d1/5P6Gez0vzo7wsoxfrAZbTny/o9k6J8z/VkO/LPlWdC1iVpbEEcq5nmeJ13LEtmbV0k2r2PrOs9PuuNglC5rL1Y5S/syXRQmutaNw1BGnnp8Wq3UG51WvX1da3bKtZtCN/R09DwAAAAAAAAAAAAAAAAAAADAb30AoMczDwAoAAA=" + +func TestStripName(t *testing.T) { + if stripPluginName("fake-plugin-0.0.1.tar.gz") != "fake-plugin" { + t.Errorf("name does not match expected value") + } + if stripPluginName("fake-plugin-0.0.1.tgz") != "fake-plugin" { + t.Errorf("name does not match expected value") + } + if stripPluginName("fake-plugin.tgz") != "fake-plugin" { + t.Errorf("name does not match expected value") + } + if stripPluginName("fake-plugin.tar.gz") != "fake-plugin" { + t.Errorf("name does not match expected value") + } +} + +func TestHttpInstaller(t *testing.T) { + source := "https://repo.localdomain/plugins/fake-plugin-0.0.1.tar.gz" + hh, err := ioutil.TempDir("", "helm-home-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(hh) + + home := helmpath.Home(hh) + if err := os.MkdirAll(home.Plugins(), 0755); err != nil { + t.Fatalf("Could not create %s: %s", home.Plugins(), err) + } + + i, err := NewForSource(source, "0.0.1", home) + if err != nil { + t.Errorf("unexpected error: %s", err) + } + + // ensure a HttpInstaller was returned + httpInstaller, ok := i.(*HttpInstaller) + if !ok { + t.Error("expected a HttpInstaller") + } + + // inject fake http client responding with minimal plugin tarball + mockTgz, err := base64.StdEncoding.DecodeString(fakePluginB64) + if err != nil { + t.Fatalf("Could not decode fake tgz plugin: %s", err) + } + + httpInstaller.getter = &TestHttpGetter{ + MockResponse: bytes.NewBuffer(mockTgz), + } + + // install the plugin + if err := Install(i); err != nil { + t.Error(err) + } + if i.Path() != home.Path("plugins", "fake-plugin") { + t.Errorf("expected path '$HELM_HOME/plugins/fake-plugin', got %q", i.Path()) + } + + // Install again to test plugin exists error + if err := Install(i); err == nil { + t.Error("expected error for plugin exists, got none") + } else if err.Error() != "plugin already exists" { + t.Errorf("expected error for plugin exists, got (%v)", err) + } + +} \ No newline at end of file diff --git a/pkg/plugin/installer/installer.go b/pkg/plugin/installer/installer.go index 6ecec980a..b82e2f8b2 100644 --- a/pkg/plugin/installer/installer.go +++ b/pkg/plugin/installer/installer.go @@ -23,6 +23,7 @@ import ( "path/filepath" "k8s.io/helm/pkg/helm/helmpath" + "strings" ) // ErrMissingMetadata indicates that plugin.yaml is missing. @@ -68,6 +69,8 @@ func NewForSource(source, version string, home helmpath.Home) (Installer, error) // Check if source is a local directory if isLocalReference(source) { return NewLocalInstaller(source, home) + } else if isRemoteHttpArchive(source) { + return NewHttpInstaller(source, home) } return NewVCSInstaller(source, version, home) } @@ -87,6 +90,18 @@ func isLocalReference(source string) bool { return err == nil } +// isRemoteHttpArchive checks if the source is a http/https url and is an archive +func isRemoteHttpArchive(source string) bool { + if strings.HasPrefix(source, "http://") || strings.HasPrefix(source, "https://") { + for suffix, _ := range Extractors { + if strings.HasSuffix(source, suffix) { + return true + } + } + } + return false +} + // isPlugin checks if the directory contains a plugin.yaml file. func isPlugin(dirname string) bool { _, err := os.Stat(filepath.Join(dirname, "plugin.yaml")) From f1a08adb4132b474115044a4de8784b8f6403a7f Mon Sep 17 00:00:00 2001 From: Johan Lyheden Date: Thu, 19 Oct 2017 13:35:18 +0200 Subject: [PATCH 032/107] Update to comply with linter rules and gofmt --- pkg/plugin/installer/http_installer.go | 292 ++++++++++---------- pkg/plugin/installer/http_installer_test.go | 144 +++++----- pkg/plugin/installer/installer.go | 10 +- 3 files changed, 225 insertions(+), 221 deletions(-) diff --git a/pkg/plugin/installer/http_installer.go b/pkg/plugin/installer/http_installer.go index cbe877777..203f038f2 100644 --- a/pkg/plugin/installer/http_installer.go +++ b/pkg/plugin/installer/http_installer.go @@ -16,188 +16,192 @@ limitations under the License. package installer // import "k8s.io/helm/pkg/plugin/installer" import ( - "k8s.io/helm/pkg/helm/helmpath" - "path/filepath" - "k8s.io/helm/pkg/getter" - "k8s.io/helm/pkg/helm/environment" - "k8s.io/helm/pkg/plugin/cache" - "compress/gzip" - "archive/tar" - "io" - "os" - "fmt" - "strings" - "bytes" - "regexp" + "archive/tar" + "bytes" + "compress/gzip" + "fmt" + "io" + "k8s.io/helm/pkg/getter" + "k8s.io/helm/pkg/helm/environment" + "k8s.io/helm/pkg/helm/helmpath" + "k8s.io/helm/pkg/plugin/cache" + "os" + "path/filepath" + "regexp" + "strings" ) -type HttpInstaller struct { - CacheDir string - PluginName string - base - extractor Extractor - getter getter.Getter +// HTTPInstaller installs plugins from an archive served by a web server. +type HTTPInstaller struct { + CacheDir string + PluginName string + base + extractor Extractor + getter getter.Getter } -type TarGzExtractor struct {} +// TarGzExtractor extracts gzip compressed tar archives +type TarGzExtractor struct{} +// Extractor provides an interface for extracting archives type Extractor interface { - Extract(buffer *bytes.Buffer, targetDir string) error + Extract(buffer *bytes.Buffer, targetDir string) error } -var Extractors = map[string]Extractor { - ".tar.gz": &TarGzExtractor{}, - ".tgz": &TarGzExtractor{}, +// Extractors contains a map of suffixes and matching implementations of extractor to return +var Extractors = map[string]Extractor{ + ".tar.gz": &TarGzExtractor{}, + ".tgz": &TarGzExtractor{}, } // NewExtractor creates a new extractor matching the source file name func NewExtractor(source string) (Extractor, error) { - for suffix, extractor := range Extractors { - if strings.HasSuffix(source, suffix) { - return extractor, nil - } - } - return nil, fmt.Errorf("no extractor implemented yet for %s", source) + for suffix, extractor := range Extractors { + if strings.HasSuffix(source, suffix) { + return extractor, nil + } + } + return nil, fmt.Errorf("no extractor implemented yet for %s", source) } -// NewHttpInstaller creates a new HttpInstaller. -func NewHttpInstaller(source string, home helmpath.Home) (*HttpInstaller, error) { - - key, err := cache.Key(source) - if err != nil { - return nil, err - } - - extractor, err := NewExtractor(source) - if err != nil { - return nil, err - } - - getConstructor, err := getter.ByScheme("http", environment.EnvSettings{}) - if err != nil { - return nil, err - } - - get, err := getConstructor.New(source,"", "", "") - if err != nil { - return nil, err - } - - i := &HttpInstaller{ - CacheDir: home.Path("cache", "plugins", key), - PluginName: stripPluginName(filepath.Base(source)), - base: newBase(source, home), - extractor: extractor, - getter: get, - } - return i, nil +// NewHTTPInstaller creates a new HttpInstaller. +func NewHTTPInstaller(source string, home helmpath.Home) (*HTTPInstaller, error) { + + key, err := cache.Key(source) + if err != nil { + return nil, err + } + + extractor, err := NewExtractor(source) + if err != nil { + return nil, err + } + + getConstructor, err := getter.ByScheme("http", environment.EnvSettings{}) + if err != nil { + return nil, err + } + + get, err := getConstructor.New(source, "", "", "") + if err != nil { + return nil, err + } + + i := &HTTPInstaller{ + CacheDir: home.Path("cache", "plugins", key), + PluginName: stripPluginName(filepath.Base(source)), + base: newBase(source, home), + extractor: extractor, + getter: get, + } + return i, nil } // helper that relies on some sort of convention for plugin name (plugin-name-) func stripPluginName(name string) string { - var strippedName string - for suffix := range Extractors { - if strings.HasSuffix(name, suffix) { - strippedName = strings.TrimSuffix(name, suffix) - break - } - } - re := regexp.MustCompile(`(.*)-[0-9]+\..*`) - return re.ReplaceAllString(strippedName, `$1`) + var strippedName string + for suffix := range Extractors { + if strings.HasSuffix(name, suffix) { + strippedName = strings.TrimSuffix(name, suffix) + break + } + } + re := regexp.MustCompile(`(.*)-[0-9]+\..*`) + return re.ReplaceAllString(strippedName, `$1`) } -// Install() downloads and extracts the tarball into the cache directory and creates a symlink to the plugin directory in $HELM_HOME. +// Install downloads and extracts the tarball into the cache directory and creates a symlink to the plugin directory in $HELM_HOME. // // Implements Installer. -func (i *HttpInstaller) Install() error { +func (i *HTTPInstaller) Install() error { - pluginData, err := i.getter.Get(i.Source) - if err != nil { - return err - } + pluginData, err := i.getter.Get(i.Source) + if err != nil { + return err + } - err = i.extractor.Extract(pluginData, i.CacheDir) - if err != nil { - return err - } + err = i.extractor.Extract(pluginData, i.CacheDir) + if err != nil { + return err + } - if !isPlugin(i.CacheDir) { - return ErrMissingMetadata - } + if !isPlugin(i.CacheDir) { + return ErrMissingMetadata + } - src, err := filepath.Abs(i.CacheDir) - if err != nil { - return err - } + src, err := filepath.Abs(i.CacheDir) + if err != nil { + return err + } - return i.link(src) + return i.link(src) } // Update updates a local repository // Not implemented for now since tarball most likely will be packaged by version -func (i *HttpInstaller) Update() error { - return fmt.Errorf("method Update() not implemented for HttpInstaller") +func (i *HTTPInstaller) Update() error { + return fmt.Errorf("method Update() not implemented for HttpInstaller") } // Override link because we want to use HttpInstaller.Path() not base.Path() -func (i *HttpInstaller) link(from string) error { - debug("symlinking %s to %s", from, i.Path()) - return os.Symlink(from, i.Path()) +func (i *HTTPInstaller) link(from string) error { + debug("symlinking %s to %s", from, i.Path()) + return os.Symlink(from, i.Path()) } -// Override Path() because we want to join on the plugin name not the file name -func (i HttpInstaller) Path() string { - if i.base.Source == "" { - return "" - } - return filepath.Join(i.base.HelmHome.Plugins(), i.PluginName) +// Path is overridden because we want to join on the plugin name not the file name +func (i HTTPInstaller) Path() string { + if i.base.Source == "" { + return "" + } + return filepath.Join(i.base.HelmHome.Plugins(), i.PluginName) } -// Extracts tar.gz archive +// Extract extracts compressed archives // // Implements Extractor. func (g *TarGzExtractor) Extract(buffer *bytes.Buffer, targetDir string) error { - uncompressedStream, err := gzip.NewReader(buffer) - if err != nil { - return err - } - - tarReader := tar.NewReader(uncompressedStream) - - os.MkdirAll(targetDir, 0755) - - for true { - header, err := tarReader.Next() - - if err == io.EOF { - break - } - - if err != nil { - return err - } - - path := filepath.Join(targetDir, header.Name) - - switch header.Typeflag { - case tar.TypeDir: - if err := os.Mkdir(path, 0755); err != nil { - return err - } - case tar.TypeReg: - outFile, err := os.Create(path) - if err != nil { - return err - } - defer outFile.Close() - if _, err := io.Copy(outFile, tarReader); err != nil { - return err - } - default: - return fmt.Errorf("unknown type: %s in %s", header.Typeflag, header.Name) - } - } - - return nil - -} \ No newline at end of file + uncompressedStream, err := gzip.NewReader(buffer) + if err != nil { + return err + } + + tarReader := tar.NewReader(uncompressedStream) + + os.MkdirAll(targetDir, 0755) + + for true { + header, err := tarReader.Next() + + if err == io.EOF { + break + } + + if err != nil { + return err + } + + path := filepath.Join(targetDir, header.Name) + + switch header.Typeflag { + case tar.TypeDir: + if err := os.Mkdir(path, 0755); err != nil { + return err + } + case tar.TypeReg: + outFile, err := os.Create(path) + if err != nil { + return err + } + defer outFile.Close() + if _, err := io.Copy(outFile, tarReader); err != nil { + return err + } + default: + return fmt.Errorf("unknown type: %b in %s", header.Typeflag, header.Name) + } + } + + return nil + +} diff --git a/pkg/plugin/installer/http_installer_test.go b/pkg/plugin/installer/http_installer_test.go index 730c33af5..3c061e68d 100644 --- a/pkg/plugin/installer/http_installer_test.go +++ b/pkg/plugin/installer/http_installer_test.go @@ -16,88 +16,88 @@ limitations under the License. package installer // import "k8s.io/helm/pkg/plugin/installer" import ( - "testing" - "io/ioutil" - "os" - "k8s.io/helm/pkg/helm/helmpath" - "bytes" - "encoding/base64" + "bytes" + "encoding/base64" + "io/ioutil" + "k8s.io/helm/pkg/helm/helmpath" + "os" + "testing" ) -var _ Installer = new(HttpInstaller) +var _ Installer = new(HTTPInstaller) // Fake http client -type TestHttpGetter struct { - MockResponse *bytes.Buffer +type TestHTTPGetter struct { + MockResponse *bytes.Buffer } -func (t *TestHttpGetter) Get(href string) (*bytes.Buffer, error) { return t.MockResponse, nil } +func (t *TestHTTPGetter) Get(href string) (*bytes.Buffer, error) { return t.MockResponse, nil } // Fake plugin tarball data var fakePluginB64 = "H4sIAKRj51kAA+3UX0vCUBgGcC9jn+Iwuk3Peza3GeyiUlJQkcogCOzgli7dJm4TvYk+a5+k479UqquUCJ/fLs549sLO2TnvWnJa9aXnjwujYdYLovxMhsPcfnHOLdNkOXthM/IVQQYjg2yyLLJ4kXGhLp5j0z3P41tZksqxmspL3B/O+j/XtZu1y8rdYzkOZRCxduKPk53ny6Wwz/GfIIf1As8lxzGJSmoHNLJZphKHG4YpTCE0wVk3DULfpSJ3DMMqkj3P5JfMYLdX1Vr9Ie/5E5cstcdC8K04iGLX5HaJuKpWL17F0TCIBi5pf/0pjtLhun5j3f9v6r7wfnI/H0eNp9d1/5P6Gez0vzo7wsoxfrAZbTny/o9k6J8z/VkO/LPlWdC1iVpbEEcq5nmeJ13LEtmbV0k2r2PrOs9PuuNglC5rL1Y5S/syXRQmutaNw1BGnnp8Wq3UG51WvX1da3bKtZtCN/R09DwAAAAAAAAAAAAAAAAAAADAb30AoMczDwAoAAA=" func TestStripName(t *testing.T) { - if stripPluginName("fake-plugin-0.0.1.tar.gz") != "fake-plugin" { - t.Errorf("name does not match expected value") - } - if stripPluginName("fake-plugin-0.0.1.tgz") != "fake-plugin" { - t.Errorf("name does not match expected value") - } - if stripPluginName("fake-plugin.tgz") != "fake-plugin" { - t.Errorf("name does not match expected value") - } - if stripPluginName("fake-plugin.tar.gz") != "fake-plugin" { - t.Errorf("name does not match expected value") - } + if stripPluginName("fake-plugin-0.0.1.tar.gz") != "fake-plugin" { + t.Errorf("name does not match expected value") + } + if stripPluginName("fake-plugin-0.0.1.tgz") != "fake-plugin" { + t.Errorf("name does not match expected value") + } + if stripPluginName("fake-plugin.tgz") != "fake-plugin" { + t.Errorf("name does not match expected value") + } + if stripPluginName("fake-plugin.tar.gz") != "fake-plugin" { + t.Errorf("name does not match expected value") + } } -func TestHttpInstaller(t *testing.T) { - source := "https://repo.localdomain/plugins/fake-plugin-0.0.1.tar.gz" - hh, err := ioutil.TempDir("", "helm-home-") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(hh) - - home := helmpath.Home(hh) - if err := os.MkdirAll(home.Plugins(), 0755); err != nil { - t.Fatalf("Could not create %s: %s", home.Plugins(), err) - } - - i, err := NewForSource(source, "0.0.1", home) - if err != nil { - t.Errorf("unexpected error: %s", err) - } - - // ensure a HttpInstaller was returned - httpInstaller, ok := i.(*HttpInstaller) - if !ok { - t.Error("expected a HttpInstaller") - } - - // inject fake http client responding with minimal plugin tarball - mockTgz, err := base64.StdEncoding.DecodeString(fakePluginB64) - if err != nil { - t.Fatalf("Could not decode fake tgz plugin: %s", err) - } - - httpInstaller.getter = &TestHttpGetter{ - MockResponse: bytes.NewBuffer(mockTgz), - } - - // install the plugin - if err := Install(i); err != nil { - t.Error(err) - } - if i.Path() != home.Path("plugins", "fake-plugin") { - t.Errorf("expected path '$HELM_HOME/plugins/fake-plugin', got %q", i.Path()) - } - - // Install again to test plugin exists error - if err := Install(i); err == nil { - t.Error("expected error for plugin exists, got none") - } else if err.Error() != "plugin already exists" { - t.Errorf("expected error for plugin exists, got (%v)", err) - } - -} \ No newline at end of file +func TestHTTPInstaller(t *testing.T) { + source := "https://repo.localdomain/plugins/fake-plugin-0.0.1.tar.gz" + hh, err := ioutil.TempDir("", "helm-home-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(hh) + + home := helmpath.Home(hh) + if err := os.MkdirAll(home.Plugins(), 0755); err != nil { + t.Fatalf("Could not create %s: %s", home.Plugins(), err) + } + + i, err := NewForSource(source, "0.0.1", home) + if err != nil { + t.Errorf("unexpected error: %s", err) + } + + // ensure a HttpInstaller was returned + httpInstaller, ok := i.(*HTTPInstaller) + if !ok { + t.Error("expected a HttpInstaller") + } + + // inject fake http client responding with minimal plugin tarball + mockTgz, err := base64.StdEncoding.DecodeString(fakePluginB64) + if err != nil { + t.Fatalf("Could not decode fake tgz plugin: %s", err) + } + + httpInstaller.getter = &TestHTTPGetter{ + MockResponse: bytes.NewBuffer(mockTgz), + } + + // install the plugin + if err := Install(i); err != nil { + t.Error(err) + } + if i.Path() != home.Path("plugins", "fake-plugin") { + t.Errorf("expected path '$HELM_HOME/plugins/fake-plugin', got %q", i.Path()) + } + + // Install again to test plugin exists error + if err := Install(i); err == nil { + t.Error("expected error for plugin exists, got none") + } else if err.Error() != "plugin already exists" { + t.Errorf("expected error for plugin exists, got (%v)", err) + } + +} diff --git a/pkg/plugin/installer/installer.go b/pkg/plugin/installer/installer.go index b82e2f8b2..10433f4cd 100644 --- a/pkg/plugin/installer/installer.go +++ b/pkg/plugin/installer/installer.go @@ -69,8 +69,8 @@ func NewForSource(source, version string, home helmpath.Home) (Installer, error) // Check if source is a local directory if isLocalReference(source) { return NewLocalInstaller(source, home) - } else if isRemoteHttpArchive(source) { - return NewHttpInstaller(source, home) + } else if isRemoteHTTPArchive(source) { + return NewHTTPInstaller(source, home) } return NewVCSInstaller(source, version, home) } @@ -90,10 +90,10 @@ func isLocalReference(source string) bool { return err == nil } -// isRemoteHttpArchive checks if the source is a http/https url and is an archive -func isRemoteHttpArchive(source string) bool { +// isRemoteHTTPArchive checks if the source is a http/https url and is an archive +func isRemoteHTTPArchive(source string) bool { if strings.HasPrefix(source, "http://") || strings.HasPrefix(source, "https://") { - for suffix, _ := range Extractors { + for suffix := range Extractors { if strings.HasSuffix(source, suffix) { return true } From 4831089500a967507465fd81a66a808fbaed2224 Mon Sep 17 00:00:00 2001 From: Johan Lyheden Date: Fri, 20 Oct 2017 10:28:40 +0200 Subject: [PATCH 033/107] Add tests to HTTPInstaller, update plugin documentation --- docs/plugins.md | 2 + pkg/plugin/installer/http_installer_test.go | 92 ++++++++++++++++++++- 2 files changed, 91 insertions(+), 3 deletions(-) diff --git a/docs/plugins.md b/docs/plugins.md index 1bee8bd56..de80491aa 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -41,6 +41,8 @@ $ cp -a myplugin/ $(helm home)/plugins/ If you have a plugin tar distribution, simply untar the plugin into the `$(helm home)/plugins` directory. +You can also install tarball plugins directly from url by issuing `helm plugin install http://domain/path/to/plugin.tar.gz` + ## Building Plugins In many ways, a plugin is similar to a chart. Each plugin has a top-level diff --git a/pkg/plugin/installer/http_installer_test.go b/pkg/plugin/installer/http_installer_test.go index 3c061e68d..ca1a71e3e 100644 --- a/pkg/plugin/installer/http_installer_test.go +++ b/pkg/plugin/installer/http_installer_test.go @@ -18,6 +18,7 @@ package installer // import "k8s.io/helm/pkg/plugin/installer" import ( "bytes" "encoding/base64" + "fmt" "io/ioutil" "k8s.io/helm/pkg/helm/helmpath" "os" @@ -29,9 +30,10 @@ var _ Installer = new(HTTPInstaller) // Fake http client type TestHTTPGetter struct { MockResponse *bytes.Buffer + MockError error } -func (t *TestHTTPGetter) Get(href string) (*bytes.Buffer, error) { return t.MockResponse, nil } +func (t *TestHTTPGetter) Get(href string) (*bytes.Buffer, error) { return t.MockResponse, t.MockError } // Fake plugin tarball data var fakePluginB64 = "H4sIAKRj51kAA+3UX0vCUBgGcC9jn+Iwuk3Peza3GeyiUlJQkcogCOzgli7dJm4TvYk+a5+k479UqquUCJ/fLs549sLO2TnvWnJa9aXnjwujYdYLovxMhsPcfnHOLdNkOXthM/IVQQYjg2yyLLJ4kXGhLp5j0z3P41tZksqxmspL3B/O+j/XtZu1y8rdYzkOZRCxduKPk53ny6Wwz/GfIIf1As8lxzGJSmoHNLJZphKHG4YpTCE0wVk3DULfpSJ3DMMqkj3P5JfMYLdX1Vr9Ie/5E5cstcdC8K04iGLX5HaJuKpWL17F0TCIBi5pf/0pjtLhun5j3f9v6r7wfnI/H0eNp9d1/5P6Gez0vzo7wsoxfrAZbTny/o9k6J8z/VkO/LPlWdC1iVpbEEcq5nmeJ13LEtmbV0k2r2PrOs9PuuNglC5rL1Y5S/syXRQmutaNw1BGnnp8Wq3UG51WvX1da3bKtZtCN/R09DwAAAAAAAAAAAAAAAAAAADAb30AoMczDwAoAAA=" @@ -69,10 +71,10 @@ func TestHTTPInstaller(t *testing.T) { t.Errorf("unexpected error: %s", err) } - // ensure a HttpInstaller was returned + // ensure a HTTPInstaller was returned httpInstaller, ok := i.(*HTTPInstaller) if !ok { - t.Error("expected a HttpInstaller") + t.Error("expected a HTTPInstaller") } // inject fake http client responding with minimal plugin tarball @@ -101,3 +103,87 @@ func TestHTTPInstaller(t *testing.T) { } } + +func TestHTTPInstallerNonExistentVersion(t *testing.T) { + source := "https://repo.localdomain/plugins/fake-plugin-0.0.2.tar.gz" + hh, err := ioutil.TempDir("", "helm-home-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(hh) + + home := helmpath.Home(hh) + if err := os.MkdirAll(home.Plugins(), 0755); err != nil { + t.Fatalf("Could not create %s: %s", home.Plugins(), err) + } + + i, err := NewForSource(source, "0.0.2", home) + if err != nil { + t.Errorf("unexpected error: %s", err) + } + + // ensure a HTTPInstaller was returned + httpInstaller, ok := i.(*HTTPInstaller) + if !ok { + t.Error("expected a HTTPInstaller") + } + + // inject fake http client responding with error + httpInstaller.getter = &TestHTTPGetter{ + MockError: fmt.Errorf("failed to download plugin for some reason"), + } + + // attempt to install the plugin + if err := Install(i); err == nil { + t.Error("expected error from http client") + } + +} + +func TestHTTPInstallerUpdate(t *testing.T) { + source := "https://repo.localdomain/plugins/fake-plugin-0.0.1.tar.gz" + hh, err := ioutil.TempDir("", "helm-home-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(hh) + + home := helmpath.Home(hh) + if err := os.MkdirAll(home.Plugins(), 0755); err != nil { + t.Fatalf("Could not create %s: %s", home.Plugins(), err) + } + + i, err := NewForSource(source, "0.0.1", home) + if err != nil { + t.Errorf("unexpected error: %s", err) + } + + // ensure a HTTPInstaller was returned + httpInstaller, ok := i.(*HTTPInstaller) + if !ok { + t.Error("expected a HTTPInstaller") + } + + // inject fake http client responding with minimal plugin tarball + mockTgz, err := base64.StdEncoding.DecodeString(fakePluginB64) + if err != nil { + t.Fatalf("Could not decode fake tgz plugin: %s", err) + } + + httpInstaller.getter = &TestHTTPGetter{ + MockResponse: bytes.NewBuffer(mockTgz), + } + + // install the plugin before updating + if err := Install(i); err != nil { + t.Error(err) + } + if i.Path() != home.Path("plugins", "fake-plugin") { + t.Errorf("expected path '$HELM_HOME/plugins/fake-plugin', got %q", i.Path()) + } + + // Update plugin, should fail because it is not implemented + if err := Update(i); err == nil { + t.Error("update method not implemented for http installer") + } +} From e16a835bedea2487c0eedacce72d8c7548be811a Mon Sep 17 00:00:00 2001 From: Jacob Tomlinson Date: Fri, 20 Oct 2017 12:19:51 +0100 Subject: [PATCH 034/107] Add clarification to resolve #3046 There must be at least one subchart or template file, therefore the `charts` and `templates` directories are not strictly optional. --- docs/charts.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/charts.md b/docs/charts.md index 81c3d44f5..58b467dc4 100644 --- a/docs/charts.md +++ b/docs/charts.md @@ -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 dependancy 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: From 14cd8833eea008dc95b329d8c534f65b2f8a6d8b Mon Sep 17 00:00:00 2001 From: Michael Venezia Date: Fri, 20 Oct 2017 09:40:03 -0400 Subject: [PATCH 035/107] Adding documentation on $ variable --- docs/chart_template_guide/variables.md | 30 +++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/docs/chart_template_guide/variables.md b/docs/chart_template_guide/variables.md index 34b6fa891..f9f5768c9 100644 --- a/docs/chart_template_guide/variables.md +++ b/docs/chart_template_guide/variables.md @@ -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. From 8a30b58eee77c8ef9e90e42725e6d78647534077 Mon Sep 17 00:00:00 2001 From: Michael Venezia Date: Fri, 20 Oct 2017 09:46:36 -0400 Subject: [PATCH 036/107] Updating comment indentation as requested --- docs/chart_template_guide/variables.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/chart_template_guide/variables.md b/docs/chart_template_guide/variables.md index f9f5768c9..b55e6e422 100644 --- a/docs/chart_template_guide/variables.md +++ b/docs/chart_template_guide/variables.md @@ -111,10 +111,10 @@ kind: Secret metadata: name: {{ .name }} labels: -# Many helm templates would use `.` below, but that will not work, -# however `$` will work here + # 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 + # I cannot reference .Chart.Name, but I can do $.Chart.Name chart: "{{ $.Chart.Name }}-{{ $.Chart.Version }}" release: "{{ $.Release.Name }}" heritage: "{{ $.Release.Service }}" From f4f932fabd197f7e6d608c8672b33a483b4b76fa Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Fri, 20 Oct 2017 09:54:00 -0700 Subject: [PATCH 037/107] fix circle not building tags CircleCI recently skipped building tags by default, so we need to explicitly enable it. See https://circleci.com/docs/2.0/configuration-reference/#tags --- .circleci/config.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 273643b7c..e7cf729fb 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -23,3 +23,11 @@ jobs: - deploy: name: deploy command: .circleci/deploy.sh +workflows: + version: 2 + build: + jobs: + - build: + filters: + tags: + only: /.*/ From 3171f89e48635c09c61dca6b4d5646c5b2931280 Mon Sep 17 00:00:00 2001 From: Alexander Lukyanchenko Date: Sat, 21 Oct 2017 11:10:18 +0300 Subject: [PATCH 038/107] Add previous namespace mismatch warning --- cmd/helm/upgrade.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go index 6ecd98608..629b3edc0 100644 --- a/cmd/helm/upgrade.go +++ b/cmd/helm/upgrade.go @@ -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{ From 08c1144f5eb3e3b636d9775617287cc26e53dba4 Mon Sep 17 00:00:00 2001 From: Adam Reese Date: Mon, 23 Oct 2017 13:24:03 -0700 Subject: [PATCH 039/107] chore(*): bump version to v2.7.0 --- README.md | 8 ++++---- pkg/version/version.go | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 8faf4f24b..022afd79e 100644 --- a/README.md +++ b/README.md @@ -34,10 +34,10 @@ Think of it like apt/yum/homebrew for Kubernetes. Binary downloads of the Helm client can be found at the following links: -- [OSX](https://kubernetes-helm.storage.googleapis.com/helm-v2.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.0-darwin-amd64.tar.gz) +- [Linux](https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-linux-amd64.tar.gz) +- [Linux 32-bit](https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-linux-386.tar.gz) +- [Windows](https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-windows-amd64.tar.gz) 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`. diff --git a/pkg/version/version.go b/pkg/version/version.go index 71b6af465..2109a0ae0 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -26,7 +26,7 @@ var ( // Increment major number for new feature additions and behavioral changes. // Increment minor number for bug fixes and performance enhancements. // Increment patch number for critical fixes to existing releases. - Version = "v2.6" + Version = "v2.7" // BuildMetadata is extra build time data BuildMetadata = "unreleased" From 22e5381251591f46ac861861083df1f92be0522b Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Tue, 24 Oct 2017 11:44:28 -0400 Subject: [PATCH 040/107] feat(chart): Adding maintainer url Each maintainer can have an optional URL. There are seceral use cases for providing a URL instead of an email address: - The case where a maintainer wants to hide their email address behind a webform for personal security - When the maintainer is an organization and feedback should go to an issue queue This change: - Adds the proto field for url - Updates the generated files for the chart proto - Includes linting for the url - Updates the docs to include the url Closes #3056 --- _proto/hapi/chart/metadata.proto | 3 ++ docs/charts.md | 1 + pkg/lint/rules/chartfile.go | 2 + pkg/proto/hapi/chart/metadata.pb.go | 64 +++++++++++++++++------------ 4 files changed, 43 insertions(+), 27 deletions(-) diff --git a/_proto/hapi/chart/metadata.proto b/_proto/hapi/chart/metadata.proto index 44ab82635..37d3ac348 100644 --- a/_proto/hapi/chart/metadata.proto +++ b/_proto/hapi/chart/metadata.proto @@ -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. diff --git a/docs/charts.md b/docs/charts.md index 81c3d44f5..77d57f7ea 100644 --- a/docs/charts.md +++ b/docs/charts.md @@ -52,6 +52,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. diff --git a/pkg/lint/rules/chartfile.go b/pkg/lint/rules/chartfile.go index fb94cc4b9..0dab0d250 100644 --- a/pkg/lint/rules/chartfile.go +++ b/pkg/lint/rules/chartfile.go @@ -141,6 +141,8 @@ func validateChartMaintainer(cf *chart.Metadata) error { return errors.New("each maintainer requires a name") } else if maintainer.Email != "" && !govalidator.IsEmail(maintainer.Email) { return fmt.Errorf("invalid email '%s' for maintainer '%s'", maintainer.Email, maintainer.Name) + } else if maintainer.Url != "" && !govalidator.IsURL(maintainer.Url) { + return fmt.Errorf("invalid url '%s' for maintainer '%s'", maintainer.Url, maintainer.Name) } } return nil diff --git a/pkg/proto/hapi/chart/metadata.pb.go b/pkg/proto/hapi/chart/metadata.pb.go index af9f58153..c9034ffdc 100644 --- a/pkg/proto/hapi/chart/metadata.pb.go +++ b/pkg/proto/hapi/chart/metadata.pb.go @@ -39,6 +39,8 @@ type Maintainer struct { Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` // Email is an optional email address to contact the named maintainer Email string `protobuf:"bytes,2,opt,name=email" json:"email,omitempty"` + // Url is an optional URL to an address for the named maintainer + Url string `protobuf:"bytes,3,opt,name=url" json:"url,omitempty"` } func (m *Maintainer) Reset() { *m = Maintainer{} } @@ -60,6 +62,13 @@ func (m *Maintainer) GetEmail() string { return "" } +func (m *Maintainer) GetUrl() string { + if m != nil { + return m.Url + } + return "" +} + // Metadata for a Chart file. This models the structure of a Chart.yaml file. // // Spec: https://k8s.io/helm/blob/master/docs/design/chart_format.md#the-chart-file @@ -226,31 +235,32 @@ func init() { func init() { proto.RegisterFile("hapi/chart/metadata.proto", fileDescriptor2) } var fileDescriptor2 = []byte{ - // 412 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x52, 0x5d, 0x6b, 0xd5, 0x40, - 0x10, 0x35, 0xbd, 0x9f, 0x99, 0x58, 0x0d, 0x83, 0x94, 0xb5, 0x88, 0x84, 0x8b, 0x42, 0x9e, 0x52, - 0x50, 0x90, 0xe2, 0x83, 0xa0, 0x50, 0xfa, 0xa0, 0xbd, 0x95, 0xe0, 0x07, 0xf8, 0xb6, 0x26, 0x43, - 0xef, 0xd2, 0x64, 0x37, 0xec, 0x6e, 0x2b, 0xf7, 0x47, 0xfb, 0x1f, 0x64, 0x37, 0xd9, 0x26, 0x95, - 0xbe, 0xcd, 0x39, 0x67, 0xe6, 0xec, 0x9e, 0x61, 0xe0, 0xf9, 0x8e, 0x77, 0xe2, 0xa4, 0xda, 0x71, - 0x6d, 0x4f, 0x5a, 0xb2, 0xbc, 0xe6, 0x96, 0x17, 0x9d, 0x56, 0x56, 0x21, 0x38, 0xa9, 0xf0, 0xd2, - 0xe6, 0x1d, 0xc0, 0x05, 0x17, 0xd2, 0x72, 0x21, 0x49, 0x23, 0xc2, 0x5c, 0xf2, 0x96, 0x58, 0x94, - 0x45, 0x79, 0x5c, 0xfa, 0x1a, 0x9f, 0xc1, 0x82, 0x5a, 0x2e, 0x1a, 0x76, 0xe0, 0xc9, 0x1e, 0x6c, - 0xfe, 0xce, 0x61, 0x7d, 0x31, 0xd8, 0x3e, 0x38, 0x86, 0x30, 0xdf, 0xa9, 0x96, 0x86, 0x29, 0x5f, - 0x23, 0x83, 0x95, 0x51, 0x37, 0xba, 0x22, 0xc3, 0x66, 0xd9, 0x2c, 0x8f, 0xcb, 0x00, 0x9d, 0x72, - 0x4b, 0xda, 0x08, 0x25, 0xd9, 0xdc, 0x0f, 0x04, 0x88, 0x19, 0x24, 0x35, 0x99, 0x4a, 0x8b, 0xce, - 0x3a, 0x75, 0xe1, 0xd5, 0x29, 0x85, 0xc7, 0xb0, 0xbe, 0xa6, 0xfd, 0x1f, 0xa5, 0x6b, 0xc3, 0x96, - 0xde, 0xf6, 0x0e, 0xe3, 0x29, 0x24, 0xed, 0x5d, 0x3c, 0xc3, 0x56, 0xd9, 0x2c, 0x4f, 0xde, 0x1c, - 0x15, 0xe3, 0x02, 0x8a, 0x31, 0x7d, 0x39, 0x6d, 0xc5, 0x23, 0x58, 0x92, 0xbc, 0x12, 0x92, 0xd8, - 0xda, 0x3f, 0x39, 0x20, 0x97, 0x4b, 0x54, 0x4a, 0xb2, 0xb8, 0xcf, 0xe5, 0x6a, 0x7c, 0x09, 0xc0, - 0x3b, 0xf1, 0x63, 0x08, 0x00, 0x5e, 0x99, 0x30, 0xf8, 0x02, 0xe2, 0x4a, 0xc9, 0x5a, 0xf8, 0x04, - 0x89, 0x97, 0x47, 0xc2, 0x39, 0x5a, 0x7e, 0x65, 0xd8, 0xe3, 0xde, 0xd1, 0xd5, 0xbd, 0x63, 0x17, - 0x1c, 0x0f, 0x83, 0x63, 0x60, 0x9c, 0x5e, 0x53, 0xa7, 0xa9, 0xe2, 0x96, 0x6a, 0xf6, 0x24, 0x8b, - 0xf2, 0x75, 0x39, 0x61, 0xf0, 0x15, 0x1c, 0x5a, 0xd1, 0x34, 0xa4, 0x83, 0xc5, 0x53, 0x6f, 0x71, - 0x9f, 0xc4, 0x73, 0x48, 0xb8, 0x94, 0xca, 0x72, 0xf7, 0x0f, 0xc3, 0x52, 0xbf, 0x9d, 0xd7, 0xf7, - 0xb6, 0x13, 0x2e, 0xe7, 0xe3, 0xd8, 0x77, 0x26, 0xad, 0xde, 0x97, 0xd3, 0xc9, 0xe3, 0x0f, 0x90, - 0xfe, 0xdf, 0x80, 0x29, 0xcc, 0xae, 0x69, 0x3f, 0xdc, 0x84, 0x2b, 0xdd, 0x25, 0xdd, 0xf2, 0xe6, - 0x26, 0xdc, 0x44, 0x0f, 0xde, 0x1f, 0x9c, 0x46, 0x9b, 0x0c, 0x96, 0x67, 0xfd, 0x7a, 0x13, 0x58, - 0x7d, 0xdf, 0x7e, 0xde, 0x5e, 0xfe, 0xdc, 0xa6, 0x8f, 0x30, 0x86, 0xc5, 0xf9, 0xe5, 0xb7, 0xaf, - 0x5f, 0xd2, 0xe8, 0xd3, 0xea, 0xd7, 0xc2, 0xff, 0xe8, 0xf7, 0xd2, 0xdf, 0xf0, 0xdb, 0x7f, 0x01, - 0x00, 0x00, 0xff, 0xff, 0xd7, 0x2b, 0xf5, 0x83, 0xe0, 0x02, 0x00, 0x00, + // 420 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x52, 0x5b, 0x6b, 0xd4, 0x40, + 0x14, 0x36, 0xcd, 0xde, 0x72, 0x62, 0x35, 0x1c, 0xa4, 0x8c, 0x45, 0x24, 0x2c, 0x0a, 0xfb, 0xb4, + 0x05, 0x7d, 0x29, 0x3e, 0x08, 0x0a, 0xa5, 0x82, 0x76, 0x2b, 0xc1, 0x0b, 0xf8, 0x36, 0x26, 0x87, + 0xee, 0xd0, 0x64, 0x26, 0x4c, 0x66, 0x2b, 0xfb, 0xa3, 0xfd, 0x0f, 0x32, 0x27, 0x49, 0x93, 0x95, + 0xbe, 0x7d, 0x97, 0x99, 0x6f, 0xe6, 0x1c, 0x3e, 0x78, 0xbe, 0x95, 0xb5, 0x3a, 0xcb, 0xb7, 0xd2, + 0xba, 0xb3, 0x8a, 0x9c, 0x2c, 0xa4, 0x93, 0xeb, 0xda, 0x1a, 0x67, 0x10, 0xbc, 0xb5, 0x66, 0x6b, + 0xf9, 0x09, 0xe0, 0x4a, 0x2a, 0xed, 0xa4, 0xd2, 0x64, 0x11, 0x61, 0xa2, 0x65, 0x45, 0x22, 0x48, + 0x83, 0x55, 0x94, 0x31, 0xc6, 0x67, 0x30, 0xa5, 0x4a, 0xaa, 0x52, 0x1c, 0xb1, 0xd8, 0x12, 0x4c, + 0x20, 0xdc, 0xd9, 0x52, 0x84, 0xac, 0x79, 0xb8, 0xfc, 0x3b, 0x81, 0xc5, 0x55, 0xf7, 0xd0, 0x83, + 0x41, 0x08, 0x93, 0xad, 0xa9, 0xa8, 0xcb, 0x61, 0x8c, 0x02, 0xe6, 0x8d, 0xd9, 0xd9, 0x9c, 0x1a, + 0x11, 0xa6, 0xe1, 0x2a, 0xca, 0x7a, 0xea, 0x9d, 0x3b, 0xb2, 0x8d, 0x32, 0x5a, 0x4c, 0xf8, 0x42, + 0x4f, 0x31, 0x85, 0xb8, 0xa0, 0x26, 0xb7, 0xaa, 0x76, 0xde, 0x9d, 0xb2, 0x3b, 0x96, 0xf0, 0x14, + 0x16, 0xb7, 0xb4, 0xff, 0x63, 0x6c, 0xd1, 0x88, 0x19, 0xc7, 0xde, 0x73, 0x3c, 0x87, 0xb8, 0xba, + 0x1f, 0xb8, 0x11, 0xf3, 0x34, 0x5c, 0xc5, 0x6f, 0x4e, 0xd6, 0xc3, 0x4a, 0xd6, 0xc3, 0x3e, 0xb2, + 0xf1, 0x51, 0x3c, 0x81, 0x19, 0xe9, 0x1b, 0xa5, 0x49, 0x2c, 0xf8, 0xc9, 0x8e, 0xf9, 0xb9, 0x54, + 0x6e, 0xb4, 0x88, 0xda, 0xb9, 0x3c, 0xc6, 0x97, 0x00, 0xb2, 0x56, 0x3f, 0xba, 0x01, 0x80, 0x9d, + 0x91, 0x82, 0x2f, 0x20, 0xca, 0x8d, 0x2e, 0x14, 0x4f, 0x10, 0xb3, 0x3d, 0x08, 0x3e, 0xd1, 0xc9, + 0x9b, 0x46, 0x3c, 0x6e, 0x13, 0x3d, 0x6e, 0x13, 0xeb, 0x3e, 0xf1, 0xb8, 0x4f, 0xec, 0x15, 0xef, + 0x17, 0x54, 0x5b, 0xca, 0xa5, 0xa3, 0x42, 0x3c, 0x49, 0x83, 0xd5, 0x22, 0x1b, 0x29, 0xf8, 0x0a, + 0x8e, 0x9d, 0x2a, 0x4b, 0xb2, 0x7d, 0xc4, 0x53, 0x8e, 0x38, 0x14, 0xf1, 0x12, 0x62, 0xa9, 0xb5, + 0x71, 0xd2, 0xff, 0xa3, 0x11, 0x09, 0x6f, 0xe7, 0xf5, 0xc1, 0x76, 0xfa, 0x2e, 0x7d, 0x18, 0xce, + 0x5d, 0x68, 0x67, 0xf7, 0xd9, 0xf8, 0xe6, 0xe9, 0x7b, 0x48, 0xfe, 0x3f, 0xe0, 0x3b, 0x73, 0x4b, + 0xfb, 0xae, 0x13, 0x1e, 0xfa, 0x6e, 0xdd, 0xc9, 0x72, 0xd7, 0x77, 0xa2, 0x25, 0xef, 0x8e, 0xce, + 0x83, 0x65, 0x0a, 0xb3, 0x8b, 0x76, 0xbd, 0x31, 0xcc, 0xbf, 0x6f, 0x3e, 0x6f, 0xae, 0x7f, 0x6e, + 0x92, 0x47, 0x18, 0xc1, 0xf4, 0xf2, 0xfa, 0xdb, 0xd7, 0x2f, 0x49, 0xf0, 0x71, 0xfe, 0x6b, 0xca, + 0x3f, 0xfa, 0x3d, 0xe3, 0x56, 0xbf, 0xfd, 0x17, 0x00, 0x00, 0xff, 0xff, 0x40, 0x4c, 0x34, 0x92, + 0xf2, 0x02, 0x00, 0x00, } From 3cba226e2db3e5b3c5e077e60e095a5f3ec95448 Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Tue, 24 Oct 2017 10:46:30 -0400 Subject: [PATCH 041/107] feat(search): Expose AppVersion in search results Some would like to expose and see the application version in the search results. This change displays it. Closes #3010 --- cmd/helm/search.go | 4 ++-- cmd/helm/search_test.go | 8 ++++---- .../testdata/helmhome/repository/cache/testing-index.yaml | 2 ++ 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/cmd/helm/search.go b/cmd/helm/search.go index 9f1398de3..fe572f46b 100644 --- a/cmd/helm/search.go +++ b/cmd/helm/search.go @@ -125,9 +125,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() } diff --git a/cmd/helm/search_test.go b/cmd/helm/search_test.go index 26878fd0f..7dc222a8e 100644 --- a/cmd/helm/search_test.go +++ b/cmd/helm/search_test.go @@ -34,18 +34,18 @@ 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 'syzygy', expect no matches", @@ -56,7 +56,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, }, { diff --git a/cmd/helm/testdata/helmhome/repository/cache/testing-index.yaml b/cmd/helm/testdata/helmhome/repository/cache/testing-index.yaml index df75878c1..96c98c38c 100644 --- a/cmd/helm/testdata/helmhome/repository/cache/testing-index.yaml +++ b/cmd/helm/testdata/helmhome/repository/cache/testing-index.yaml @@ -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: [] From 60fc7bde7327c5fd41c54f96c9b85b234a0890b2 Mon Sep 17 00:00:00 2001 From: Gabriel Miretti Date: Tue, 24 Oct 2017 21:08:37 -0300 Subject: [PATCH 042/107] Using Helm in Openshift Kubernetes distribution --- docs/kubernetes_distros.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/kubernetes_distros.md b/docs/kubernetes_distros.md index 7b5382893..620ef72ac 100644 --- a/docs/kubernetes_distros.md +++ b/docs/kubernetes_distros.md @@ -35,3 +35,7 @@ or create a `~/.kube/config`. ## Container Linux by CoreOS Helm requires that kubelet have access to a copy of the `socat` program to proxy connections to the Tiller API. On Container Linux the Kubelet runs inside of a [hyperkube](https://github.com/kubernetes/kubernetes/tree/master/cluster/images/hyperkube) container image that has socat. So, even though Container Linux doesn't ship `socat` the container filesystem running kubelet does have socat. To learn more read the [Kubelet Wrapper](https://coreos.com/kubernetes/docs/latest/kubelet-wrapper.html) docs. + +## Openshift + +Helm works straightforward on OpenShift Online, OpenShift Dedicated, OpenShift Container Platform (version >= 3.6) or OpenShift Origin (version >= 3.6). To learn more read [this blog](https://blog.openshift.com/getting-started-helm-openshift/) post. From bff5261715d01634cbe317bb8bb12fbb04e8d5c3 Mon Sep 17 00:00:00 2001 From: Neil Moore Date: Wed, 25 Oct 2017 15:53:23 +0100 Subject: [PATCH 043/107] Update charts.md --- docs/charts.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/docs/charts.md b/docs/charts.md index 81c3d44f5..714f0cc3e 100644 --- a/docs/charts.md +++ b/docs/charts.md @@ -449,6 +449,40 @@ 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" + +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. The release will +create all the above Kubernetes objects in the following order: + +- A-Namespace +- B-Namespace +- A-StatefulSet +- B-ReplicaSet +- A-Service +- B-Service + +This is because the Kubernetes objects from all the charts 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 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 From 7888f54adbcae71f088ea1219d87c8faaf0ca149 Mon Sep 17 00:00:00 2001 From: Neil Moore Date: Wed, 25 Oct 2017 15:56:34 +0100 Subject: [PATCH 044/107] Update charts.md --- docs/charts.md | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/docs/charts.md b/docs/charts.md index 714f0cc3e..42aa6c1d7 100644 --- a/docs/charts.md +++ b/docs/charts.md @@ -460,14 +460,14 @@ Suppose that a chart named "A" creates the following Kubernetes objects - statefulset "A-StatefulSet" - service "A-Service" -A is dependent on chart B that creates objects +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. The release will -create all the above Kubernetes objects in the following order: +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 @@ -476,11 +476,16 @@ create all the above Kubernetes objects in the following order: - A-Service - B-Service -This is because the Kubernetes objects from all the charts 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. +This is because when Helm installs/upgrades charts, +the Kubernetes objects from the charts and all its dependencies are -The install order of types is given by the enumeration InstallOrder in kind_sorter.go +- 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 From 441758b206db1df58be058511d2d4dfba4c836c1 Mon Sep 17 00:00:00 2001 From: Yagnesh Mistry Date: Thu, 26 Oct 2017 15:41:38 +0000 Subject: [PATCH 045/107] add version flag to tiller binary (#2965) add version flag to tiller binary * TODO comment on tiller.go --- cmd/tiller/tiller.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cmd/tiller/tiller.go b/cmd/tiller/tiller.go index f18ce6c3d..fadf8dd3a 100644 --- a/cmd/tiller/tiller.go +++ b/cmd/tiller/tiller.go @@ -77,6 +77,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. // @@ -92,8 +93,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) } From 4c7617a76e310fa53473b31b18b371b344da4fef Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Fri, 27 Oct 2017 09:58:34 -0400 Subject: [PATCH 046/107] fix(circleci): Fixing the glide/vendor cache so it is used by glide This commit does a few things: * It moves the information being cached to be the glide cache. This will make the glide install process faster. * The cache is restored from prior to installing the dependencies. --- .circleci/config.yml | 8 ++++++-- glide.lock | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index e7cf729fb..73e734825 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,13 +10,17 @@ 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 diff --git a/glide.lock b/glide.lock index cb17642e4..11b56ad2d 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: 650f1d4cd9e9dc5ba76480a5465923ce1bbd11b8fa956b644aaf975e8f7e1f33 -updated: 2017-10-12T13:08:50.435765-07:00 +hash: 397d714c3a444071879981d3e6575931bd637166e845c6577eaea08ffde7e33d +updated: 2017-10-27T11:04:22.887120936-04:00 imports: - name: cloud.google.com/go version: 3b1ae45394a234c385be014e9a488f2bb6eef821 From c27333fd4ce4301df49322100b905ccc4a9eec17 Mon Sep 17 00:00:00 2001 From: Joan Rieu Date: Sun, 29 Oct 2017 14:58:57 +0100 Subject: [PATCH 047/107] docs(chart): add note about `.helmignore` for `.Files` --- docs/charts.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/charts.md b/docs/charts.md index 5098e0041..ea747db3d 100644 --- a/docs/charts.md +++ b/docs/charts.md @@ -589,9 +589,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 From 171fa2ac46d63602a560d4e32b246e87f8dc1173 Mon Sep 17 00:00:00 2001 From: Joan Rieu Date: Sun, 29 Oct 2017 15:05:43 +0100 Subject: [PATCH 048/107] docs(chart-files): add note about `.helmignore` --- docs/chart_template_guide/accessing_files.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/chart_template_guide/accessing_files.md b/docs/chart_template_guide/accessing_files.md index 3911af830..c547babdd 100644 --- a/docs/chart_template_guide/accessing_files.md +++ b/docs/chart_template_guide/accessing_files.md @@ -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. From 8775f632f246ff3c7746c3cc3f71d51a06101e93 Mon Sep 17 00:00:00 2001 From: Christian Jauvin Date: Wed, 25 Oct 2017 18:36:55 -0400 Subject: [PATCH 049/107] Fix for relative chart path support in index.yaml --- pkg/downloader/chart_downloader.go | 11 +++++--- pkg/downloader/chart_downloader_test.go | 4 +++ .../cache/testing-relative-index.yaml | 28 +++++++++++++++++++ ...testing-relative-trailing-slash-index.yaml | 28 +++++++++++++++++++ .../helmhome/repository/repositories.yaml | 6 +++- 5 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 pkg/downloader/testdata/helmhome/repository/cache/testing-relative-index.yaml create mode 100644 pkg/downloader/testdata/helmhome/repository/cache/testing-relative-trailing-slash-index.yaml diff --git a/pkg/downloader/chart_downloader.go b/pkg/downloader/chart_downloader.go index a8a1b5a57..f0fd5073c 100644 --- a/pkg/downloader/chart_downloader.go +++ b/pkg/downloader/chart_downloader.go @@ -217,12 +217,15 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, ge // If the URL is relative (no scheme), prepend the chart repo's base URL if !u.IsAbs() { - path := u.Path - u, err = url.Parse(rc.URL) + repoURL, err := url.Parse(rc.URL) if err != nil { - return u, r.Client, err + return repoURL, r.Client, err } - u.Path = u.Path + path + q := repoURL.Query() + // We need a trailing slash for ResolveReference to work, but make sure there isn't already one + repoURL.Path = strings.TrimSuffix(repoURL.Path, "/") + "/" + u = repoURL.ResolveReference(u) + u.RawQuery = q.Encode() return u, r.Client, err } diff --git a/pkg/downloader/chart_downloader_test.go b/pkg/downloader/chart_downloader_test.go index 73f9191c9..0100772e9 100644 --- a/pkg/downloader/chart_downloader_test.go +++ b/pkg/downloader/chart_downloader_test.go @@ -44,6 +44,10 @@ func TestResolveChartRef(t *testing.T) { {name: "reference, version, testing repo", ref: "testing/alpine", version: "0.2.0", expect: "http://example.com/alpine-0.2.0.tgz"}, {name: "reference, version, malformed repo", ref: "malformed/alpine", version: "1.2.3", expect: "http://dl.example.com/alpine-1.2.3.tgz"}, {name: "reference, querystring repo", ref: "testing-querystring/alpine", expect: "http://example.com/alpine-1.2.3.tgz?key=value"}, + {name: "reference, testing-relative repo", ref: "testing-relative/foo", expect: "http://example.com/helm/charts/foo-1.2.3.tgz"}, + {name: "reference, testing-relative repo", ref: "testing-relative/bar", expect: "http://example.com/helm/bar-1.2.3.tgz"}, + {name: "reference, testing-relative-trailing-slash repo", ref: "testing-relative-trailing-slash/foo", expect: "http://example.com/helm/charts/foo-1.2.3.tgz"}, + {name: "reference, testing-relative-trailing-slash repo", ref: "testing-relative-trailing-slash/bar", expect: "http://example.com/helm/bar-1.2.3.tgz"}, {name: "full URL, HTTPS, irrelevant version", ref: "https://example.com/foo-1.2.3.tgz", version: "0.1.0", expect: "https://example.com/foo-1.2.3.tgz", fail: true}, {name: "full URL, file", ref: "file:///foo-1.2.3.tgz", fail: true}, {name: "invalid", ref: "invalid-1.2.3", fail: true}, diff --git a/pkg/downloader/testdata/helmhome/repository/cache/testing-relative-index.yaml b/pkg/downloader/testdata/helmhome/repository/cache/testing-relative-index.yaml new file mode 100644 index 000000000..210f92e45 --- /dev/null +++ b/pkg/downloader/testdata/helmhome/repository/cache/testing-relative-index.yaml @@ -0,0 +1,28 @@ +apiVersion: v1 +entries: + foo: + - name: foo + description: Foo Chart With Relative Path + engine: gotpl + home: https://k8s.io/helm + keywords: [] + maintainers: [] + sources: + - https://github.com/kubernetes/charts + urls: + - charts/foo-1.2.3.tgz + version: 1.2.3 + checksum: 0e6661f193211d7a5206918d42f5c2a9470b737d + bar: + - name: bar + description: Bar Chart With Relative Path + engine: gotpl + home: https://k8s.io/helm + keywords: [] + maintainers: [] + sources: + - https://github.com/kubernetes/charts + urls: + - bar-1.2.3.tgz + version: 1.2.3 + checksum: 0e6661f193211d7a5206918d42f5c2a9470b737d diff --git a/pkg/downloader/testdata/helmhome/repository/cache/testing-relative-trailing-slash-index.yaml b/pkg/downloader/testdata/helmhome/repository/cache/testing-relative-trailing-slash-index.yaml new file mode 100644 index 000000000..210f92e45 --- /dev/null +++ b/pkg/downloader/testdata/helmhome/repository/cache/testing-relative-trailing-slash-index.yaml @@ -0,0 +1,28 @@ +apiVersion: v1 +entries: + foo: + - name: foo + description: Foo Chart With Relative Path + engine: gotpl + home: https://k8s.io/helm + keywords: [] + maintainers: [] + sources: + - https://github.com/kubernetes/charts + urls: + - charts/foo-1.2.3.tgz + version: 1.2.3 + checksum: 0e6661f193211d7a5206918d42f5c2a9470b737d + bar: + - name: bar + description: Bar Chart With Relative Path + engine: gotpl + home: https://k8s.io/helm + keywords: [] + maintainers: [] + sources: + - https://github.com/kubernetes/charts + urls: + - bar-1.2.3.tgz + version: 1.2.3 + checksum: 0e6661f193211d7a5206918d42f5c2a9470b737d diff --git a/pkg/downloader/testdata/helmhome/repository/repositories.yaml b/pkg/downloader/testdata/helmhome/repository/repositories.yaml index 68efb461a..374d95c8a 100644 --- a/pkg/downloader/testdata/helmhome/repository/repositories.yaml +++ b/pkg/downloader/testdata/helmhome/repository/repositories.yaml @@ -11,4 +11,8 @@ repositories: - name: malformed url: "http://dl.example.com" - name: testing-querystring - url: "http://example.com?key=value" \ No newline at end of file + url: "http://example.com?key=value" + - name: testing-relative + url: "http://example.com/helm" + - name: testing-relative-trailing-slash + url: "http://example.com/helm/" \ No newline at end of file From 3c3936fcaaf2c86d783ed87d6d1aca25d6dd5d15 Mon Sep 17 00:00:00 2001 From: Simon Schmidt Date: Mon, 30 Oct 2017 18:49:20 +0200 Subject: [PATCH 050/107] Fix typo for --service-account --- docs/using_helm.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/using_helm.md b/docs/using_helm.md index 6bf3b2bcc..531cdac44 100755 --- a/docs/using_helm.md +++ b/docs/using_helm.md @@ -498,7 +498,7 @@ accepts chart source code, and (after audit) packages those for you. In some cases you may wish to scope Tiller or deploy multiple Tillers to a single cluster. Here are some best practices when operating in those circumstances. 1. Tiller can be [installed](install.md) into any namespace. By default, it is installed into kube-system. You can run multiple Tillers provided they each run in their own namespace. -2. Limiting Tiller to only be able to install into specific namespaces and/or resource types is controlled by Kubernetes [RBAC](https://kubernetes.io/docs/admin/authorization/rbac/) roles and rolebindings. You can add a service account to Tiller when configuring Helm via `helm init --service-acount `. You can find more information about that [here](service_accounts.md). +2. Limiting Tiller to only be able to install into specific namespaces and/or resource types is controlled by Kubernetes [RBAC](https://kubernetes.io/docs/admin/authorization/rbac/) roles and rolebindings. You can add a service account to Tiller when configuring Helm via `helm init --service-account `. You can find more information about that [here](service_accounts.md). 3. Release names are unique PER TILLER INSTANCE. 4. Charts should only contain resources that exist in a single namespace. 5. It is not recommended to have multiple Tillers configured to manage resources in the same namespace. From e464479cb2bb9b7228f595e513622bef2b173946 Mon Sep 17 00:00:00 2001 From: Joan Rieu Date: Mon, 30 Oct 2017 22:58:17 +0100 Subject: [PATCH 051/107] docs(templates): fix misleading/broken examples --- docs/charts_tips_and_tricks.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/charts_tips_and_tricks.md b/docs/charts_tips_and_tricks.md index 885c30085..1573f2edd 100644 --- a/docs/charts_tips_and_tricks.md +++ b/docs/charts_tips_and_tricks.md @@ -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 @@ -144,7 +144,7 @@ spec: template: metadata: annotations: - checksum/config: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }} + checksum/config: {{ .Files.Get "path/to/config" | sha256sum }} [...] ``` From 25e851ecd03301030aa76b106520a52ec2a8f44e Mon Sep 17 00:00:00 2001 From: Joan Rieu Date: Mon, 30 Oct 2017 23:08:50 +0100 Subject: [PATCH 052/107] docs(templates): fix and expand config checksum example --- docs/charts_tips_and_tricks.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/charts_tips_and_tricks.md b/docs/charts_tips_and_tricks.md index 1573f2edd..f1faca100 100644 --- a/docs/charts_tips_and_tricks.md +++ b/docs/charts_tips_and_tricks.md @@ -134,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 @@ -148,6 +147,9 @@ spec: [...] ``` +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 From 0af689b48976c50570155a9324eb13d44bbfac44 Mon Sep 17 00:00:00 2001 From: Joan Rieu Date: Mon, 30 Oct 2017 23:19:16 +0100 Subject: [PATCH 053/107] docs(templates): remove link to changed example --- docs/chart_template_guide/builtin_objects.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/chart_template_guide/builtin_objects.md b/docs/chart_template_guide/builtin_objects.md index 2e1a5d8a3..11982229b 100644 --- a/docs/chart_template_guide/builtin_objects.md +++ b/docs/chart_template_guide/builtin_objects.md @@ -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_. From ae49979175a784b9a83a4fa590edc0f2c6927719 Mon Sep 17 00:00:00 2001 From: xuhaigang Date: Thu, 31 Aug 2017 14:19:59 +0800 Subject: [PATCH 054/107] feat(helm): Add a flag --dep-up that helm install will automatically execute helm dep up when charts are in requirements.yaml but not in charts If checkdependencies returns an error, we can start download the charts which are not in charts. Closes #2879 --- cmd/helm/install.go | 19 ++++++++++++++++++- docs/helm/helm_install.md | 1 + docs/man/man1/helm_install.1 | 6 +++++- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/cmd/helm/install.go b/cmd/helm/install.go index d3b830029..9858a85fe 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -119,6 +119,7 @@ type installCmd struct { wait bool repoURL string devel bool + depUp bool certFile string keyFile string @@ -194,6 +195,7 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command { 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-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 } @@ -231,7 +233,22 @@ 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 { - return prettyError(err) + 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) diff --git a/docs/helm/helm_install.md b/docs/helm/helm_install.md index 74fe19759..7596688e1 100644 --- a/docs/helm/helm_install.md +++ b/docs/helm/helm_install.md @@ -70,6 +70,7 @@ helm install [CHART] ``` --ca-file string verify certificates of HTTPS-enabled servers using this CA bundle --cert-file string identify HTTPS client using this SSL certificate file + --dep-up run helm dependency update before installing the chart --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 diff --git a/docs/man/man1/helm_install.1 b/docs/man/man1/helm_install.1 index a19b3adf4..fe1856bed 100644 --- a/docs/man/man1/helm_install.1 +++ b/docs/man/man1/helm_install.1 @@ -122,6 +122,10 @@ charts in a repository, use 'helm search'. \fB\-\-cert\-file\fP="" identify HTTPS client using this SSL certificate file +.PP +\fB\-\-dep\-up\fP[=false] + run helm dependency update before installing the chart. + .PP \fB\-\-devel\fP[=false] use development versions, too. Equivalent to version '>0.0.0\-a'. If \-\-version is set, this is ignored. @@ -236,4 +240,4 @@ charts in a repository, use 'helm search'. .SH HISTORY .PP -19\-May\-2017 Auto generated by spf13/cobra +31\-Oct\-2017 Auto generated by spf13/cobra From f20af6ab4c419f14fd05ba03fcf1970d6d0da8a9 Mon Sep 17 00:00:00 2001 From: Ivan Pedrazas Date: Tue, 31 Oct 2017 12:26:47 +0000 Subject: [PATCH 055/107] feat(tiller): exposes port 44135 in tiller deployment Tiller exposes probes and metrics in 44135. Because tiller doesn't expose that port and does not contain any Prometheus annotations, making Prometheus scrape tiller is a bit more complex. Closes #2985 --- cmd/helm/installer/install.go | 1 + cmd/helm/installer/install_test.go | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/cmd/helm/installer/install.go b/cmd/helm/installer/install.go index c3d970726..9fa365a51 100644 --- a/cmd/helm/installer/install.go +++ b/cmd/helm/installer/install.go @@ -168,6 +168,7 @@ func generateDeployment(opts *Options) (*v1beta1.Deployment, error) { ImagePullPolicy: opts.pullPolicy(), Ports: []v1.ContainerPort{ {ContainerPort: 44134, Name: "tiller"}, + {ContainerPort: 44135, Name: "http"}, }, Env: []v1.EnvVar{ {Name: "TILLER_NAMESPACE", Value: opts.Namespace}, diff --git a/cmd/helm/installer/install_test.go b/cmd/helm/installer/install_test.go index f0ee61853..ad30557e2 100644 --- a/cmd/helm/installer/install_test.go +++ b/cmd/helm/installer/install_test.go @@ -207,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) { From a9756d140bd58e3052f3dd5f2e55b4abf31b5598 Mon Sep 17 00:00:00 2001 From: Valentin Tjoncke Date: Tue, 31 Oct 2017 16:09:12 +0100 Subject: [PATCH 056/107] Update related.md Add helm-gcs plugin --- docs/related.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/related.md b/docs/related.md index 73db34829..59177d65d 100644 --- a/docs/related.md +++ b/docs/related.md @@ -36,6 +36,7 @@ or [pull request](https://github.com/kubernetes/helm/pulls). - [App Registry](https://github.com/app-registry/helm-plugin) - Plugin to manage charts via the [App Registry specification](https://github.com/app-registry/spec) - [helm-secrets](https://github.com/futuresimple/helm-secrets) - Plugin to manage and store secrets safely - [helm-edit](https://github.com/mstrzele/helm-edit) - Plugin for editing release's values +- [helm-gcs](https://github.com/nouney/helm-gcs) - Plugin to manage repositories on Google Cloud Storage We also encourage GitHub authors to use the [helm-plugin](https://github.com/search?q=topic%3Ahelm-plugin&type=Repositories) tag on their plugin repositories. From 1eb96ad9bc1bc404256b4567ee4e3719c4fb81de Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Tue, 31 Oct 2017 18:15:41 -0700 Subject: [PATCH 057/107] use 127.0.0.1 instead of localhost --- cmd/helm/helm.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/helm/helm.go b/cmd/helm/helm.go index 4d3a9ae83..9bc98792e 100644 --- a/cmd/helm/helm.go +++ b/cmd/helm/helm.go @@ -174,7 +174,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) } From 371ff8f26deaf57556b35dd6c0378950ae07422e Mon Sep 17 00:00:00 2001 From: gardlt Date: Sat, 24 Jun 2017 20:01:59 -0500 Subject: [PATCH 058/107] feat(helm): adding kubeconfig flag --- cmd/helm/helm.go | 2 +- cmd/helm/install.go | 2 +- docs/helm/helm.md | 3 ++- docs/helm/helm_completion.md | 3 ++- docs/helm/helm_create.md | 3 ++- docs/helm/helm_delete.md | 3 ++- docs/helm/helm_dependency.md | 3 ++- docs/helm/helm_dependency_build.md | 3 ++- docs/helm/helm_dependency_list.md | 3 ++- docs/helm/helm_dependency_update.md | 3 ++- docs/helm/helm_fetch.md | 3 ++- docs/helm/helm_get.md | 3 ++- docs/helm/helm_get_hooks.md | 3 ++- docs/helm/helm_get_manifest.md | 3 ++- docs/helm/helm_get_values.md | 3 ++- docs/helm/helm_history.md | 3 ++- docs/helm/helm_home.md | 3 ++- docs/helm/helm_init.md | 3 ++- docs/helm/helm_inspect.md | 3 ++- docs/helm/helm_inspect_chart.md | 3 ++- docs/helm/helm_inspect_values.md | 3 ++- docs/helm/helm_install.md | 3 ++- docs/helm/helm_lint.md | 3 ++- docs/helm/helm_list.md | 3 ++- docs/helm/helm_package.md | 3 ++- docs/helm/helm_plugin.md | 3 ++- docs/helm/helm_plugin_install.md | 3 ++- docs/helm/helm_plugin_list.md | 3 ++- docs/helm/helm_plugin_remove.md | 3 ++- docs/helm/helm_plugin_update.md | 3 ++- docs/helm/helm_repo.md | 3 ++- docs/helm/helm_repo_add.md | 3 ++- docs/helm/helm_repo_index.md | 3 ++- docs/helm/helm_repo_list.md | 3 ++- docs/helm/helm_repo_remove.md | 3 ++- docs/helm/helm_repo_update.md | 3 ++- docs/helm/helm_reset.md | 3 ++- docs/helm/helm_rollback.md | 3 ++- docs/helm/helm_search.md | 3 ++- docs/helm/helm_serve.md | 3 ++- docs/helm/helm_status.md | 3 ++- docs/helm/helm_template.md | 3 ++- docs/helm/helm_test.md | 3 ++- docs/helm/helm_upgrade.md | 3 ++- docs/helm/helm_verify.md | 3 ++- docs/helm/helm_version.md | 3 ++- pkg/helm/environment/environment.go | 4 ++++ pkg/kube/config.go | 7 ++++++- 48 files changed, 100 insertions(+), 47 deletions(-) diff --git a/cmd/helm/helm.go b/cmd/helm/helm.go index 4d3a9ae83..3be4e5d12 100644 --- a/cmd/helm/helm.go +++ b/cmd/helm/helm.go @@ -216,7 +216,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) } diff --git a/cmd/helm/install.go b/cmd/helm/install.go index 9858a85fe..1ed179d57 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -460,7 +460,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" diff --git a/docs/helm/helm.md b/docs/helm/helm.md index 36e41835e..0b0eb37de 100644 --- a/docs/helm/helm.md +++ b/docs/helm/helm.md @@ -36,6 +36,7 @@ Environment: --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_completion.md b/docs/helm/helm_completion.md index 60cc7497c..68d227198 100644 --- a/docs/helm/helm_completion.md +++ b/docs/helm/helm_completion.md @@ -28,10 +28,11 @@ helm completion SHELL --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_create.md b/docs/helm/helm_create.md index 73d435d6c..4719e45d3 100644 --- a/docs/helm/helm_create.md +++ b/docs/helm/helm_create.md @@ -47,10 +47,11 @@ helm create NAME --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_delete.md b/docs/helm/helm_delete.md index 91fc51c22..5540736ad 100644 --- a/docs/helm/helm_delete.md +++ b/docs/helm/helm_delete.md @@ -38,10 +38,11 @@ helm delete [flags] RELEASE_NAME [...] --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_dependency.md b/docs/helm/helm_dependency.md index d7259c2f6..1b8b685e4 100644 --- a/docs/helm/helm_dependency.md +++ b/docs/helm/helm_dependency.md @@ -61,6 +61,7 @@ for this case. --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_dependency_build.md b/docs/helm/helm_dependency_build.md index d99eb0ea3..b16d56a58 100644 --- a/docs/helm/helm_dependency_build.md +++ b/docs/helm/helm_dependency_build.md @@ -34,10 +34,11 @@ helm dependency build [flags] CHART --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_dependency_list.md b/docs/helm/helm_dependency_list.md index 74e4fb80e..8003b79f4 100644 --- a/docs/helm/helm_dependency_list.md +++ b/docs/helm/helm_dependency_list.md @@ -26,10 +26,11 @@ helm dependency list [flags] CHART --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_dependency_update.md b/docs/helm/helm_dependency_update.md index 2fa782c34..2ed84ec15 100644 --- a/docs/helm/helm_dependency_update.md +++ b/docs/helm/helm_dependency_update.md @@ -39,10 +39,11 @@ helm dependency update [flags] CHART --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_fetch.md b/docs/helm/helm_fetch.md index 6bb3279c4..a8de1f446 100644 --- a/docs/helm/helm_fetch.md +++ b/docs/helm/helm_fetch.md @@ -48,10 +48,11 @@ helm fetch [flags] [chart URL | repo/chartname] [...] --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_get.md b/docs/helm/helm_get.md index 418566c78..0b8fc73fd 100644 --- a/docs/helm/helm_get.md +++ b/docs/helm/helm_get.md @@ -40,6 +40,7 @@ helm get [flags] RELEASE_NAME --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_get_hooks.md b/docs/helm/helm_get_hooks.md index c90d5a5e4..3e94b014a 100644 --- a/docs/helm/helm_get_hooks.md +++ b/docs/helm/helm_get_hooks.md @@ -28,10 +28,11 @@ helm get hooks [flags] RELEASE_NAME --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_get_manifest.md b/docs/helm/helm_get_manifest.md index 294ae9528..4c802a7f3 100644 --- a/docs/helm/helm_get_manifest.md +++ b/docs/helm/helm_get_manifest.md @@ -30,10 +30,11 @@ helm get manifest [flags] RELEASE_NAME --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_get_values.md b/docs/helm/helm_get_values.md index 7067d8ac0..57c344ef6 100644 --- a/docs/helm/helm_get_values.md +++ b/docs/helm/helm_get_values.md @@ -27,10 +27,11 @@ helm get values [flags] RELEASE_NAME --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_history.md b/docs/helm/helm_history.md index afd411515..7dfacc08b 100644 --- a/docs/helm/helm_history.md +++ b/docs/helm/helm_history.md @@ -43,10 +43,11 @@ helm history [flags] RELEASE_NAME --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_home.md b/docs/helm/helm_home.md index c5c4f50e3..2e7054e05 100644 --- a/docs/helm/helm_home.md +++ b/docs/helm/helm_home.md @@ -21,10 +21,11 @@ helm home --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_init.md b/docs/helm/helm_init.md index 0085f6cde..f6408dd99 100644 --- a/docs/helm/helm_init.md +++ b/docs/helm/helm_init.md @@ -61,10 +61,11 @@ helm init --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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-Oct-2017 +###### Auto generated by spf13/cobra on 1-Nov-2017 diff --git a/docs/helm/helm_inspect.md b/docs/helm/helm_inspect.md index a740c3b27..5219eaa33 100644 --- a/docs/helm/helm_inspect.md +++ b/docs/helm/helm_inspect.md @@ -35,6 +35,7 @@ helm inspect [CHART] --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_inspect_chart.md b/docs/helm/helm_inspect_chart.md index e9d5bc08c..36bd6df98 100644 --- a/docs/helm/helm_inspect_chart.md +++ b/docs/helm/helm_inspect_chart.md @@ -33,10 +33,11 @@ helm inspect chart [CHART] --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_inspect_values.md b/docs/helm/helm_inspect_values.md index a151c404b..d2d345b9b 100644 --- a/docs/helm/helm_inspect_values.md +++ b/docs/helm/helm_inspect_values.md @@ -33,10 +33,11 @@ helm inspect values [CHART] --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_install.md b/docs/helm/helm_install.md index 7596688e1..17963a06e 100644 --- a/docs/helm/helm_install.md +++ b/docs/helm/helm_install.md @@ -101,10 +101,11 @@ helm install [CHART] --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_lint.md b/docs/helm/helm_lint.md index 618d5c5e2..1a8ddb0cd 100644 --- a/docs/helm/helm_lint.md +++ b/docs/helm/helm_lint.md @@ -31,10 +31,11 @@ helm lint [flags] PATH --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_list.md b/docs/helm/helm_list.md index f32233756..9b13f887f 100644 --- a/docs/helm/helm_list.md +++ b/docs/helm/helm_list.md @@ -65,10 +65,11 @@ helm list [flags] [FILTER] --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_package.md b/docs/helm/helm_package.md index 88374b737..09513e793 100644 --- a/docs/helm/helm_package.md +++ b/docs/helm/helm_package.md @@ -39,10 +39,11 @@ helm package [flags] [CHART_PATH] [...] --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_plugin.md b/docs/helm/helm_plugin.md index 79653f5de..ce21e2b68 100644 --- a/docs/helm/helm_plugin.md +++ b/docs/helm/helm_plugin.md @@ -16,6 +16,7 @@ Manage client-side Helm plugins. --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_plugin_install.md b/docs/helm/helm_plugin_install.md index 635e68fff..03dc3c024 100644 --- a/docs/helm/helm_plugin_install.md +++ b/docs/helm/helm_plugin_install.md @@ -24,10 +24,11 @@ helm plugin install [options] ... --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_plugin_list.md b/docs/helm/helm_plugin_list.md index 823f4369b..134eac58f 100644 --- a/docs/helm/helm_plugin_list.md +++ b/docs/helm/helm_plugin_list.md @@ -18,10 +18,11 @@ helm plugin list --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_plugin_remove.md b/docs/helm/helm_plugin_remove.md index 8d02ee751..8dc301d3b 100644 --- a/docs/helm/helm_plugin_remove.md +++ b/docs/helm/helm_plugin_remove.md @@ -18,10 +18,11 @@ helm plugin remove ... --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_plugin_update.md b/docs/helm/helm_plugin_update.md index 9817c052b..5d786b01c 100644 --- a/docs/helm/helm_plugin_update.md +++ b/docs/helm/helm_plugin_update.md @@ -18,10 +18,11 @@ helm plugin update ... --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_repo.md b/docs/helm/helm_repo.md index 06cc1f4b2..2a2d67cec 100644 --- a/docs/helm/helm_repo.md +++ b/docs/helm/helm_repo.md @@ -20,6 +20,7 @@ Example usage: --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_repo_add.md b/docs/helm/helm_repo_add.md index 34e1c5b8c..5f8247fba 100644 --- a/docs/helm/helm_repo_add.md +++ b/docs/helm/helm_repo_add.md @@ -27,10 +27,11 @@ helm repo add [flags] [NAME] [URL] --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_repo_index.md b/docs/helm/helm_repo_index.md index 533e38848..a9f407a02 100644 --- a/docs/helm/helm_repo_index.md +++ b/docs/helm/helm_repo_index.md @@ -34,10 +34,11 @@ helm repo index [flags] [DIR] --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_repo_list.md b/docs/helm/helm_repo_list.md index f4ab740af..ee156ea66 100644 --- a/docs/helm/helm_repo_list.md +++ b/docs/helm/helm_repo_list.md @@ -18,10 +18,11 @@ helm repo list [flags] --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_repo_remove.md b/docs/helm/helm_repo_remove.md index 0198f9618..4620b30d0 100644 --- a/docs/helm/helm_repo_remove.md +++ b/docs/helm/helm_repo_remove.md @@ -18,10 +18,11 @@ helm repo remove [flags] [NAME] --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_repo_update.md b/docs/helm/helm_repo_update.md index 61cca84eb..85399bf17 100644 --- a/docs/helm/helm_repo_update.md +++ b/docs/helm/helm_repo_update.md @@ -24,10 +24,11 @@ helm repo update --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_reset.md b/docs/helm/helm_reset.md index 78218a4e9..122d49cf3 100644 --- a/docs/helm/helm_reset.md +++ b/docs/helm/helm_reset.md @@ -34,10 +34,11 @@ helm reset --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_rollback.md b/docs/helm/helm_rollback.md index 53baef487..8a6a0f558 100644 --- a/docs/helm/helm_rollback.md +++ b/docs/helm/helm_rollback.md @@ -40,10 +40,11 @@ helm rollback [flags] [RELEASE] [REVISION] --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_search.md b/docs/helm/helm_search.md index 8522e4867..e81aa515f 100644 --- a/docs/helm/helm_search.md +++ b/docs/helm/helm_search.md @@ -31,10 +31,11 @@ helm search [keyword] --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_serve.md b/docs/helm/helm_serve.md index 989694103..73e8467ff 100644 --- a/docs/helm/helm_serve.md +++ b/docs/helm/helm_serve.md @@ -39,10 +39,11 @@ helm serve --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_status.md b/docs/helm/helm_status.md index 82fa9faec..38c78d296 100644 --- a/docs/helm/helm_status.md +++ b/docs/helm/helm_status.md @@ -38,10 +38,11 @@ helm status [flags] RELEASE_NAME --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_template.md b/docs/helm/helm_template.md index adfffa269..0a66145ac 100644 --- a/docs/helm/helm_template.md +++ b/docs/helm/helm_template.md @@ -42,10 +42,11 @@ helm template [flags] CHART --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_test.md b/docs/helm/helm_test.md index ae6f3e0cd..c95c12a15 100644 --- a/docs/helm/helm_test.md +++ b/docs/helm/helm_test.md @@ -35,10 +35,11 @@ helm test [RELEASE] --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_upgrade.md b/docs/helm/helm_upgrade.md index 07927523f..fe3eef6ef 100644 --- a/docs/helm/helm_upgrade.md +++ b/docs/helm/helm_upgrade.md @@ -70,10 +70,11 @@ helm upgrade [RELEASE] [CHART] --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_verify.md b/docs/helm/helm_verify.md index cd967c52e..4153c1235 100644 --- a/docs/helm/helm_verify.md +++ b/docs/helm/helm_verify.md @@ -33,10 +33,11 @@ helm verify [flags] PATH --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/docs/helm/helm_version.md b/docs/helm/helm_version.md index 3b55fafa0..74fe86d9f 100644 --- a/docs/helm/helm_version.md +++ b/docs/helm/helm_version.md @@ -47,10 +47,11 @@ helm version --home string location of your Helm config. Overrides $HELM_HOME (default "$HOME/.helm") --host string address of Tiller. Overrides $HELM_HOST --kube-context string name of the kubeconfig context to use + --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 1-Nov-2017 diff --git a/pkg/helm/environment/environment.go b/pkg/helm/environment/environment.go index 3ddd90449..e72710064 100644 --- a/pkg/helm/environment/environment.go +++ b/pkg/helm/environment/environment.go @@ -46,6 +46,8 @@ type EnvSettings struct { Debug bool // KubeContext is the name of the kubeconfig context. KubeContext string + // KubeConfig is the name of the kubeconfig file. + KubeConfig string } // AddFlags binds flags to the given flagset. @@ -53,6 +55,7 @@ func (s *EnvSettings) AddFlags(fs *pflag.FlagSet) { fs.StringVar((*string)(&s.Home), "home", DefaultHelmHome, "location of your Helm config. Overrides $HELM_HOME") fs.StringVar(&s.TillerHost, "host", "", "address of Tiller. Overrides $HELM_HOST") fs.StringVar(&s.KubeContext, "kube-context", "", "name of the kubeconfig context to use") + fs.StringVar(&s.KubeConfig, "kubeconfig", "", "path to kubeconfig file. Overrides $KUBECONFIG") fs.BoolVar(&s.Debug, "debug", false, "enable verbose output") fs.StringVar(&s.TillerNamespace, "tiller-namespace", "kube-system", "namespace of Tiller") } @@ -77,6 +80,7 @@ var envMap = map[string]string{ "debug": "HELM_DEBUG", "home": "HELM_HOME", "host": "HELM_HOST", + "kubeconfig": "KUBECONFIG", "tiller-namespace": "TILLER_NAMESPACE", } diff --git a/pkg/kube/config.go b/pkg/kube/config.go index b6560486e..541d4eba6 100644 --- a/pkg/kube/config.go +++ b/pkg/kube/config.go @@ -19,7 +19,7 @@ package kube // import "k8s.io/helm/pkg/kube" import "k8s.io/client-go/tools/clientcmd" // GetConfig returns a Kubernetes client config for a given context. -func GetConfig(context string) clientcmd.ClientConfig { +func GetConfig(context string, kubeconfig string) clientcmd.ClientConfig { rules := clientcmd.NewDefaultClientConfigLoadingRules() rules.DefaultClientConfig = &clientcmd.DefaultClientConfig @@ -28,5 +28,10 @@ func GetConfig(context string) clientcmd.ClientConfig { if context != "" { overrides.CurrentContext = context } + + if kubeconfig != "" { + rules.ExplicitPath = kubeconfig + } + return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(rules, overrides) } From b8734a173ec079e9ec181b03bee44bebae8e9c2e Mon Sep 17 00:00:00 2001 From: Matt Tucker Date: Wed, 1 Nov 2017 16:44:38 -0600 Subject: [PATCH 059/107] fix(docs): fix code comment for ReuseValues() --- pkg/helm/option.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/helm/option.go b/pkg/helm/option.go index 2b30cd3c5..387247b86 100644 --- a/pkg/helm/option.go +++ b/pkg/helm/option.go @@ -348,7 +348,8 @@ func ResetValues(reset bool) UpdateOption { } } -// ReuseValues will (if true) trigger resetting the values to their original state. +// ReuseValues will cause Tiller to reuse the values from the last release. +// This is ignored if ResetValues is true. func ReuseValues(reuse bool) UpdateOption { return func(opts *options) { opts.reuseValues = reuse From e261f44dde521bee47f2b00093f53cfd4af9a949 Mon Sep 17 00:00:00 2001 From: Michael Venezia Date: Fri, 3 Nov 2017 15:48:17 -0400 Subject: [PATCH 060/107] Adding documentation on what rbac privileges are needed for a helm client to connect to tiller --- docs/service_accounts.md | 58 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/docs/service_accounts.md b/docs/service_accounts.md index 612074d03..e04fa7f3d 100644 --- a/docs/service_accounts.md +++ b/docs/service_accounts.md @@ -110,3 +110,61 @@ NAME READY STATUS RESTARTS AGE wayfaring-yak-alpine 0/1 ContainerCreating 0 0s ``` +# Helm and Service Accounts +In order for a helm client to talk to a tiller, it will need certain privileges to be granted. + +Specifically, the helm client will need to be able to `create` `pods/portforward` and +be able to `list` `pods` in the namespace where tiller is running. + +## Example: Service account for a helm client + +In this example, we will assume tiller is running in a namespace called `tiller-world` +and that the helm client is running in a namespace called `helm-world` By default, +tiller is running in the `kube-system` namespace. + +In helm-user.yaml: +```yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: helm-user-serviceaccount + namespace: helm-world +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: Role +metadata: + name: helm-user-role + namespace: tiller-world +rules: +- apiGroups: + - "" + resources: + - pods/portforward + verbs: + - create +- apiGroups: + - "" + resources: + - pods + verbs: + - list +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: RoleBinding +metadata: + name: helm-user-role-binding + namespace: tiller-world +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: helm-user-role +subjects: +- kind: ServiceAccount + name: helm-user-serviceaccount + namespace: helm-world +``` + +Please note that the role and rolebindings must be placed in the namespace +that tiller is running in, while the service account must be in the namespace +that the helm client is to be run in. (the pod using the helm client must +be using the service account created here) \ No newline at end of file From 62e2f140270097230557c8f70924fb0c7253774c Mon Sep 17 00:00:00 2001 From: Michael Venezia Date: Fri, 3 Nov 2017 16:12:42 -0400 Subject: [PATCH 061/107] Fixing a couple of styling issues --- docs/service_accounts.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/service_accounts.md b/docs/service_accounts.md index e04fa7f3d..38e422fe1 100644 --- a/docs/service_accounts.md +++ b/docs/service_accounts.md @@ -122,7 +122,7 @@ In this example, we will assume tiller is running in a namespace called `tiller- and that the helm client is running in a namespace called `helm-world` By default, tiller is running in the `kube-system` namespace. -In helm-user.yaml: +In `helm-user.yaml`: ```yaml apiVersion: v1 kind: ServiceAccount @@ -164,7 +164,7 @@ subjects: namespace: helm-world ``` -Please note that the role and rolebindings must be placed in the namespace +Please note that the `role` and `rolebinding` must be placed in the namespace that tiller is running in, while the service account must be in the namespace that the helm client is to be run in. (the pod using the helm client must be using the service account created here) \ No newline at end of file From 82ef751414d9de6b64ffaf89d964ab67cb5d4766 Mon Sep 17 00:00:00 2001 From: Adam Reese Date: Fri, 3 Nov 2017 14:57:33 -0700 Subject: [PATCH 062/107] fix(tiller): upgrade last deployed release Fixes #2437 Two bugs were causing this behavior - Tiller was marking the previous release superseded when an upgrade failed. - Upgrade was diffing against failed releases --- pkg/storage/storage.go | 12 ++++++------ pkg/tiller/release_update.go | 13 +++++++++---- pkg/tiller/release_update_test.go | 4 ++-- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/pkg/storage/storage.go b/pkg/storage/storage.go index e1a570188..4ac5dbf4f 100644 --- a/pkg/storage/storage.go +++ b/pkg/storage/storage.go @@ -18,6 +18,7 @@ package storage // import "k8s.io/helm/pkg/storage" import ( "fmt" + "strings" rspb "k8s.io/helm/pkg/proto/hapi/release" relutil "k8s.io/helm/pkg/releaseutil" @@ -127,14 +128,13 @@ func (s *Storage) Deployed(name string) (*rspb.Release, error) { "OWNER": "TILLER", "STATUS": "DEPLOYED", }) - switch { - case err != nil: - return nil, err - case len(ls) == 0: - return nil, fmt.Errorf("%q has no deployed releases", name) - default: + if err == nil { return ls[0], nil } + if strings.Contains(err.Error(), "not found") { + return nil, fmt.Errorf("%q has no deployed releases", name) + } + return nil, err } // History returns the revision history for the release with the provided name, or diff --git a/pkg/tiller/release_update.go b/pkg/tiller/release_update.go index 18cf56737..d251db753 100644 --- a/pkg/tiller/release_update.go +++ b/pkg/tiller/release_update.go @@ -69,8 +69,8 @@ func (s *ReleaseServer) prepareUpdate(req *services.UpdateReleaseRequest) (*rele return nil, nil, errMissingChart } - // finds the non-deleted release with the given name - currentRelease, err := s.env.Releases.Last(req.Name) + // finds the deployed release with the given name + currentRelease, err := s.env.Releases.Deployed(req.Name) if err != nil { return nil, nil, err } @@ -80,9 +80,15 @@ func (s *ReleaseServer) prepareUpdate(req *services.UpdateReleaseRequest) (*rele return nil, nil, err } + // finds the non-deleted release with the given name + lastRelease, err := s.env.Releases.Last(req.Name) + if err != nil { + return nil, nil, err + } + // Increment revision count. This is passed to templates, and also stored on // the release object. - revision := currentRelease.Version + 1 + revision := lastRelease.Version + 1 ts := timeconv.Now() options := chartutil.ReleaseOptions{ @@ -151,7 +157,6 @@ func (s *ReleaseServer) performUpdate(originalRelease, updatedRelease *release.R if err := s.ReleaseModule.Update(originalRelease, updatedRelease, req, s.env); err != nil { msg := fmt.Sprintf("Upgrade %q failed: %s", updatedRelease.Name, err) s.Log("warning: %s", msg) - originalRelease.Info.Status.Code = release.Status_SUPERSEDED updatedRelease.Info.Status.Code = release.Status_FAILED updatedRelease.Info.Description = msg s.recordRelease(originalRelease, true) diff --git a/pkg/tiller/release_update_test.go b/pkg/tiller/release_update_test.go index a3eb37f4a..0f2bcbabd 100644 --- a/pkg/tiller/release_update_test.go +++ b/pkg/tiller/release_update_test.go @@ -234,8 +234,8 @@ func TestUpdateReleaseFailure(t *testing.T) { if err != nil { t.Errorf("Expected to be able to get previous release") } - if oldStatus := oldRelease.Info.Status.Code; oldStatus != release.Status_SUPERSEDED { - t.Errorf("Expected SUPERSEDED status on previous Release version. Got %v", oldStatus) + if oldStatus := oldRelease.Info.Status.Code; oldStatus != release.Status_DEPLOYED { + t.Errorf("Expected Deployed status on previous Release version. Got %v", oldStatus) } } From 8203d813a50cb43a38450cbba28e563d3b931059 Mon Sep 17 00:00:00 2001 From: Justin Scott Date: Tue, 7 Nov 2017 10:45:18 -0800 Subject: [PATCH 063/107] docs(helm): Correct --set to --override in helm init example --- docs/install.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install.md b/docs/install.md index ea51afd89..96aea1f76 100755 --- a/docs/install.md +++ b/docs/install.md @@ -241,7 +241,7 @@ In the example below we use `--override` to add the revision property and set its value to 1. ``` -helm init --set metadata.annotations."deployment\.kubernetes\.io/revision"="1" +helm init --override metadata.annotations."deployment\.kubernetes\.io/revision"="1" ``` Output: From 6f6d46de06a1b580d350f3cdf9bfb78cf4de76a3 Mon Sep 17 00:00:00 2001 From: Alexander Lukyanchenko Date: Tue, 7 Nov 2017 23:42:13 +0300 Subject: [PATCH 064/107] Fix err checking --- cmd/helm/upgrade.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go index 629b3edc0..7a7dfb0f6 100644 --- a/cmd/helm/upgrade.go +++ b/cmd/helm/upgrade.go @@ -153,7 +153,7 @@ func (u *upgradeCmd) run() error { // inside of the grpc.rpcError message. releaseHistory, err := u.client.ReleaseHistory(u.release, helm.WithMaxHistory(1)) - if err != nil { + 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) From ece9486182db705923e3f04618c5f6a37e71076d Mon Sep 17 00:00:00 2001 From: Pietro Menna Date: Wed, 8 Nov 2017 00:33:34 -0200 Subject: [PATCH 065/107] fix(helm): home env not set on Windows When setting $HELM_HOME, only $HOME was considered. This variable is not always present on Windows. --- pkg/helm/environment/environment.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/helm/environment/environment.go b/pkg/helm/environment/environment.go index e72710064..b8bcf0def 100644 --- a/pkg/helm/environment/environment.go +++ b/pkg/helm/environment/environment.go @@ -28,11 +28,12 @@ import ( "github.com/spf13/pflag" + "k8s.io/client-go/util/homedir" "k8s.io/helm/pkg/helm/helmpath" ) // DefaultHelmHome is the default HELM_HOME. -var DefaultHelmHome = filepath.Join("$HOME", ".helm") +var DefaultHelmHome = filepath.Join(homedir.HomeDir(), ".helm") // EnvSettings describes all of the environment settings. type EnvSettings struct { From 8ee89fe5dcdf35bc937508367dce8133ed08f43e Mon Sep 17 00:00:00 2001 From: Pietro Menna Date: Wed, 8 Nov 2017 00:36:05 -0200 Subject: [PATCH 066/107] fix(helm): update documentation to reflect $HOME env var change --- docs/helm/helm.md | 4 ++-- docs/helm/helm_completion.md | 4 ++-- docs/helm/helm_create.md | 4 ++-- docs/helm/helm_delete.md | 4 ++-- docs/helm/helm_dependency.md | 4 ++-- docs/helm/helm_dependency_build.md | 4 ++-- docs/helm/helm_dependency_list.md | 4 ++-- docs/helm/helm_dependency_update.md | 4 ++-- docs/helm/helm_fetch.md | 4 ++-- docs/helm/helm_get.md | 4 ++-- docs/helm/helm_get_hooks.md | 4 ++-- docs/helm/helm_get_manifest.md | 4 ++-- docs/helm/helm_get_values.md | 4 ++-- docs/helm/helm_history.md | 4 ++-- docs/helm/helm_home.md | 4 ++-- docs/helm/helm_init.md | 4 ++-- docs/helm/helm_inspect.md | 4 ++-- docs/helm/helm_inspect_chart.md | 4 ++-- docs/helm/helm_inspect_values.md | 4 ++-- docs/helm/helm_install.md | 4 ++-- docs/helm/helm_lint.md | 4 ++-- docs/helm/helm_list.md | 4 ++-- docs/helm/helm_package.md | 4 ++-- docs/helm/helm_plugin.md | 4 ++-- docs/helm/helm_plugin_install.md | 4 ++-- docs/helm/helm_plugin_list.md | 4 ++-- docs/helm/helm_plugin_remove.md | 4 ++-- docs/helm/helm_plugin_update.md | 4 ++-- docs/helm/helm_repo.md | 4 ++-- docs/helm/helm_repo_add.md | 4 ++-- docs/helm/helm_repo_index.md | 4 ++-- docs/helm/helm_repo_list.md | 4 ++-- docs/helm/helm_repo_remove.md | 4 ++-- docs/helm/helm_repo_update.md | 4 ++-- docs/helm/helm_reset.md | 4 ++-- docs/helm/helm_rollback.md | 4 ++-- docs/helm/helm_search.md | 4 ++-- docs/helm/helm_serve.md | 4 ++-- docs/helm/helm_status.md | 4 ++-- docs/helm/helm_template.md | 4 ++-- docs/helm/helm_test.md | 4 ++-- docs/helm/helm_upgrade.md | 4 ++-- docs/helm/helm_verify.md | 4 ++-- docs/helm/helm_version.md | 4 ++-- 44 files changed, 88 insertions(+), 88 deletions(-) diff --git a/docs/helm/helm.md b/docs/helm/helm.md index 0b0eb37de..caa4301a0 100644 --- a/docs/helm/helm.md +++ b/docs/helm/helm.md @@ -33,7 +33,7 @@ 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 @@ -68,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 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_completion.md b/docs/helm/helm_completion.md index 68d227198..9fe91d52a 100644 --- a/docs/helm/helm_completion.md +++ b/docs/helm/helm_completion.md @@ -25,7 +25,7 @@ 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 @@ -35,4 +35,4 @@ helm completion SHELL ### SEE ALSO * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_create.md b/docs/helm/helm_create.md index 4719e45d3..fa047ee23 100644 --- a/docs/helm/helm_create.md +++ b/docs/helm/helm_create.md @@ -44,7 +44,7 @@ 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 @@ -54,4 +54,4 @@ helm create NAME ### SEE ALSO * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_delete.md b/docs/helm/helm_delete.md index 5540736ad..bf3adb6b2 100644 --- a/docs/helm/helm_delete.md +++ b/docs/helm/helm_delete.md @@ -35,7 +35,7 @@ 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 @@ -45,4 +45,4 @@ helm delete [flags] RELEASE_NAME [...] ### SEE ALSO * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_dependency.md b/docs/helm/helm_dependency.md index 1b8b685e4..673c2c384 100644 --- a/docs/helm/helm_dependency.md +++ b/docs/helm/helm_dependency.md @@ -58,7 +58,7 @@ 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 @@ -71,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 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_dependency_build.md b/docs/helm/helm_dependency_build.md index b16d56a58..0c9d1f97b 100644 --- a/docs/helm/helm_dependency_build.md +++ b/docs/helm/helm_dependency_build.md @@ -31,7 +31,7 @@ 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 @@ -41,4 +41,4 @@ helm dependency build [flags] CHART ### SEE ALSO * [helm dependency](helm_dependency.md) - manage a chart's dependencies -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_dependency_list.md b/docs/helm/helm_dependency_list.md index 8003b79f4..a558356be 100644 --- a/docs/helm/helm_dependency_list.md +++ b/docs/helm/helm_dependency_list.md @@ -23,7 +23,7 @@ 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 @@ -33,4 +33,4 @@ helm dependency list [flags] CHART ### SEE ALSO * [helm dependency](helm_dependency.md) - manage a chart's dependencies -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_dependency_update.md b/docs/helm/helm_dependency_update.md index 2ed84ec15..191a69644 100644 --- a/docs/helm/helm_dependency_update.md +++ b/docs/helm/helm_dependency_update.md @@ -36,7 +36,7 @@ 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 @@ -46,4 +46,4 @@ helm dependency update [flags] CHART ### SEE ALSO * [helm dependency](helm_dependency.md) - manage a chart's dependencies -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_fetch.md b/docs/helm/helm_fetch.md index a8de1f446..5b4127c0a 100644 --- a/docs/helm/helm_fetch.md +++ b/docs/helm/helm_fetch.md @@ -45,7 +45,7 @@ helm fetch [flags] [chart URL | repo/chartname] [...] ``` --debug enable verbose output - --home string location of your Helm config. Overrides $HELM_HOME (default "$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 @@ -55,4 +55,4 @@ helm fetch [flags] [chart URL | repo/chartname] [...] ### SEE ALSO * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_get.md b/docs/helm/helm_get.md index 0b8fc73fd..ce6718b28 100644 --- a/docs/helm/helm_get.md +++ b/docs/helm/helm_get.md @@ -37,7 +37,7 @@ 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 @@ -50,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 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_get_hooks.md b/docs/helm/helm_get_hooks.md index 3e94b014a..3db1b8d55 100644 --- a/docs/helm/helm_get_hooks.md +++ b/docs/helm/helm_get_hooks.md @@ -25,7 +25,7 @@ helm get hooks [flags] RELEASE_NAME ``` --debug enable verbose output - --home string location of your Helm config. Overrides $HELM_HOME (default "$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 @@ -35,4 +35,4 @@ helm get hooks [flags] RELEASE_NAME ### SEE ALSO * [helm get](helm_get.md) - download a named release -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_get_manifest.md b/docs/helm/helm_get_manifest.md index 4c802a7f3..11597716d 100644 --- a/docs/helm/helm_get_manifest.md +++ b/docs/helm/helm_get_manifest.md @@ -27,7 +27,7 @@ helm get manifest [flags] RELEASE_NAME ``` --debug enable verbose output - --home string location of your Helm config. Overrides $HELM_HOME (default "$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 @@ -37,4 +37,4 @@ helm get manifest [flags] RELEASE_NAME ### SEE ALSO * [helm get](helm_get.md) - download a named release -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_get_values.md b/docs/helm/helm_get_values.md index 57c344ef6..fe23e6819 100644 --- a/docs/helm/helm_get_values.md +++ b/docs/helm/helm_get_values.md @@ -24,7 +24,7 @@ helm get values [flags] RELEASE_NAME ``` --debug enable verbose output - --home string location of your Helm config. Overrides $HELM_HOME (default "$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 @@ -34,4 +34,4 @@ helm get values [flags] RELEASE_NAME ### SEE ALSO * [helm get](helm_get.md) - download a named release -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_history.md b/docs/helm/helm_history.md index 7dfacc08b..84792081a 100644 --- a/docs/helm/helm_history.md +++ b/docs/helm/helm_history.md @@ -40,7 +40,7 @@ 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 @@ -50,4 +50,4 @@ helm history [flags] RELEASE_NAME ### SEE ALSO * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_home.md b/docs/helm/helm_home.md index 2e7054e05..069f6a162 100644 --- a/docs/helm/helm_home.md +++ b/docs/helm/helm_home.md @@ -18,7 +18,7 @@ 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 @@ -28,4 +28,4 @@ helm home ### SEE ALSO * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_init.md b/docs/helm/helm_init.md index f6408dd99..eeee9b013 100644 --- a/docs/helm/helm_init.md +++ b/docs/helm/helm_init.md @@ -58,7 +58,7 @@ 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 @@ -68,4 +68,4 @@ helm init ### SEE ALSO * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_inspect.md b/docs/helm/helm_inspect.md index 5219eaa33..7fc56cacc 100644 --- a/docs/helm/helm_inspect.md +++ b/docs/helm/helm_inspect.md @@ -32,7 +32,7 @@ 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 @@ -44,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 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_inspect_chart.md b/docs/helm/helm_inspect_chart.md index 36bd6df98..e1e88fbbe 100644 --- a/docs/helm/helm_inspect_chart.md +++ b/docs/helm/helm_inspect_chart.md @@ -30,7 +30,7 @@ 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 @@ -40,4 +40,4 @@ helm inspect chart [CHART] ### SEE ALSO * [helm inspect](helm_inspect.md) - inspect a chart -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_inspect_values.md b/docs/helm/helm_inspect_values.md index d2d345b9b..348336b8f 100644 --- a/docs/helm/helm_inspect_values.md +++ b/docs/helm/helm_inspect_values.md @@ -30,7 +30,7 @@ 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 @@ -40,4 +40,4 @@ helm inspect values [CHART] ### SEE ALSO * [helm inspect](helm_inspect.md) - inspect a chart -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_install.md b/docs/helm/helm_install.md index 17963a06e..bb66345f4 100644 --- a/docs/helm/helm_install.md +++ b/docs/helm/helm_install.md @@ -98,7 +98,7 @@ 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 @@ -108,4 +108,4 @@ helm install [CHART] ### SEE ALSO * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_lint.md b/docs/helm/helm_lint.md index 1a8ddb0cd..a07a43627 100644 --- a/docs/helm/helm_lint.md +++ b/docs/helm/helm_lint.md @@ -28,7 +28,7 @@ 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 @@ -38,4 +38,4 @@ helm lint [flags] PATH ### SEE ALSO * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_list.md b/docs/helm/helm_list.md index 9b13f887f..b1dcb19de 100644 --- a/docs/helm/helm_list.md +++ b/docs/helm/helm_list.md @@ -62,7 +62,7 @@ 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 @@ -72,4 +72,4 @@ helm list [flags] [FILTER] ### SEE ALSO * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_package.md b/docs/helm/helm_package.md index 09513e793..c4b506641 100644 --- a/docs/helm/helm_package.md +++ b/docs/helm/helm_package.md @@ -36,7 +36,7 @@ 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 @@ -46,4 +46,4 @@ helm package [flags] [CHART_PATH] [...] ### SEE ALSO * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_plugin.md b/docs/helm/helm_plugin.md index ce21e2b68..5a636724c 100644 --- a/docs/helm/helm_plugin.md +++ b/docs/helm/helm_plugin.md @@ -13,7 +13,7 @@ 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 @@ -27,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 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_plugin_install.md b/docs/helm/helm_plugin_install.md index 03dc3c024..1b1e03ea7 100644 --- a/docs/helm/helm_plugin_install.md +++ b/docs/helm/helm_plugin_install.md @@ -21,7 +21,7 @@ helm plugin install [options] ... ``` --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 @@ -31,4 +31,4 @@ helm plugin install [options] ... ### SEE ALSO * [helm plugin](helm_plugin.md) - add, list, or remove Helm plugins -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_plugin_list.md b/docs/helm/helm_plugin_list.md index 134eac58f..403ef1a6f 100644 --- a/docs/helm/helm_plugin_list.md +++ b/docs/helm/helm_plugin_list.md @@ -15,7 +15,7 @@ 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 @@ -25,4 +25,4 @@ helm plugin list ### SEE ALSO * [helm plugin](helm_plugin.md) - add, list, or remove Helm plugins -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_plugin_remove.md b/docs/helm/helm_plugin_remove.md index 8dc301d3b..6c4530ce1 100644 --- a/docs/helm/helm_plugin_remove.md +++ b/docs/helm/helm_plugin_remove.md @@ -15,7 +15,7 @@ helm plugin remove ... ``` --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 @@ -25,4 +25,4 @@ helm plugin remove ... ### SEE ALSO * [helm plugin](helm_plugin.md) - add, list, or remove Helm plugins -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_plugin_update.md b/docs/helm/helm_plugin_update.md index 5d786b01c..cbfe9ad5e 100644 --- a/docs/helm/helm_plugin_update.md +++ b/docs/helm/helm_plugin_update.md @@ -15,7 +15,7 @@ helm plugin 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 @@ -25,4 +25,4 @@ helm plugin update ... ### SEE ALSO * [helm plugin](helm_plugin.md) - add, list, or remove Helm plugins -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_repo.md b/docs/helm/helm_repo.md index 2a2d67cec..3f184e875 100644 --- a/docs/helm/helm_repo.md +++ b/docs/helm/helm_repo.md @@ -17,7 +17,7 @@ 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 @@ -32,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 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_repo_add.md b/docs/helm/helm_repo_add.md index 5f8247fba..c16797c63 100644 --- a/docs/helm/helm_repo_add.md +++ b/docs/helm/helm_repo_add.md @@ -24,7 +24,7 @@ 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 @@ -34,4 +34,4 @@ helm repo add [flags] [NAME] [URL] ### SEE ALSO * [helm repo](helm_repo.md) - add, list, remove, update, and index chart repositories -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_repo_index.md b/docs/helm/helm_repo_index.md index a9f407a02..aece31367 100644 --- a/docs/helm/helm_repo_index.md +++ b/docs/helm/helm_repo_index.md @@ -31,7 +31,7 @@ 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 @@ -41,4 +41,4 @@ helm repo index [flags] [DIR] ### SEE ALSO * [helm repo](helm_repo.md) - add, list, remove, update, and index chart repositories -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_repo_list.md b/docs/helm/helm_repo_list.md index ee156ea66..484ce3c68 100644 --- a/docs/helm/helm_repo_list.md +++ b/docs/helm/helm_repo_list.md @@ -15,7 +15,7 @@ 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 @@ -25,4 +25,4 @@ helm repo list [flags] ### SEE ALSO * [helm repo](helm_repo.md) - add, list, remove, update, and index chart repositories -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_repo_remove.md b/docs/helm/helm_repo_remove.md index 4620b30d0..b34cee61c 100644 --- a/docs/helm/helm_repo_remove.md +++ b/docs/helm/helm_repo_remove.md @@ -15,7 +15,7 @@ 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 @@ -25,4 +25,4 @@ helm repo remove [flags] [NAME] ### SEE ALSO * [helm repo](helm_repo.md) - add, list, remove, update, and index chart repositories -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_repo_update.md b/docs/helm/helm_repo_update.md index 85399bf17..0c9fb6efd 100644 --- a/docs/helm/helm_repo_update.md +++ b/docs/helm/helm_repo_update.md @@ -21,7 +21,7 @@ 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 @@ -31,4 +31,4 @@ helm repo update ### SEE ALSO * [helm repo](helm_repo.md) - add, list, remove, update, and index chart repositories -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_reset.md b/docs/helm/helm_reset.md index 122d49cf3..dfb78c376 100644 --- a/docs/helm/helm_reset.md +++ b/docs/helm/helm_reset.md @@ -31,7 +31,7 @@ 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 @@ -41,4 +41,4 @@ helm reset ### SEE ALSO * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_rollback.md b/docs/helm/helm_rollback.md index 8a6a0f558..a2fedc559 100644 --- a/docs/helm/helm_rollback.md +++ b/docs/helm/helm_rollback.md @@ -37,7 +37,7 @@ 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 @@ -47,4 +47,4 @@ helm rollback [flags] [RELEASE] [REVISION] ### SEE ALSO * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_search.md b/docs/helm/helm_search.md index e81aa515f..1dc7e38ba 100644 --- a/docs/helm/helm_search.md +++ b/docs/helm/helm_search.md @@ -28,7 +28,7 @@ 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 @@ -38,4 +38,4 @@ helm search [keyword] ### SEE ALSO * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_serve.md b/docs/helm/helm_serve.md index 73e8467ff..4ce8a997a 100644 --- a/docs/helm/helm_serve.md +++ b/docs/helm/helm_serve.md @@ -36,7 +36,7 @@ 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 @@ -46,4 +46,4 @@ helm serve ### SEE ALSO * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_status.md b/docs/helm/helm_status.md index 38c78d296..2331558c0 100644 --- a/docs/helm/helm_status.md +++ b/docs/helm/helm_status.md @@ -35,7 +35,7 @@ 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 @@ -45,4 +45,4 @@ helm status [flags] RELEASE_NAME ### SEE ALSO * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_template.md b/docs/helm/helm_template.md index 0a66145ac..46c4f9ca1 100644 --- a/docs/helm/helm_template.md +++ b/docs/helm/helm_template.md @@ -39,7 +39,7 @@ 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 @@ -49,4 +49,4 @@ helm template [flags] CHART ### SEE ALSO * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_test.md b/docs/helm/helm_test.md index c95c12a15..b46d43e64 100644 --- a/docs/helm/helm_test.md +++ b/docs/helm/helm_test.md @@ -32,7 +32,7 @@ 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 @@ -42,4 +42,4 @@ helm test [RELEASE] ### SEE ALSO * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_upgrade.md b/docs/helm/helm_upgrade.md index fe3eef6ef..5f4fde96c 100644 --- a/docs/helm/helm_upgrade.md +++ b/docs/helm/helm_upgrade.md @@ -67,7 +67,7 @@ helm upgrade [RELEASE] [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 @@ -77,4 +77,4 @@ helm upgrade [RELEASE] [CHART] ### SEE ALSO * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_verify.md b/docs/helm/helm_verify.md index 4153c1235..74c3ee488 100644 --- a/docs/helm/helm_verify.md +++ b/docs/helm/helm_verify.md @@ -30,7 +30,7 @@ helm verify [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 @@ -40,4 +40,4 @@ helm verify [flags] PATH ### SEE ALSO * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 diff --git a/docs/helm/helm_version.md b/docs/helm/helm_version.md index 74fe86d9f..1e46ceb18 100644 --- a/docs/helm/helm_version.md +++ b/docs/helm/helm_version.md @@ -44,7 +44,7 @@ helm version ``` --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 @@ -54,4 +54,4 @@ helm version ### SEE ALSO * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 1-Nov-2017 +###### Auto generated by spf13/cobra on 7-Nov-2017 From 85ed9f3d4b876ea7c91024c7f03789830d4508a9 Mon Sep 17 00:00:00 2001 From: Franz Beltran <32735684+franzbeltran@users.noreply.github.com> Date: Thu, 9 Nov 2017 10:35:24 +0800 Subject: [PATCH 067/107] Update best practices on imagePullPolicy Setting the value of `imagePullPolicy` should be aligned to what `helm create` does --- docs/chart_best_practices/pods.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/docs/chart_best_practices/pods.md b/docs/chart_best_practices/pods.md index de679f9f5..3f26b0253 100644 --- a/docs/chart_best_practices/pods.md +++ b/docs/chart_best_practices/pods.md @@ -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: From c864ba179ee97ac111529fa8e6285e0a3e40760c Mon Sep 17 00:00:00 2001 From: Maxime Guyot Date: Fri, 10 Nov 2017 10:52:56 +0100 Subject: [PATCH 068/107] Add fullnameOverride --- pkg/chartutil/create.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/chartutil/create.go b/pkg/chartutil/create.go index 5fb3834ef..ba43dec9b 100644 --- a/pkg/chartutil/create.go +++ b/pkg/chartutil/create.go @@ -240,7 +240,8 @@ We truncate at 63 chars because some Kubernetes name fields are limited to this */}} {{- define ".fullname" -}} {{- $name := default .Chart.Name .Values.nameOverride -}} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- $default := printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- default $default .Values.fullnameOverride -}} {{- end -}} ` From e6d907ed285ff9e7a6527bc4efaad9be11d95a93 Mon Sep 17 00:00:00 2001 From: Federico Gimenez Date: Sun, 12 Nov 2017 11:20:52 +0100 Subject: [PATCH 069/107] check if resource is present before adding it to remaining or keep on deletion --- pkg/kube/client.go | 7 ++++++- pkg/tiller/release_modules.go | 2 +- pkg/tiller/resource_policy.go | 11 ++++++++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/pkg/kube/client.go b/pkg/kube/client.go index 798434da4..f117d7ee9 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -53,6 +53,11 @@ import ( "k8s.io/kubernetes/pkg/printers" ) +const ( + // MissingGetHeader is added to Get's outout when a resource is not found. + MissingGetHeader = "==> MISSING\nKIND\t\tNAME\n" +) + // ErrNoObjectsVisited indicates that during a visit operation, no matching objects were found. var ErrNoObjectsVisited = goerrors.New("no objects visited") @@ -217,7 +222,7 @@ func (c *Client) Get(namespace string, reader io.Reader) (string, error) { } } if len(missing) > 0 { - buf.WriteString("==> MISSING\nKIND\t\tNAME\n") + buf.WriteString(MissingGetHeader) for _, s := range missing { fmt.Fprintln(buf, s) } diff --git a/pkg/tiller/release_modules.go b/pkg/tiller/release_modules.go index b5fbbeb44..57b8c4fee 100644 --- a/pkg/tiller/release_modules.go +++ b/pkg/tiller/release_modules.go @@ -159,7 +159,7 @@ func DeleteRelease(rel *release.Release, vs chartutil.VersionSet, kubeClient env return rel.Manifest, []error{fmt.Errorf("corrupted release record. You must manually delete the resources: %s", err)} } - filesToKeep, filesToDelete := filterManifestsToKeep(files) + filesToKeep, filesToDelete := filterManifestsToKeep(files, kubeClient, rel.Namespace) if len(filesToKeep) > 0 { kept = summarizeKeptManifests(filesToKeep) } diff --git a/pkg/tiller/resource_policy.go b/pkg/tiller/resource_policy.go index 2102ab66b..e4e08d435 100644 --- a/pkg/tiller/resource_policy.go +++ b/pkg/tiller/resource_policy.go @@ -17,7 +17,11 @@ limitations under the License. package tiller import ( + "bytes" "strings" + + "k8s.io/helm/pkg/kube" + "k8s.io/helm/pkg/tiller/environment" ) // resourcePolicyAnno is the annotation name for a resource policy @@ -29,11 +33,16 @@ const resourcePolicyAnno = "helm.sh/resource-policy" // during an uninstallRelease action. const keepPolicy = "keep" -func filterManifestsToKeep(manifests []Manifest) ([]Manifest, []Manifest) { +func filterManifestsToKeep(manifests []Manifest, kubeClient environment.KubeClient, namespace string) ([]Manifest, []Manifest) { remaining := []Manifest{} keep := []Manifest{} for _, m := range manifests { + // check if m is in fact present from k8s client's POV. + output, err := kubeClient.Get(namespace, bytes.NewBufferString(m.Content)) + if err != nil || strings.Contains(output, kube.MissingGetHeader) { + continue + } if m.Head.Metadata == nil || m.Head.Metadata.Annotations == nil || len(m.Head.Metadata.Annotations) == 0 { remaining = append(remaining, m) From cf6f139ee839ce63fada6e07d052f94601f44359 Mon Sep 17 00:00:00 2001 From: Stephen McQuaid Date: Tue, 14 Nov 2017 15:07:23 -0800 Subject: [PATCH 070/107] Update related.md with new helm plugin Add helm-github plugin to list in documentation --- docs/related.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/related.md b/docs/related.md index 59177d65d..1f9ec68c1 100644 --- a/docs/related.md +++ b/docs/related.md @@ -37,6 +37,7 @@ or [pull request](https://github.com/kubernetes/helm/pulls). - [helm-secrets](https://github.com/futuresimple/helm-secrets) - Plugin to manage and store secrets safely - [helm-edit](https://github.com/mstrzele/helm-edit) - Plugin for editing release's values - [helm-gcs](https://github.com/nouney/helm-gcs) - Plugin to manage repositories on Google Cloud Storage +- [helm-github](https://github.com/sagansystems/helm-github) - Plugin to install Helm Charts from Github repositories We also encourage GitHub authors to use the [helm-plugin](https://github.com/search?q=topic%3Ahelm-plugin&type=Repositories) tag on their plugin repositories. From 7e0e27726df8b7b7023f78f1ed593a58bc15377a Mon Sep 17 00:00:00 2001 From: Denis Mikhaylov Date: Wed, 15 Nov 2017 10:48:29 +0300 Subject: [PATCH 071/107] Fix incorrect line --- docs/charts_tips_and_tricks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/charts_tips_and_tricks.md b/docs/charts_tips_and_tricks.md index f1faca100..0b74af1e5 100644 --- a/docs/charts_tips_and_tricks.md +++ b/docs/charts_tips_and_tricks.md @@ -143,7 +143,7 @@ spec: template: metadata: annotations: - checksum/config: {{ .Files.Get "path/to/config" | sha256sum }} + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} [...] ``` From e8e6ac5d7783808cc0bd1adad053bec339849647 Mon Sep 17 00:00:00 2001 From: Matt Butcher Date: Wed, 15 Nov 2017 17:52:24 -0700 Subject: [PATCH 072/107] Fix/missing ssl params (#3152) * fix(helm): add TLS params back During a recent refactor, several TLS flags stopped being processed for a few of the commands. This fixes those commands, and documents how to set up TLS. * fix(tiller): add stricter certificate verification The older version of Tiller allowed a weaker set of certificate checks than we intended. This version requires a client certificate, and then requires that that certificate be signed by a known CA. This works around the situation where a user could provide a self-signed certificate. --- cmd/helm/get.go | 8 +- cmd/helm/helm.go | 20 ++- cmd/helm/history.go | 2 +- cmd/helm/list.go | 2 +- cmd/helm/status.go | 2 +- cmd/tiller/tiller.go | 6 +- docs/helm/helm_get_hooks.md | 9 +- docs/helm/helm_get_manifest.md | 9 +- docs/helm/helm_get_values.md | 11 +- docs/index.md | 2 + docs/tiller_ssl.md | 291 +++++++++++++++++++++++++++++++++ pkg/tlsutil/tls.go | 2 +- 12 files changed, 342 insertions(+), 22 deletions(-) create mode 100644 docs/tiller_ssl.md diff --git a/cmd/helm/get.go b/cmd/helm/get.go index fc5871f46..477f730d5 100644 --- a/cmd/helm/get.go +++ b/cmd/helm/get.go @@ -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 } diff --git a/cmd/helm/helm.go b/cmd/helm/helm.go index 6412057b8..b262e577b 100644 --- a/cmd/helm/helm.go +++ b/cmd/helm/helm.go @@ -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 ) @@ -263,6 +267,16 @@ func newClient() helm.Interface { options := []helm.Option{helm.Host(settings.TillerHost)} if tlsVerify || tlsEnable { + if tlsCaCertFile == "" { + tlsCaCertFile = os.ExpandEnv(tlsCaCertDefault) + } + if tlsCertFile == "" { + tlsCertFile = os.ExpandEnv(tlsCertDefault) + } + if tlsKeyFile == "" { + tlsKeyFile = os.ExpandEnv(tlsKeyDefault) + } + 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") diff --git a/cmd/helm/history.go b/cmd/helm/history.go index 08f1656f5..27c47ad3e 100644 --- a/cmd/helm/history.go +++ b/cmd/helm/history.go @@ -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() diff --git a/cmd/helm/list.go b/cmd/helm/list.go index f6cdaacfe..7c312a365 100644 --- a/cmd/helm/list.go +++ b/cmd/helm/list.go @@ -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() }, diff --git a/cmd/helm/status.go b/cmd/helm/status.go index 36269c4b1..e5e9aa44c 100644 --- a/cmd/helm/status.go +++ b/cmd/helm/status.go @@ -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() }, diff --git a/cmd/tiller/tiller.go b/cmd/tiller/tiller.go index fadf8dd3a..f9ec0d4fc 100644 --- a/cmd/tiller/tiller.go +++ b/cmd/tiller/tiller.go @@ -232,7 +232,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 } diff --git a/docs/helm/helm_get_hooks.md b/docs/helm/helm_get_hooks.md index 3db1b8d55..a2fb36acd 100644 --- a/docs/helm/helm_get_hooks.md +++ b/docs/helm/helm_get_hooks.md @@ -18,7 +18,12 @@ helm get hooks [flags] RELEASE_NAME ### Options ``` - --revision int32 get the named release with revision + --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 @@ -35,4 +40,4 @@ helm get hooks [flags] RELEASE_NAME ### SEE ALSO * [helm get](helm_get.md) - download a named release -###### Auto generated by spf13/cobra on 7-Nov-2017 +###### Auto generated by spf13/cobra on 15-Nov-2017 diff --git a/docs/helm/helm_get_manifest.md b/docs/helm/helm_get_manifest.md index 11597716d..1cf712d9b 100644 --- a/docs/helm/helm_get_manifest.md +++ b/docs/helm/helm_get_manifest.md @@ -20,7 +20,12 @@ helm get manifest [flags] RELEASE_NAME ### Options ``` - --revision int32 get the named release with revision + --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 @@ -37,4 +42,4 @@ helm get manifest [flags] RELEASE_NAME ### SEE ALSO * [helm get](helm_get.md) - download a named release -###### Auto generated by spf13/cobra on 7-Nov-2017 +###### Auto generated by spf13/cobra on 15-Nov-2017 diff --git a/docs/helm/helm_get_values.md b/docs/helm/helm_get_values.md index fe23e6819..1e57a2303 100644 --- a/docs/helm/helm_get_values.md +++ b/docs/helm/helm_get_values.md @@ -16,8 +16,13 @@ helm get values [flags] RELEASE_NAME ### Options ``` - -a, --all dump all (computed) values - --revision int32 get the named release with revision + -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 @@ -34,4 +39,4 @@ helm get values [flags] RELEASE_NAME ### SEE ALSO * [helm get](helm_get.md) - download a named release -###### Auto generated by spf13/cobra on 7-Nov-2017 +###### Auto generated by spf13/cobra on 15-Nov-2017 diff --git a/docs/index.md b/docs/index.md index b787463a6..a8e4ac483 100644 --- a/docs/index.md +++ b/docs/index.md @@ -6,6 +6,8 @@ - [Frequently Asked Questions](install_faq.md) - [Using Helm](using_helm.md) - Learn the Helm tools - [Plugins](plugins.md) + - [Service Accounts for Tiller](service_accounts.md) - Apply RBACs to Tiller + - [TLS/SSL for Helm and Tiller](tiller_ssl.md) - Use Helm-to-Tiller encryption - [Developing Charts](charts.md) - An introduction to chart development - [Chart Lifecycle Hooks](charts_hooks.md) - [Chart Tips and Tricks](charts_tips_and_tricks.md) diff --git a/docs/tiller_ssl.md b/docs/tiller_ssl.md new file mode 100644 index 000000000..59d653e26 --- /dev/null +++ b/docs/tiller_ssl.md @@ -0,0 +1,291 @@ +# Using SSL Between Helm and Tiller + +This document explains how to create strong SSL/TLS connections between Helm and +Tiller. The emphasis here is on creating an internal CA, and using both the +cryptographic and identity functions of SSL. + +> Support for TLS-based auth was introduced in Helm 2.3.0 + +Configuring SSL is considered an advanced topic, and knowledge of Helm and Tiller +is assumed. + +## Overview + +The Tiller authentication model uses client-side SSL certificates. Tiller itself +verifies these certificates using a certificate authority. Likewise, the client +also verifies Tiller's identity by certificate authority. + +There are numerous possible configurations for setting up certificates and authorities, +but the method we cover here will work for most situations. + +> As of Helm 2.7.2, Tiller _requires_ that the client certificate be validated +> by its CA. In prior versions, Tiller used a weaker validation strategy that +> allowed self-signed certificates. + +In this guide, we will show how to: + +- Create a private CA that is used to issue certificates for Tiller clients and + servers. +- Create a certificate for Tiller +- Create a certificate for the Helm client +- Create a Tiller instance that uses the certificate +- Configure the Helm client to use the CA and client-side certificate + +By the end of this guide, you should have a Tiller instance running that will +only accept connections from clients who can be authenticated by SSL certificate. + +## Generating Certificate Authorities and Certificates + +One way to generate SSL CAs is via the `openssl` command line tool. There are many +guides and best practices documents available online. This explanation is focused +on getting ready within a small amount of time. For production configurations, +we urge readers to read [the official documentation](https://www.openssl.org) and +consult other resources. + +### Generate a Certificate Authority + +The simplest way to generate a certificate authority is to run two commands: + +```console +$ openssl genrsa -out ./ca.key.pem 4096 +$ openssl req -key ca.key.pem -new -x509 -days 7300 -sha256 -out ca.cert.pem -extensions v3_ca +Enter pass phrase for ca.key.pem: +You are about to be asked to enter information that will be incorporated +into your certificate request. +What you are about to enter is what is called a Distinguished Name or a DN. +There are quite a few fields but you can leave some blank +For some fields there will be a default value, +If you enter '.', the field will be left blank. +----- +Country Name (2 letter code) [AU]:US +State or Province Name (full name) [Some-State]:CO +Locality Name (eg, city) []:Boulder +Organization Name (eg, company) [Internet Widgits Pty Ltd]:tiller +Organizational Unit Name (eg, section) []: +Common Name (e.g. server FQDN or YOUR name) []:tiller +Email Address []:tiller@example.com +``` + +Note that the data input above is _sample data_. You should customize to your own +specifications. + +The above will generate both a secret key and a CA. Note that these two files are +very important. The key in particular should be handled with particular care. + +Often, you will want to generate an intermediate signing key. For the sake of brevity, +we will be signing keys with our root CA. + +### Generating Certificates + +We will be generating two certificates, each representing a type of certificate: + +- One certificate is for Tiller. You will want one of these _per tiller host_ that + you run. +- One certificate is for the user. You will want one of these _per helm user_. + +Since the commands to generate these are the same, we'll be creating both at the +same time. The names will indicate their target. + +First, the Tiller key: + +```console +$ openssl genrsa -out ./tiller.key.pem 4096 +Generating RSA private key, 4096 bit long modulus +..........................................................................................................................................................................................................................................................................................................................++ +............................................................................++ +e is 65537 (0x10001) +Enter pass phrase for ./tiller.key.pem: +Verifying - Enter pass phrase for ./tiller.key.pem: +``` + +Next, generate the Helm client's key: + +```console +$ openssl genrsa -out ./helm.key.pem 4096 +Generating RSA private key, 4096 bit long modulus +.....++ +......................................................................................................................................................................................++ +e is 65537 (0x10001) +Enter pass phrase for ./helm.key.pem: +Verifying - Enter pass phrase for ./helm.key.pem: +``` + +Again, for production use you will generate one client certificate for each user. + +Next we need to create certificates from these keys. For each certificate, this is +a two-step process of creating a CSR, and then creating the certificate. + +```console +$ openssl req -key tiller.key.pem -new -sha256 -out tiller.csr.pem +Enter pass phrase for tiller.key.pem: +You are about to be asked to enter information that will be incorporated +into your certificate request. +What you are about to enter is what is called a Distinguished Name or a DN. +There are quite a few fields but you can leave some blank +For some fields there will be a default value, +If you enter '.', the field will be left blank. +----- +Country Name (2 letter code) [AU]:US +State or Province Name (full name) [Some-State]:CO +Locality Name (eg, city) []:Boulder +Organization Name (eg, company) [Internet Widgits Pty Ltd]:Tiller Server +Organizational Unit Name (eg, section) []: +Common Name (e.g. server FQDN or YOUR name) []:tiller-server +Email Address []: + +Please enter the following 'extra' attributes +to be sent with your certificate request +A challenge password []: +An optional company name []: +``` + +And we repeat this step for the Helm client certificate: + +```console +$ openssl req -key helm.key.pem -new -sha256 -out helm.csr.pem +# Answer the questions with your client user's info +``` + +(In rare cases, we've had to add the `-nodes` flag when generating the request.) + +Now we sign each of these CSRs with the CA certificate we created: + +```console +$ openssl x509 -req -CA ca.cert.pem -CAkey ca.key.pem -CAcreateserial -in tiller.csr.pem -out tiller.cert.pem +Signature ok +subject=/C=US/ST=CO/L=Boulder/O=Tiller Server/CN=tiller-server +Getting CA Private Key +Enter pass phrase for ca.key.pem: +``` + +And again for the client certificate: + +```console +$ openssl x509 -req -CA ca.cert.pem -CAkey ca.key.pem -CAcreateserial -in helm.csr.pem -out helm.cert.pem +``` + +At this point, the important files for us are these: + +``` +# The CA. Make sure the key is kept secret. +ca.cert.pem +ca.key.pem +# The Helm client files +helm.cert.pem +helm.key.pem +# The Tiller server files. +tiller.cert.pem +tiller.key.pem +``` + +Now we're ready to move on to the next steps. + +## Creating a Custom Tiller Installation + +Helm includes full support for creating a deployment configured for SSL. By specifying +a few flags, the `helm init` command can create a new Tiller installation complete +with all of our SSL configuration. + +To take a look at what this will generate, run this command: + +```console +$ helm init --dry-run --debug --tiller-tls --tiller-tls-cert ./tiller.cert.pem --tiller-tls-key ./tiller.key.pem --tiller-tls-verify --tls-ca-cert ca.cert.pem +``` + +The output will show you a Deployment, a Secret, and a Service. Your SSL information +will be preloaded into the Secret, which the Deployment will mount to pods as they +start up. + +If you want to customize the manifest, you can save that output to a file and then +use `kubectl create` to load it into your cluster. + +> We strongly recommend enabling RBAC on your cluster and adding [service accounts](service_accounts.md) +> with RBACS. + +Otherwise, you can remove the `--dry-run` and `--debug` flags. We also recommend +putting Tiller in a non-system namespace (`--tiller-namespace=something`) and enable +a service account (`--service-account=somename`). But for this example we will stay +with the basics: + +```console +$ helm init --tiller-tls --tiller-tls-cert ./tiller.cert.pem --tiller-tls-key ./tiller.key.pem --tiller-tls-verify --tls-ca-cert ca.cert.pem +``` + +In a minute or two it should be ready. We can check Tiller like this: + +```console +$ kubectl -n kube-system get deployment +NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE +... other stuff +tiller-deploy 1 1 1 1 2m +``` + +If there is a problem, you may want to use `kubectl get pods -n kube-system` to +find out what went wrong. With the SSL/TLS support, the most common problems all +have to do with improperly generated TLS certificates or accidentally swapping the +cert and the key. + +At this point, you should get a _failure_ when you run basic Helm commands: + +```console +$ helm ls +Error: transport is closing +``` + +This is because your Helm client does not have the correct certificate to authenticate +to Tiller. + +## Configuring the Helm Client + +The Tiller server is now running with TLS protection. It's time to configure the +Helm client to also perform TLS operations. + +For a quick test, we can specify our configuration manually. We'll run a normal +Helm command (`helm ls`), but with SSL/TLS enabled. + +```console +helm ls --tls --tls-ca-cert ca.cert.pem --tls-cert helm.cert.pem --tls-key helm.key.pem +``` + +This configuration sends our client-side certificate to establish identity, uses +the client key for encryption, and uses the CA certificate to validate the remote +Tiller's identity. + +Typing a line that that is cumbersome, though. The shortcut is to move the key, +cert, and CA into `$HELM_HOME`: + +```console +$ cp ca.cert.pem $(helm home)/ca.pem +$ cp helm.cert.pem $(helm home)/cert.pem +$ cp helm.key.pem $(helm home)/key.pem +``` + +With this, you can simply run `helm ls --tls` to enable TLS. + +### Troubleshooting + +*Running a command, I get `Error: transport is closing`* + +This is almost always due to a configuration error in which the client is missing +a certificate (`--tls-cert`) or the certificate is bad. + +*I'm using a certificate, but get `Error: remote error: tls: bad certificate`* + +This means that Tiller's CA cannot verify your certificate. In the examples above, +we used a single CA to generate both the client and server certificates. In these +examples, the CA has _signed_ the client's certificate. We then load that CA +up to Tiller. So when the client certificate is sent to the server, Tiller +checks the client certificate against the CA. + +*If I use `--tls-verify` on the client, I get `Error: x509: certificate is valid for tiller-server, not localhost`* + +If you plan to use `--tls-verify` on the client, you will need to make sure that +the host name that Helm connects to matches the host name on the certificate. In +some cases this is awkward, since Helm will connect over localhost, or the FQDN is +not available for public resolution. + +## References + +https://github.com/denji/golang-tls +https://www.openssl.org/docs/ +https://jamielinux.com/docs/openssl-certificate-authority/sign-server-and-client-certificates.html diff --git a/pkg/tlsutil/tls.go b/pkg/tlsutil/tls.go index 422bddacb..df698fd4e 100644 --- a/pkg/tlsutil/tls.go +++ b/pkg/tlsutil/tls.go @@ -65,7 +65,7 @@ func CertPoolFromFile(filename string) (*x509.CertPool, error) { func CertFromFilePair(certFile, keyFile string) (*tls.Certificate, error) { cert, err := tls.LoadX509KeyPair(certFile, keyFile) if err != nil { - return nil, fmt.Errorf("can't load key pair from cert %s and key %s", certFile, keyFile) + return nil, fmt.Errorf("can't load key pair from cert %s and key %s: %s", certFile, keyFile, err) } return &cert, err } From de0859327647cb22fe42d4d6b81970f602c05f6f Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Wed, 15 Nov 2017 17:16:09 -0800 Subject: [PATCH 073/107] bump version to v2.7.2 --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 022afd79e..d1787ef1e 100644 --- a/README.md +++ b/README.md @@ -34,10 +34,10 @@ Think of it like apt/yum/homebrew for Kubernetes. Binary downloads of the Helm client can be found at the following links: -- [OSX](https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-darwin-amd64.tar.gz) -- [Linux](https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-linux-amd64.tar.gz) -- [Linux 32-bit](https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-linux-386.tar.gz) -- [Windows](https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-windows-amd64.tar.gz) +- [OSX](https://kubernetes-helm.storage.googleapis.com/helm-v2.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`. From 06454330484e10cb4c5aa1f61a67894403db3354 Mon Sep 17 00:00:00 2001 From: Tim H Date: Mon, 20 Nov 2017 12:15:20 +0100 Subject: [PATCH 074/107] Increase script portability Instead of presuming that bash is installed at /bin/bash, use `$PATH`. Official [bash docker container](https://hub.docker.com/_/bash/) installs bash at `/usr/local/bin` and recommends the use of `env` --- scripts/get | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/get b/scripts/get index 88a6fa1a7..d900ab2c2 100755 --- a/scripts/get +++ b/scripts/get @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Copyright 2016 The Kubernetes Authors All rights reserved. # From 5884124294c43396d97e9d6e291320327a28e762 Mon Sep 17 00:00:00 2001 From: Michelle Noorali Date: Mon, 20 Nov 2017 10:01:15 -0500 Subject: [PATCH 075/107] ref(docs): update plugin install documentation --- cmd/helm/plugin_install.go | 8 ++++++++ docs/helm/helm_plugin_install.md | 9 +++++++-- docs/plugins.md | 5 ++--- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/cmd/helm/plugin_install.go b/cmd/helm/plugin_install.go index aa75770fc..f36178808 100644 --- a/cmd/helm/plugin_install.go +++ b/cmd/helm/plugin_install.go @@ -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] ...", Short: "install one or more Helm plugins", + Long: pluginInstallDesc, PreRunE: func(cmd *cobra.Command, args []string) error { return pcmd.complete(args) }, diff --git a/docs/helm/helm_plugin_install.md b/docs/helm/helm_plugin_install.md index 1b1e03ea7..f93378b7b 100644 --- a/docs/helm/helm_plugin_install.md +++ b/docs/helm/helm_plugin_install.md @@ -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] ... @@ -31,4 +36,4 @@ helm plugin install [options] ... ### SEE ALSO * [helm plugin](helm_plugin.md) - add, list, or remove Helm plugins -###### Auto generated by spf13/cobra on 7-Nov-2017 +###### Auto generated by spf13/cobra on 20-Nov-2017 diff --git a/docs/plugins.md b/docs/plugins.md index 1bee8bd56..5d7e4f622 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -31,11 +31,10 @@ plugins do the "detail work" of performing a desired action. ## Installing a Plugin -A Helm plugin management system is in the works. But in the short term, plugins -are installed by copying the plugin directory into `$(helm home)/plugins`. +Plugins are installed using the `$ helm plugin install command. You can pass in a path to a plugin on your local file system or a url of a remote VCS repo. The `helm plugin install` command clones or copies the plugin at the path/url given into `$ (helm home)/plugins` ```console -$ cp -a myplugin/ $(helm home)/plugins/ +$ helm plugin install https://github.com/technosophos/helm-template ``` If you have a plugin tar distribution, simply untar the plugin into the From 275fbd431c09b42f6dc232e5e826fbd881a7148b Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Mon, 20 Nov 2017 13:05:03 -0500 Subject: [PATCH 076/107] feat(http): Add a Helm user-agent string to the http getter Adding a user-agent to the http getter will enable servers to distinguish between helm (including various versions) and other tools connecting to the server. --- pkg/getter/httpgetter.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/pkg/getter/httpgetter.go b/pkg/getter/httpgetter.go index 9afa31f60..5a2146ec6 100644 --- a/pkg/getter/httpgetter.go +++ b/pkg/getter/httpgetter.go @@ -20,9 +20,11 @@ import ( "fmt" "io" "net/http" + "strings" "k8s.io/helm/pkg/tlsutil" "k8s.io/helm/pkg/urlutil" + "k8s.io/helm/pkg/version" ) //httpGetter is the efault HTTP(/S) backend handler @@ -34,7 +36,15 @@ type httpGetter struct { func (g *httpGetter) Get(href string) (*bytes.Buffer, error) { buf := bytes.NewBuffer(nil) - resp, err := g.client.Get(href) + // Set a helm specific user agent so that a repo server and metrics can + // separate helm calls from other tools interacting with repos. + req, err := http.NewRequest("GET", href, nil) + if err != nil { + return buf, err + } + req.Header.Set("User-Agent", "Helm/"+strings.TrimPrefix(version.GetVersion(), "v")) + + resp, err := g.client.Do(req) if err != nil { return buf, err } From bc45e90198885d4d6eb6ba719239c538533155e8 Mon Sep 17 00:00:00 2001 From: Kai Chen Date: Tue, 21 Nov 2017 10:30:01 -0800 Subject: [PATCH 077/107] Remove unnecessary parentheses in switch statements (#3175) --- pkg/kube/wait.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pkg/kube/wait.go b/pkg/kube/wait.go index 63e7c4a65..abab31661 100644 --- a/pkg/kube/wait.go +++ b/pkg/kube/wait.go @@ -60,19 +60,19 @@ func (c *Client) waitForResources(timeout time.Duration, created Result) error { return false, err } switch value := obj.(type) { - case (*v1.ReplicationController): + case *v1.ReplicationController: list, err := getPods(kcs, value.Namespace, value.Spec.Selector) if err != nil { return false, err } pods = append(pods, list...) - case (*v1.Pod): + case *v1.Pod: pod, err := kcs.Core().Pods(value.Namespace).Get(value.Name, metav1.GetOptions{}) if err != nil { return false, err } pods = append(pods, *pod) - case (*extensions.Deployment): + case *extensions.Deployment: currentDeployment, err := kcs.Extensions().Deployments(value.Namespace).Get(value.Name, metav1.GetOptions{}) if err != nil { return false, err @@ -87,37 +87,37 @@ func (c *Client) waitForResources(timeout time.Duration, created Result) error { currentDeployment, } deployments = append(deployments, newDeployment) - case (*extensions.DaemonSet): + case *extensions.DaemonSet: list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) if err != nil { return false, err } pods = append(pods, list...) - case (*appsv1beta1.StatefulSet): + case *appsv1beta1.StatefulSet: list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) if err != nil { return false, err } pods = append(pods, list...) - case (*appsv1beta2.StatefulSet): + case *appsv1beta2.StatefulSet: list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) if err != nil { return false, err } pods = append(pods, list...) - case (*extensions.ReplicaSet): + case *extensions.ReplicaSet: list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) if err != nil { return false, err } pods = append(pods, list...) - case (*v1.PersistentVolumeClaim): + case *v1.PersistentVolumeClaim: claim, err := kcs.Core().PersistentVolumeClaims(value.Namespace).Get(value.Name, metav1.GetOptions{}) if err != nil { return false, err } pvc = append(pvc, *claim) - case (*v1.Service): + case *v1.Service: svc, err := kcs.Core().Services(value.Namespace).Get(value.Name, metav1.GetOptions{}) if err != nil { return false, err From 31ea2018fac8a8adc114354b9fb05118f4d21418 Mon Sep 17 00:00:00 2001 From: Sebastien Plisson Date: Tue, 21 Nov 2017 10:30:59 -0800 Subject: [PATCH 078/107] docs(helm): Document how to update a release idempotently (#3148) * docs(helm): Document how to update a release idempotently To use the same command when installing and upgrading a release, using helm upgrade with '--install' works. Closes #3134 * Upgrade instead of update --- docs/charts_tips_and_tricks.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/charts_tips_and_tricks.md b/docs/charts_tips_and_tricks.md index 0b74af1e5..b1df146db 100644 --- a/docs/charts_tips_and_tricks.md +++ b/docs/charts_tips_and_tricks.md @@ -231,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 --values +``` From fe3eeaf39d44a95aa9e7cff29647cd12ab60da5a Mon Sep 17 00:00:00 2001 From: Matt Cholick Date: Tue, 21 Nov 2017 10:34:02 -0800 Subject: [PATCH 079/107] fix(helm): Tunnel closing already closed channel (#3157) k8s client-go closes the ready channel that's passed in (see https://github.com/kubernetes/client-go/blob/master/tools/portforward/portforward.go#L171) This means that Tunnel's Close will always panic, as the client-go library will have closed then channel. This isn't reproducible unless helm.Client is externally, as the helm cli runner doesn't actually invoke Close. --- pkg/kube/tunnel.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/kube/tunnel.go b/pkg/kube/tunnel.go index 6da0c4594..08280f25d 100644 --- a/pkg/kube/tunnel.go +++ b/pkg/kube/tunnel.go @@ -59,7 +59,6 @@ func NewTunnel(client rest.Interface, config *rest.Config, namespace, podName st // Close disconnects a tunnel connection func (t *Tunnel) Close() { close(t.stopChan) - close(t.readyChan) } // ForwardPort opens a tunnel to a kubernetes pod From 7f13e13a716b192ecac104c0736227120f924dae Mon Sep 17 00:00:00 2001 From: Rajat Jindal Date: Tue, 21 Nov 2017 11:10:27 -0800 Subject: [PATCH 080/107] support output-dir when running 'helm template' (#3144) * support output-dir when running 'helm template' * add --output-dir to documentation * when writing to file, dont add additional document * trigger another ci build. make test-unit works for me * dont write blank files * return err instead of panic --- cmd/helm/template.go | 68 ++++++++++++++++++++++++++++++++++++++ docs/helm/helm_template.md | 3 +- 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/cmd/helm/template.go b/cmd/helm/template.go index 92f6ed738..3ca364cfb 100644 --- a/cmd/helm/template.go +++ b/cmd/helm/template.go @@ -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 to / +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 +} diff --git a/docs/helm/helm_template.md b/docs/helm/helm_template.md index 46c4f9ca1..983652dba 100644 --- a/docs/helm/helm_template.md +++ b/docs/helm/helm_template.md @@ -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 []) ``` @@ -49,4 +50,4 @@ helm template [flags] CHART ### SEE ALSO * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 7-Nov-2017 +###### Auto generated by spf13/cobra on 15-Nov-2017 From 79ccafde2b4bc26829054fbbef9ca0c99f6ecd61 Mon Sep 17 00:00:00 2001 From: Matt Butcher Date: Tue, 21 Nov 2017 12:53:32 -0700 Subject: [PATCH 081/107] docs(quickstart): add clarifications about RBAC, TLS (#3180) This puts pointers to RBAC and TLS docs in the quickstart guide. --- docs/quickstart.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/quickstart.md b/docs/quickstart.md index dcf266867..729a9c9e2 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -20,6 +20,9 @@ $ kubectl config current-context my-cluster ``` +If your cluster has Role-Based Access Control (RBAC) enabled, you may want +to [configure a service account and rules](service_account.md) before proceeding. + ## Install Helm Download a binary release of the Helm client. You can use tools like @@ -45,6 +48,10 @@ This will install Tiller into the Kubernetes cluster you saw with **TIP:** When you want to upgrade Tiller, just run `helm init --upgrade`. +By default, when Tiller is installed,it does not have authentication enabled. +To learn more about configuring strong TLS authentication for Tiller, consult +[the Tiller TLS guide](tiller_ssl.md). + ## Install an Example Chart To install a chart, you can run the `helm install` command. Helm has From 41415e5c42ac0ad40c59bcca8f0115910bc106e3 Mon Sep 17 00:00:00 2001 From: omkensey Date: Tue, 21 Nov 2017 23:05:55 -0500 Subject: [PATCH 082/107] RBAC best practices (#3184) Document chart best practices related to RBAC. Fixes #3098. --- docs/chart_best_practices/README.md | 1 + docs/chart_best_practices/rbac.md | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 docs/chart_best_practices/rbac.md diff --git a/docs/chart_best_practices/README.md b/docs/chart_best_practices/README.md index 22908871d..58cc65407 100644 --- a/docs/chart_best_practices/README.md +++ b/docs/chart_best_practices/README.md @@ -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. diff --git a/docs/chart_best_practices/rbac.md b/docs/chart_best_practices/rbac.md new file mode 100644 index 000000000..4b84b3d42 --- /dev/null +++ b/docs/chart_best_practices/rbac.md @@ -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.) From 06cc1ea3892b21be038d22b881dd93dd8c552808 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helgi=20=C3=9Eormar=20=C3=9Eorbj=C3=B6rnsson?= Date: Tue, 21 Nov 2017 20:06:55 -0800 Subject: [PATCH 083/107] Make build-cross TARGETS configurable (#3185) Lets us build a subset of the targets while still using build-cross To build for multiple linux archs: TARGETS="linux/amd64 linux/386" make clean build-cross dist APP=helm VERSION=v25.12.2 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 737be298c..a5bdf1b8f 100644 --- a/Makefile +++ b/Makefile @@ -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 From 09313ad26c38d905b7ff87921fa5754ade0152d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20H=C3=B6sler?= Date: Wed, 22 Nov 2017 12:51:06 +0100 Subject: [PATCH 084/107] fix(helm): resolve relative chart paths --- cmd/helm/install.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/cmd/helm/install.go b/cmd/helm/install.go index 1ed179d57..df9bf09fb 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -424,7 +424,22 @@ func locateChartPath(repoURL, name, version string, verify bool, keyring, if err != nil { return "", err } - name = chartURL + + parsedChartURL, err := url.Parse(chartURL) + if err != nil { + return "", err + } + + if parsedChartURL.IsAbs() { + name = chartURL + } else { + parsedRepoUrl, err := url.Parse(repoURL) + if err != nil { + return "", err + } + name = parsedRepoUrl.ResolveReference(parsedChartURL).String() + } + } if _, err := os.Stat(settings.Home.Archive()); os.IsNotExist(err) { From 57daa56b8156d35f9b6b0fc31baec429fab1b3ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20H=C3=B6sler?= Date: Wed, 22 Nov 2017 13:17:18 +0100 Subject: [PATCH 085/107] Update installDesc --- cmd/helm/install.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd/helm/install.go b/cmd/helm/install.go index df9bf09fb..bc44bd0e4 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -79,18 +79,19 @@ 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. -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 From b45293feb006013094213d6380cb881956a4672b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20H=C3=B6sler?= Date: Wed, 22 Nov 2017 13:27:00 +0100 Subject: [PATCH 086/107] fix: updated docs --- docs/helm/helm_install.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/helm/helm_install.md b/docs/helm/helm_install.md index bb66345f4..6ddb56cee 100644 --- a/docs/helm/helm_install.md +++ b/docs/helm/helm_install.md @@ -40,18 +40,19 @@ 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. -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 @@ -108,4 +109,4 @@ helm install [CHART] ### SEE ALSO * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 7-Nov-2017 +###### Auto generated by spf13/cobra on 22-Nov-2017 From 2106766ab81b6fb881809aa25a9e35999a6170f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20H=C3=B6sler?= Date: Wed, 22 Nov 2017 13:46:47 +0100 Subject: [PATCH 087/107] fix: rename variable due to linter warning --- cmd/helm/install.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/helm/install.go b/cmd/helm/install.go index bc44bd0e4..088d05106 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -434,11 +434,11 @@ func locateChartPath(repoURL, name, version string, verify bool, keyring, if parsedChartURL.IsAbs() { name = chartURL } else { - parsedRepoUrl, err := url.Parse(repoURL) + parsedRepoURL, err := url.Parse(repoURL) if err != nil { return "", err } - name = parsedRepoUrl.ResolveReference(parsedChartURL).String() + name = parsedRepoURL.ResolveReference(parsedChartURL).String() } } From 838d7808946b554865e0fc897e7db8e8dfd63bde Mon Sep 17 00:00:00 2001 From: Hadrien Chauvin Date: Wed, 22 Nov 2017 17:16:02 +0100 Subject: [PATCH 088/107] update google.golang.org/grpc to 1.7.2 (#3101) --- glide.lock | 15 ++++++++++++--- glide.yaml | 2 +- pkg/helm/option.go | 2 +- pkg/tiller/server.go | 2 +- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/glide.lock b/glide.lock index 11b56ad2d..10cd55076 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: 397d714c3a444071879981d3e6575931bd637166e845c6577eaea08ffde7e33d -updated: 2017-10-27T11:04:22.887120936-04:00 +hash: 3d0ff2a6cf119f719abbd2606da14a00073627972be81a6e68404ad92c2d4cd5 +updated: 2017-11-04T13:04:46.410949815+01:00 imports: - name: cloud.google.com/go version: 3b1ae45394a234c385be014e9a488f2bb6eef821 @@ -320,18 +320,27 @@ imports: - internal/remote_api - internal/urlfetch - urlfetch +- name: google.golang.org/genproto + version: 09f6ed296fc66555a25fe4ce95173148778dfa85 + subpackages: + - googleapis/rpc/status - name: google.golang.org/grpc - version: 8050b9cbc271307e5a716a9d782803d09b0d6f2d + version: 5ffe3083946d5603a0578721101dc8165b1d5b5f subpackages: + - balancer - codes + - connectivity - credentials + - grpclb/grpc_lb_v1/messages - grpclog - internal - keepalive - metadata - naming - peer + - resolver - stats + - status - tap - transport - name: gopkg.in/inf.v0 diff --git a/glide.yaml b/glide.yaml index a91094d22..ef29fe246 100644 --- a/glide.yaml +++ b/glide.yaml @@ -26,7 +26,7 @@ import: - ptypes/any - ptypes/timestamp - package: google.golang.org/grpc - version: 1.2.1 + version: 1.7.2 # 1.8.1 libs are hosed and need some manual intervention, so pinning to 1.8.0 for now # so others aren't getting errors when running `glide up` - package: k8s.io/kubernetes diff --git a/pkg/helm/option.go b/pkg/helm/option.go index 387247b86..4f6924db2 100644 --- a/pkg/helm/option.go +++ b/pkg/helm/option.go @@ -426,7 +426,7 @@ func WithMaxHistory(max int32) HistoryOption { // NewContext creates a versioned context. func NewContext() context.Context { md := metadata.Pairs("x-helm-api-client", version.GetVersion()) - return metadata.NewContext(context.TODO(), md) + return metadata.NewOutgoingContext(context.TODO(), md) } // ReleaseTestOption allows configuring optional request data for diff --git a/pkg/tiller/server.go b/pkg/tiller/server.go index 8d6b6fa13..57826578e 100644 --- a/pkg/tiller/server.go +++ b/pkg/tiller/server.go @@ -78,7 +78,7 @@ func splitMethod(fullMethod string) (string, string) { } func versionFromContext(ctx context.Context) string { - if md, ok := metadata.FromContext(ctx); ok { + if md, ok := metadata.FromIncomingContext(ctx); ok { if v, ok := md["x-helm-api-client"]; ok && len(v) > 0 { return v[0] } From d762a42168308d93a46be1d7bc37bc518eee496f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johnny=20Bergstr=C3=B6m?= Date: Wed, 22 Nov 2017 17:20:41 +0100 Subject: [PATCH 089/107] Fix helmignore for .* (#3114) When the first rule matching entry for top level dir will be empty string, the .* rule will match. Skip this entry as it's not needed for processing. --- pkg/chartutil/load.go | 5 +++++ pkg/chartutil/requirements_test.go | 6 ++++++ .../dependent-chart-helmignore/.helmignore | 2 ++ .../dependent-chart-helmignore/Chart.yaml | 17 +++++++++++++++++ .../charts/.ignore_me | 0 .../charts/_ignore_me | 1 + .../charts/alpine/Chart.yaml | 4 ++++ .../charts/alpine/README.md | 9 +++++++++ .../charts/alpine/charts/mast1/Chart.yaml | 4 ++++ .../charts/alpine/charts/mast1/values.yaml | 4 ++++ .../charts/alpine/charts/mast2-0.1.0.tgz | Bin 0 -> 325 bytes .../charts/alpine/templates/alpine-pod.yaml | 16 ++++++++++++++++ .../charts/alpine/values.yaml | 2 ++ .../templates/template.tpl | 1 + .../dependent-chart-helmignore/values.yaml | 6 ++++++ pkg/ignore/rules.go | 5 +++++ pkg/ignore/rules_test.go | 3 +++ pkg/ignore/testdata/.joonix | 0 18 files changed, 85 insertions(+) create mode 100644 pkg/chartutil/testdata/dependent-chart-helmignore/.helmignore create mode 100644 pkg/chartutil/testdata/dependent-chart-helmignore/Chart.yaml create mode 100644 pkg/chartutil/testdata/dependent-chart-helmignore/charts/.ignore_me create mode 100644 pkg/chartutil/testdata/dependent-chart-helmignore/charts/_ignore_me create mode 100644 pkg/chartutil/testdata/dependent-chart-helmignore/charts/alpine/Chart.yaml create mode 100644 pkg/chartutil/testdata/dependent-chart-helmignore/charts/alpine/README.md create mode 100644 pkg/chartutil/testdata/dependent-chart-helmignore/charts/alpine/charts/mast1/Chart.yaml create mode 100644 pkg/chartutil/testdata/dependent-chart-helmignore/charts/alpine/charts/mast1/values.yaml create mode 100644 pkg/chartutil/testdata/dependent-chart-helmignore/charts/alpine/charts/mast2-0.1.0.tgz create mode 100644 pkg/chartutil/testdata/dependent-chart-helmignore/charts/alpine/templates/alpine-pod.yaml create mode 100644 pkg/chartutil/testdata/dependent-chart-helmignore/charts/alpine/values.yaml create mode 100644 pkg/chartutil/testdata/dependent-chart-helmignore/templates/template.tpl create mode 100644 pkg/chartutil/testdata/dependent-chart-helmignore/values.yaml create mode 100644 pkg/ignore/testdata/.joonix diff --git a/pkg/chartutil/load.go b/pkg/chartutil/load.go index cf11ae2e4..f10c0eddd 100644 --- a/pkg/chartutil/load.go +++ b/pkg/chartutil/load.go @@ -245,6 +245,11 @@ func LoadDir(dir string) (*chart.Chart, error) { err = filepath.Walk(topdir, func(name string, fi os.FileInfo, err error) error { n := strings.TrimPrefix(name, topdir) + if n == "" { + // No need to process top level. Avoid bug with helmignore .* matching + // empty names. See issue 1779. + return nil + } // Normalize to / since it will also work on Windows n = filepath.ToSlash(n) diff --git a/pkg/chartutil/requirements_test.go b/pkg/chartutil/requirements_test.go index ef09bcd2e..1ddaa78a1 100644 --- a/pkg/chartutil/requirements_test.go +++ b/pkg/chartutil/requirements_test.go @@ -419,6 +419,12 @@ func TestDependentChartWithSubChartsAbsentInRequirements(t *testing.T) { } +func TestDependentChartWithSubChartsHelmignore(t *testing.T) { + if _, err := Load("testdata/dependent-chart-helmignore"); err != nil { + t.Fatalf("Failed to load testdata: %s", err) + } +} + func TestDependentChartsWithSubchartsAllSpecifiedInRequirements(t *testing.T) { c, err := Load("testdata/dependent-chart-with-all-in-requirements-yaml") if err != nil { diff --git a/pkg/chartutil/testdata/dependent-chart-helmignore/.helmignore b/pkg/chartutil/testdata/dependent-chart-helmignore/.helmignore new file mode 100644 index 000000000..8a71bc82e --- /dev/null +++ b/pkg/chartutil/testdata/dependent-chart-helmignore/.helmignore @@ -0,0 +1,2 @@ +ignore/ +.* diff --git a/pkg/chartutil/testdata/dependent-chart-helmignore/Chart.yaml b/pkg/chartutil/testdata/dependent-chart-helmignore/Chart.yaml new file mode 100644 index 000000000..7c071c27b --- /dev/null +++ b/pkg/chartutil/testdata/dependent-chart-helmignore/Chart.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +name: frobnitz +description: This is a frobnitz. +version: "1.2.3" +keywords: + - frobnitz + - sprocket + - dodad +maintainers: + - name: The Helm Team + email: helm@example.com + - name: Someone Else + email: nobody@example.com +sources: + - https://example.com/foo/bar +home: http://example.com +icon: https://example.com/64x64.png diff --git a/pkg/chartutil/testdata/dependent-chart-helmignore/charts/.ignore_me b/pkg/chartutil/testdata/dependent-chart-helmignore/charts/.ignore_me new file mode 100644 index 000000000..e69de29bb diff --git a/pkg/chartutil/testdata/dependent-chart-helmignore/charts/_ignore_me b/pkg/chartutil/testdata/dependent-chart-helmignore/charts/_ignore_me new file mode 100644 index 000000000..2cecca682 --- /dev/null +++ b/pkg/chartutil/testdata/dependent-chart-helmignore/charts/_ignore_me @@ -0,0 +1 @@ +This should be ignored by the loader, but may be included in a chart. diff --git a/pkg/chartutil/testdata/dependent-chart-helmignore/charts/alpine/Chart.yaml b/pkg/chartutil/testdata/dependent-chart-helmignore/charts/alpine/Chart.yaml new file mode 100644 index 000000000..38a4aaa54 --- /dev/null +++ b/pkg/chartutil/testdata/dependent-chart-helmignore/charts/alpine/Chart.yaml @@ -0,0 +1,4 @@ +name: alpine +description: Deploy a basic Alpine Linux pod +version: 0.1.0 +home: https://k8s.io/helm diff --git a/pkg/chartutil/testdata/dependent-chart-helmignore/charts/alpine/README.md b/pkg/chartutil/testdata/dependent-chart-helmignore/charts/alpine/README.md new file mode 100644 index 000000000..a7c84fc41 --- /dev/null +++ b/pkg/chartutil/testdata/dependent-chart-helmignore/charts/alpine/README.md @@ -0,0 +1,9 @@ +This example was generated using the command `helm create alpine`. + +The `templates/` directory contains a very simple pod resource with a +couple of parameters. + +The `values.toml` file contains the default values for the +`alpine-pod.yaml` template. + +You can install this example using `helm install docs/examples/alpine`. diff --git a/pkg/chartutil/testdata/dependent-chart-helmignore/charts/alpine/charts/mast1/Chart.yaml b/pkg/chartutil/testdata/dependent-chart-helmignore/charts/alpine/charts/mast1/Chart.yaml new file mode 100644 index 000000000..171e36156 --- /dev/null +++ b/pkg/chartutil/testdata/dependent-chart-helmignore/charts/alpine/charts/mast1/Chart.yaml @@ -0,0 +1,4 @@ +name: mast1 +description: A Helm chart for Kubernetes +version: 0.1.0 +home: "" diff --git a/pkg/chartutil/testdata/dependent-chart-helmignore/charts/alpine/charts/mast1/values.yaml b/pkg/chartutil/testdata/dependent-chart-helmignore/charts/alpine/charts/mast1/values.yaml new file mode 100644 index 000000000..42c39c262 --- /dev/null +++ b/pkg/chartutil/testdata/dependent-chart-helmignore/charts/alpine/charts/mast1/values.yaml @@ -0,0 +1,4 @@ +# Default values for mast1. +# This is a YAML-formatted file. +# Declare name/value pairs to be passed into your templates. +# name = "value" diff --git a/pkg/chartutil/testdata/dependent-chart-helmignore/charts/alpine/charts/mast2-0.1.0.tgz b/pkg/chartutil/testdata/dependent-chart-helmignore/charts/alpine/charts/mast2-0.1.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..ced5a4a6adf946f76033b6ee584affc12433cb78 GIT binary patch literal 325 zcmV-L0lNMliwFRxBUV=c1MSw|YJ)Ho2Jl|{6o>BKov2ah-PkS$dy3RWS}syLpID4If6g{VtOEXtaBMKbNS zqRDw>=dBp!{dV&0PTP0q&C|N>lXXt-@itxw6Y{^`DeLnWW%?A)n7>C|RUhXsgbeu$ zF~=_IIe#g+SrMn$%(;J_|DcTCP^g0JS-aNm4}L!m8@i)M-5Y9`%Ajtv^fYa?9kkaj zJ8J8~B+f<7*=}6cSg*6cei`_&c>Y7mE>#=&?)@Lnf3ci@t|adNONjYC00000 X0000000000z?FFgy`&fL04M+ebFHRB literal 0 HcmV?d00001 diff --git a/pkg/chartutil/testdata/dependent-chart-helmignore/charts/alpine/templates/alpine-pod.yaml b/pkg/chartutil/testdata/dependent-chart-helmignore/charts/alpine/templates/alpine-pod.yaml new file mode 100644 index 000000000..08cf3c2c1 --- /dev/null +++ b/pkg/chartutil/testdata/dependent-chart-helmignore/charts/alpine/templates/alpine-pod.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Pod +metadata: + name: {{.Release.Name}}-{{.Chart.Name}} + labels: + heritage: {{.Release.Service}} + chartName: {{.Chart.Name}} + chartVersion: {{.Chart.Version | quote}} + annotations: + "helm.sh/created": "{{.Release.Time.Seconds}}" +spec: + restartPolicy: {{default "Never" .restart_policy}} + containers: + - name: waiter + image: "alpine:3.3" + command: ["/bin/sleep","9000"] diff --git a/pkg/chartutil/testdata/dependent-chart-helmignore/charts/alpine/values.yaml b/pkg/chartutil/testdata/dependent-chart-helmignore/charts/alpine/values.yaml new file mode 100644 index 000000000..6c2aab7ba --- /dev/null +++ b/pkg/chartutil/testdata/dependent-chart-helmignore/charts/alpine/values.yaml @@ -0,0 +1,2 @@ +# The pod name +name: "my-alpine" diff --git a/pkg/chartutil/testdata/dependent-chart-helmignore/templates/template.tpl b/pkg/chartutil/testdata/dependent-chart-helmignore/templates/template.tpl new file mode 100644 index 000000000..c651ee6a0 --- /dev/null +++ b/pkg/chartutil/testdata/dependent-chart-helmignore/templates/template.tpl @@ -0,0 +1 @@ +Hello {{.Name | default "world"}} diff --git a/pkg/chartutil/testdata/dependent-chart-helmignore/values.yaml b/pkg/chartutil/testdata/dependent-chart-helmignore/values.yaml new file mode 100644 index 000000000..61f501258 --- /dev/null +++ b/pkg/chartutil/testdata/dependent-chart-helmignore/values.yaml @@ -0,0 +1,6 @@ +# A values file contains configuration. + +name: "Some Name" + +section: + name: "Name in a section" diff --git a/pkg/ignore/rules.go b/pkg/ignore/rules.go index aba089613..76f45fc7a 100644 --- a/pkg/ignore/rules.go +++ b/pkg/ignore/rules.go @@ -82,6 +82,11 @@ func (r *Rules) Len() int { // Ignore evaluates path against the rules in order. Evaluation stops when a match // is found. Matching a negative rule will stop evaluation. func (r *Rules) Ignore(path string, fi os.FileInfo) bool { + // Don't match on empty dirs. + if path == "" { + return false + } + // Disallow ignoring the current working directory. // See issue: // 1776 (New York City) Hamilton: "Pardon me, are you Aaron Burr, sir?" diff --git a/pkg/ignore/rules_test.go b/pkg/ignore/rules_test.go index 6afc4345b..17b8bf403 100644 --- a/pkg/ignore/rules_test.go +++ b/pkg/ignore/rules_test.go @@ -102,6 +102,9 @@ func TestIgnore(t *testing.T) { // "." should never get ignored. https://github.com/kubernetes/helm/issues/1776 {`.*`, ".", false}, {`.*`, "./", false}, + {`.*`, ".joonix", true}, + {`.*`, "helm.txt", false}, + {`.*`, "", false}, // Directory tests {`cargo/`, "cargo", true}, diff --git a/pkg/ignore/testdata/.joonix b/pkg/ignore/testdata/.joonix new file mode 100644 index 000000000..e69de29bb From 803f7c706ef4ce44aa6418c42c77dbf7e60ac66d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helgi=20=C3=9Eormar=20=C3=9Eorbj=C3=B6rnsson?= Date: Wed, 22 Nov 2017 08:30:25 -0800 Subject: [PATCH 090/107] add a keepalive of 30s to the client (#3183) --- pkg/helm/client.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkg/helm/client.go b/pkg/helm/client.go index dbaf01d96..33d56e88d 100644 --- a/pkg/helm/client.go +++ b/pkg/helm/client.go @@ -23,6 +23,7 @@ import ( "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/credentials" + "google.golang.org/grpc/keepalive" "k8s.io/helm/pkg/chartutil" "k8s.io/helm/pkg/proto/hapi/chart" @@ -289,6 +290,11 @@ func (h *Client) connect(ctx context.Context) (conn *grpc.ClientConn, err error) opts := []grpc.DialOption{ grpc.WithTimeout(5 * time.Second), grpc.WithBlock(), + grpc.WithKeepaliveParams(keepalive.ClientParameters{ + // Send keepalive every 30 seconds to prevent the connection from + // getting closed by upstreams + Time: time.Duration(30) * time.Second, + }), } switch { case h.opts.useTLS: From b74c21a7b291033cfe417a153eb4b455eba60696 Mon Sep 17 00:00:00 2001 From: Morgan Parry Date: Wed, 22 Nov 2017 16:39:02 +0000 Subject: [PATCH 091/107] fix(helm): Fixed semantic version constraints on 'search' command (#3116) Closes #3115 --- cmd/helm/search.go | 9 ++++++++- cmd/helm/search_test.go | 24 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/cmd/helm/search.go b/cmd/helm/search.go index fe572f46b..cf924dcb0 100644 --- a/cmd/helm/search.go +++ b/cmd/helm/search.go @@ -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 + } } } @@ -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 } diff --git a/cmd/helm/search_test.go b/cmd/helm/search_test.go index 7dc222a8e..0fb54b5f9 100644 --- a/cmd/helm/search_test.go +++ b/cmd/helm/search_test.go @@ -47,6 +47,30 @@ func TestSearchCmd(t *testing.T) { flags: []string{"--versions"}, 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", args: []string{"syzygy"}, From ae878f91c36b491b92f046de74784cb462f67419 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Thu, 2 Nov 2017 15:59:04 -0700 Subject: [PATCH 092/107] more expansive RBAC setup docs --- docs/rbac.md | 281 +++++++++++++++++++++++++++++++++++++++ docs/service_accounts.md | 170 ----------------------- 2 files changed, 281 insertions(+), 170 deletions(-) create mode 100644 docs/rbac.md delete mode 100644 docs/service_accounts.md diff --git a/docs/rbac.md b/docs/rbac.md new file mode 100644 index 000000000..bc138ceee --- /dev/null +++ b/docs/rbac.md @@ -0,0 +1,281 @@ +# Role-based Access Control + +In Kubernetes, granting a role to an application-specific service account is a best practice to ensure that your application is operating in the scope that you have specified. Read more about service account permissions [in the official Kubernetes docs](https://kubernetes.io/docs/admin/authorization/rbac/#service-account-permissions). + +Bitnami also has a fantastic guide for [configuring RBAC in your cluster](https://docs.bitnami.com/kubernetes/how-to/configure-rbac-in-your-kubernetes-cluster/) that takes you through RBAC basics. + +This guide is for users who want to restrict tiller's capabilities to install resources to certain namespaces, or to grant a helm client running access to a tiller instance. + +## Tiller and Role-based Access Control + +You can add a service account to Tiller using the `--service-account ` flag while you're configuring helm. As a prerequisite, you'll have to create a role binding which specifies a [role](https://kubernetes.io/docs/admin/authorization/rbac/#role-and-clusterrole) and a [service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) name that have been set up in advance. + +Once you have satisfied the pre-requisite and have a service account with the correct permissions, you'll run a command like this: `helm init --service-account ` + +### Example: Service account with cluster-admin role + +```console +$ kubectl create serviceaccount tiller --namespace kube-system +serviceaccount "tiller" created +``` + +In `rbac-config.yaml`: + +```yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: tiller + namespace: kube-system +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: tiller +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin +subjects: + - kind: ServiceAccount + name: tiller + namespace: kube-system +``` + +_Note: The cluster-admin role is created by default in a Kubernetes cluster, so you don't have to define it explicitly._ + +```console +$ kubectl create -f rbac-config.yaml +serviceaccount "tiller" created +clusterrolebinding "tiller" created +$ helm init --service-account tiller +``` + +### Example: Deploy tiller in a namespace, restricted to deploying resources only in that namespace + +In the example above, we gave Tiller admin access to the entire cluster. You are not at all required to give Tiller cluster-admin access for it to work. Instead of specifying a ClusterRole or a ClusterRoleBinding, you can specify a Role and RoleBinding to limit Tiller's scope to a particular namespace. + +```console +$ kubectl create namespace tiller-world +namespace "tiller-world" created +$ kubectl create serviceaccount tiller --namespace tiller-world +serviceaccount "tiller" created +``` + +Define a Role that allows tiller to manage all resources in `tiller-world` like in `role-tiller.yaml`: + +```yaml +kind: Role +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: tiller-manager + namespace: tiller-world +rules: +- apiGroups: ["", "extensions", "apps"] + resources: ["*"] + verbs: ["*"] +``` + +```console +$ kubectl create -f role-tiller.yaml +role "tiller-manager" created +``` + +In `rolebinding-tiller.yaml`, + +```yaml +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: tiller-binding + namespace: tiller-world +subjects: +- kind: ServiceAccount + name: tiller + namespace: tiller-world +roleRef: + kind: Role + name: tiller-manager + apiGroup: rbac.authorization.k8s.io +``` + +```console +$ kubectl create -f rolebinding-tiller.yaml +rolebinding "tiller-binding" created +``` + +Afterwards you can run `helm init` to install tiller in the `tiller-world` namespace. + +```console +$ helm init --service-account tiller --tiller-namespace tiller-world +$HELM_HOME has been configured at /Users/awesome-user/.helm. + +Tiller (the helm server side component) has been installed into your Kubernetes Cluster. +Happy Helming! + +$ helm install nginx --tiller-namespace tiller-world --namespace tiller-world +NAME: wayfaring-yak +LAST DEPLOYED: Mon Aug 7 16:00:16 2017 +NAMESPACE: tiller-world +STATUS: DEPLOYED + +RESOURCES: +==> v1/Pod +NAME READY STATUS RESTARTS AGE +wayfaring-yak-alpine 0/1 ContainerCreating 0 0s +``` + +### Example: Deploy tiller in a namespace, restricted to deploying resources in another namespace + +In the example above, we gave Tiller admin access to the namespace it was deployed inside. Now, let's limit Tiller's scope to deploy resources in a different namespace! + +For example, let's install tiller in the namespace `myorg-system` and allow tiller to deploy resources in the namespace `myorg-users`. + +```console +$ kubectl create namespace myorg-system +namespace "myorg-system" created +$ kubectl create serviceaccount tiller --namespace myorg-system +serviceaccount "tiller" created +``` + +Define a Role that allows tiller to manage all resources in `myorg-users` like in `role-tiller.yaml`: + +```yaml +kind: Role +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: tiller-manager + namespace: myorg-users +rules: +- apiGroups: ["", "extensions", "apps"] + resources: ["*"] + verbs: ["*"] +``` + +```console +$ kubectl create -f role-tiller.yaml +role "tiller-manager" created +``` + +Bind the service account to that role. In `rolebinding-tiller.yaml`, + +```yaml +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: tiller-binding + namespace: myorg-users +subjects: +- kind: ServiceAccount + name: tiller + namespace: myorg-system +roleRef: + kind: Role + name: tiller-manager + apiGroup: rbac.authorization.k8s.io +``` + +```console +$ kubectl create -f rolebinding-tiller.yaml +rolebinding "tiller-binding" created +``` + +We'll also need to grant tiller access to read configmaps in myorg-system so it can store release information. In `role-tiller-myorg-system.yaml`: + +```yaml +kind: Role +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + namespace: myorg-system + name: tiller-manager +rules: +- apiGroups: ["", "extensions", "apps"] + resources: ["configmaps"] + verbs: ["*"] +``` + +```console +$ kubectl create -f role-tiller-myorg-system.yaml +role "tiller-manager" created +``` + +And the respective role binding. In `rolebinding-tiller-myorg-system.yaml`: + +```yaml +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: tiller-binding + namespace: myorg-system +subjects: +- kind: ServiceAccount + name: tiller + namespace: myorg-system +roleRef: + kind: Role + name: tiller-manager + apiGroup: rbac.authorization.k8s.io +``` + +```console +$ kubectl create -f rolebinding-tiller-myorg-system.yaml +rolebinding "tiller-binding" created +``` + +## Helm and Role-based Access Control + +When running a helm client in a pod, in order for the helm client to talk to a tiller instance, it will need certain privileges to be granted. Specifically, the helm client will need to be able to create pods, forward ports and be able to list pods in the namespace where tiller is running (so it can find tiller). + +### Example: Deploy Helm in a namespace, talking to Tiller in another namespace + +In this example, we will assume tiller is running in a namespace called `tiller-world` and that the helm client is running in a namespace called `helm-world`. By default, tiller is running in the `kube-system` namespace. + +In `helm-user.yaml`: + +```yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: helm + namespace: helm-world +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: Role +metadata: + name: tiller-user + namespace: tiller-world +rules: +- apiGroups: + - "" + resources: + - pods/portforward + verbs: + - create +- apiGroups: + - "" + resources: + - pods + verbs: + - list +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: RoleBinding +metadata: + name: tiller-user-binding + namespace: tiller-world +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: tiller-user +subjects: +- kind: ServiceAccount + name: helm + namespace: helm-world +``` + +```console +$ kubectl create -f helm-user.yaml +serviceaccount "helm" created +role "tiller-user" created +rolebinding "tiller-user-binding" created +``` diff --git a/docs/service_accounts.md b/docs/service_accounts.md deleted file mode 100644 index 38e422fe1..000000000 --- a/docs/service_accounts.md +++ /dev/null @@ -1,170 +0,0 @@ -# Tiller and Service Accounts - -In Kubernetes, granting a role to an application-specific service account is a best practice to ensure that your application is operating in the scope that you have specified. Read more about service account permissions [in the official Kubernetes docs](https://kubernetes.io/docs/admin/authorization/rbac/#service-account-permissions). Bitnami also has a fantastic guide for [configuring RBAC in your cluster](https://docs.bitnami.com/kubernetes/how-to/configure-rbac-in-your-kubernetes-cluster/) that takes you through RBAC basics. - -You can add a service account to Tiller using the `--service-account ` flag while you're configuring helm. As a prerequisite, you'll have to create a role binding which specifies a [role](https://kubernetes.io/docs/admin/authorization/rbac/#role-and-clusterrole) and a [service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) name that have been set up in advance. - -Once you have satisfied the pre-requisite and have a service account with the correct permissions, you'll run a command like this: `helm init --service-account ` - -## Example: Service account with cluster-admin role - -```console -$ kubectl create serviceaccount tiller --namespace kube-system -``` - -In `rbac-config.yaml`: -```yaml -apiVersion: v1 -kind: ServiceAccount -metadata: - name: tiller - namespace: kube-system ---- -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: ClusterRoleBinding -metadata: - name: tiller -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: cluster-admin -subjects: - - kind: ServiceAccount - name: tiller - namespace: kube-system -``` - -_Note: The cluster-admin role is created by default in a Kubernetes cluster, so you don't have to define it explicitly._ - -```console -$ kubectl create -f rbac-config.yaml -$ helm init --service-account tiller -``` - -## Example: Service account restricted to a namespace -In the example above, we gave Tiller admin access to the entire cluster. You are not at all required to give Tiller cluster-admin access for it to work. Instead of specifying a ClusterRole or a ClusterRoleBinding, you can specify a Role and RoleBinding to limit Tiller's scope to a particular namespace. - -```console -$ kubectl create namespace tiller-world -namespace "tiller-world" created -$ kubectl create serviceaccount tiller --namespace tiller-world -serviceaccount "tiller" created -``` - -Define a Role like in `role-tiller.yaml`: -```yaml -kind: Role -apiVersion: rbac.authorization.k8s.io/v1beta1 -metadata: - namespace: tiller-world - name: tiller-manager -rules: -- apiGroups: ["", "extensions", "apps"] - resources: ["deployments", "replicasets", "pods", "configmaps", "secrets", "namespaces"] - verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # You can also use ["*"] -``` - -```console -$ kubectl create -f role-tiller.yaml -role "tiller-manager" created -``` - -In `rolebinding-tiller.yaml`, -```yaml -kind: RoleBinding -apiVersion: rbac.authorization.k8s.io/v1beta1 -metadata: - name: tiller-binding - namespace: tiller-world -subjects: -- kind: ServiceAccount - name: tiller - namespace: tiller-world -roleRef: - kind: Role - name: tiller-manager - apiGroup: rbac.authorization.k8s.io -``` - -```console -$ kubectl create -f rolebinding-tiller.yaml -rolebinding "tiller-binding" created -``` - -```console -$ helm init --service-account tiller --tiller-namespace tiller-world -$HELM_HOME has been configured at /Users/awesome-user/.helm. - -Tiller (the helm server side component) has been installed into your Kubernetes Cluster. -Happy Helming! - -$ helm install nginx --tiller-namespace tiller-world --namespace tiller-world -NAME: wayfaring-yak -LAST DEPLOYED: Mon Aug 7 16:00:16 2017 -NAMESPACE: tiller-world -STATUS: DEPLOYED - -RESOURCES: -==> v1/Pod -NAME READY STATUS RESTARTS AGE -wayfaring-yak-alpine 0/1 ContainerCreating 0 0s -``` - -# Helm and Service Accounts -In order for a helm client to talk to a tiller, it will need certain privileges to be granted. - -Specifically, the helm client will need to be able to `create` `pods/portforward` and -be able to `list` `pods` in the namespace where tiller is running. - -## Example: Service account for a helm client - -In this example, we will assume tiller is running in a namespace called `tiller-world` -and that the helm client is running in a namespace called `helm-world` By default, -tiller is running in the `kube-system` namespace. - -In `helm-user.yaml`: -```yaml -apiVersion: v1 -kind: ServiceAccount -metadata: - name: helm-user-serviceaccount - namespace: helm-world ---- -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: Role -metadata: - name: helm-user-role - namespace: tiller-world -rules: -- apiGroups: - - "" - resources: - - pods/portforward - verbs: - - create -- apiGroups: - - "" - resources: - - pods - verbs: - - list ---- -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: RoleBinding -metadata: - name: helm-user-role-binding - namespace: tiller-world -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: helm-user-role -subjects: -- kind: ServiceAccount - name: helm-user-serviceaccount - namespace: helm-world -``` - -Please note that the `role` and `rolebinding` must be placed in the namespace -that tiller is running in, while the service account must be in the namespace -that the helm client is to be run in. (the pod using the helm client must -be using the service account created here) \ No newline at end of file From af9190f956cf8983370fe6b6d96aa30e9552c94a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20H=C3=B6sler?= Date: Wed, 22 Nov 2017 18:32:05 +0100 Subject: [PATCH 093/107] feature: let FindChartInRepoURL return absolute chart URLs --- cmd/helm/install.go | 21 +++------------------ docs/helm/helm_install.md | 2 +- pkg/repo/chartrepo.go | 27 +++++++++++++++++++++++++-- pkg/repo/chartrepo_test.go | 18 ++++++++++++++++++ 4 files changed, 47 insertions(+), 21 deletions(-) diff --git a/cmd/helm/install.go b/cmd/helm/install.go index 088d05106..218ad7c22 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -85,7 +85,7 @@ There are five different ways you can express the chart you want to install: 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 +5. By chart reference and repo url: helm install --repo https://example.com/charts/ nginx CHART REFERENCES @@ -425,22 +425,7 @@ func locateChartPath(repoURL, name, version string, verify bool, keyring, if err != nil { return "", err } - - parsedChartURL, err := url.Parse(chartURL) - if err != nil { - return "", err - } - - if parsedChartURL.IsAbs() { - name = chartURL - } else { - parsedRepoURL, err := url.Parse(repoURL) - if err != nil { - return "", err - } - name = parsedRepoURL.ResolveReference(parsedChartURL).String() - } - + name = chartURL } if _, err := os.Stat(settings.Home.Archive()); os.IsNotExist(err) { @@ -459,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) { diff --git a/docs/helm/helm_install.md b/docs/helm/helm_install.md index 6ddb56cee..7e206f721 100644 --- a/docs/helm/helm_install.md +++ b/docs/helm/helm_install.md @@ -46,7 +46,7 @@ There are five different ways you can express the chart you want to install: 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 +5. By chart reference and repo url: helm install --repo https://example.com/charts/ nginx CHART REFERENCES diff --git a/pkg/repo/chartrepo.go b/pkg/repo/chartrepo.go index 236032eef..a7e0305c5 100644 --- a/pkg/repo/chartrepo.go +++ b/pkg/repo/chartrepo.go @@ -184,7 +184,7 @@ func (r *ChartRepository) generateIndex() error { } // FindChartInRepoURL finds chart in chart repository pointed by repoURL -// without adding repo to repostiories +// without adding repo to repositories func FindChartInRepoURL(repoURL, chartName, chartVersion, certFile, keyFile, caFile string, getters getter.Providers) (string, error) { // Download and write the index file to a temporary location @@ -227,5 +227,28 @@ func FindChartInRepoURL(repoURL, chartName, chartVersion, certFile, keyFile, caF return "", fmt.Errorf("%s has no downloadable URLs", errMsg) } - return cv.URLs[0], nil + chartURL := cv.URLs[0] + + absoluteChartURL, err := MakeAbsoluteChartURL(repoURL, chartURL) + if err != nil { + return "", err + } + + return absoluteChartURL, nil +} + +// MakeAbsoluteChartURL resolves chartURL relative to repoURL. +// If chartURL is absolute, it returns chartURL. +func MakeAbsoluteChartURL(repoURL, chartURL string) (string, error) { + parsedRepoURL, err := url.Parse(repoURL) + if err != nil { + return "", err + } + + parsedChartURL, err := url.Parse(chartURL) + if err != nil { + return "", err + } + + return parsedRepoURL.ResolveReference(parsedChartURL).String(), nil } diff --git a/pkg/repo/chartrepo_test.go b/pkg/repo/chartrepo_test.go index 9f1bc995a..cc19fd0b0 100644 --- a/pkg/repo/chartrepo_test.go +++ b/pkg/repo/chartrepo_test.go @@ -277,3 +277,21 @@ func TestErrorFindChartInRepoURL(t *testing.T) { t.Errorf("Expected error for chart not found, but got a different error (%v)", err) } } + +func TestMakeAbsoluteChartURL(t *testing.T) { + chartURL, err := MakeAbsoluteChartURL("http://localhost:8123/charts/", "nginx-0.2.0.tgz") + if err != nil { + t.Errorf("%s", err) + } + if chartURL != "http://localhost:8123/charts/nginx-0.2.0.tgz" { + t.Errorf("%s", chartURL) + } + + chartURL, err = MakeAbsoluteChartURL("http://localhost:8123", "https://kubernetes-charts.storage.googleapis.com/nginx-0.2.0.tgz") + if err != nil { + t.Errorf("%s", err) + } + if chartURL != "https://kubernetes-charts.storage.googleapis.com/nginx-0.2.0.tgz" { + t.Errorf("%s", chartURL) + } +} From 98e0bd2ecb9a276bdc041b73c2b4a531be5cfdb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20H=C3=B6sler?= Date: Thu, 23 Nov 2017 09:41:34 +0100 Subject: [PATCH 094/107] refactor: rename function and improve error messages --- pkg/repo/chartrepo.go | 20 ++++++++++---------- pkg/repo/chartrepo_test.go | 6 +++--- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/pkg/repo/chartrepo.go b/pkg/repo/chartrepo.go index a7e0305c5..b95a7ae07 100644 --- a/pkg/repo/chartrepo.go +++ b/pkg/repo/chartrepo.go @@ -229,26 +229,26 @@ func FindChartInRepoURL(repoURL, chartName, chartVersion, certFile, keyFile, caF chartURL := cv.URLs[0] - absoluteChartURL, err := MakeAbsoluteChartURL(repoURL, chartURL) + absoluteChartURL, err := ResolveReferenceURL(repoURL, chartURL) if err != nil { - return "", err + return "", fmt.Errorf("failed to make chart URL absolute: %v", err) } return absoluteChartURL, nil } -// MakeAbsoluteChartURL resolves chartURL relative to repoURL. -// If chartURL is absolute, it returns chartURL. -func MakeAbsoluteChartURL(repoURL, chartURL string) (string, error) { - parsedRepoURL, err := url.Parse(repoURL) +// ResolveReferenceURL resolves refURL relative to baseURL. +// If refURL is absolute, it simply returns refURL. +func ResolveReferenceURL(baseURL, refURL string) (string, error) { + parsedBaseURL, err := url.Parse(baseURL) if err != nil { - return "", err + return "", fmt.Errorf("failed to parse %s as URL: %v", baseURL, err) } - parsedChartURL, err := url.Parse(chartURL) + parsedRefURL, err := url.Parse(refURL) if err != nil { - return "", err + return "", fmt.Errorf("failed to parse %s as URL: %v", refURL, err) } - return parsedRepoURL.ResolveReference(parsedChartURL).String(), nil + return parsedBaseURL.ResolveReference(parsedRefURL).String(), nil } diff --git a/pkg/repo/chartrepo_test.go b/pkg/repo/chartrepo_test.go index cc19fd0b0..948ee12d3 100644 --- a/pkg/repo/chartrepo_test.go +++ b/pkg/repo/chartrepo_test.go @@ -278,8 +278,8 @@ func TestErrorFindChartInRepoURL(t *testing.T) { } } -func TestMakeAbsoluteChartURL(t *testing.T) { - chartURL, err := MakeAbsoluteChartURL("http://localhost:8123/charts/", "nginx-0.2.0.tgz") +func TestResolveReferenceURL(t *testing.T) { + chartURL, err := ResolveReferenceURL("http://localhost:8123/charts/", "nginx-0.2.0.tgz") if err != nil { t.Errorf("%s", err) } @@ -287,7 +287,7 @@ func TestMakeAbsoluteChartURL(t *testing.T) { t.Errorf("%s", chartURL) } - chartURL, err = MakeAbsoluteChartURL("http://localhost:8123", "https://kubernetes-charts.storage.googleapis.com/nginx-0.2.0.tgz") + chartURL, err = ResolveReferenceURL("http://localhost:8123", "https://kubernetes-charts.storage.googleapis.com/nginx-0.2.0.tgz") if err != nil { t.Errorf("%s", err) } From 335ea3c6ac1786aab4f3a0028d0c5bc7941d33d8 Mon Sep 17 00:00:00 2001 From: Mark Gibaud Date: Thu, 23 Nov 2017 09:16:02 +0000 Subject: [PATCH 095/107] correct typo --- docs/charts.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/charts.md b/docs/charts.md index f71cc2904..1bcafb64b 100644 --- a/docs/charts.md +++ b/docs/charts.md @@ -36,7 +36,7 @@ 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 dependancy or template file for the chart to be valid. +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 From f432e07126524db74fe5b9c958d07c74cbb7796e Mon Sep 17 00:00:00 2001 From: Alexandr Burdiyan Date: Thu, 23 Nov 2017 11:19:48 +0100 Subject: [PATCH 096/107] ref(helm): improve fullname template in starter chart Closes #1186 --- pkg/chartutil/create.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pkg/chartutil/create.go b/pkg/chartutil/create.go index ba43dec9b..5cdf7ab4b 100644 --- a/pkg/chartutil/create.go +++ b/pkg/chartutil/create.go @@ -237,11 +237,15 @@ 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). +If release name contains chart name it will be used as a full name. */}} {{- define ".fullname" -}} {{- $name := default .Chart.Name .Values.nameOverride -}} -{{- $default := printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} -{{- default $default .Values.fullnameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} {{- end -}} ` From 7cc610960f91589b9a07c285f73f96023db99fef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johnny=20Bergstr=C3=B6m?= Date: Wed, 8 Nov 2017 10:43:25 +0100 Subject: [PATCH 097/107] Walk symbolic link directories Continue walking symlinks to be able to use them for sub-charts. Useful when not specifying requirements but still want to share charts locally. --- pkg/chartutil/load.go | 41 +++++++++++++++++-- pkg/chartutil/requirements_test.go | 13 ++++++ pkg/chartutil/testdata/joonix/Chart.yaml | 4 ++ pkg/chartutil/testdata/joonix/charts/frobnitz | 1 + 4 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 pkg/chartutil/testdata/joonix/Chart.yaml create mode 120000 pkg/chartutil/testdata/joonix/charts/frobnitz diff --git a/pkg/chartutil/load.go b/pkg/chartutil/load.go index f10c0eddd..6d70f97b4 100644 --- a/pkg/chartutil/load.go +++ b/pkg/chartutil/load.go @@ -243,7 +243,7 @@ func LoadDir(dir string) (*chart.Chart, error) { files := []*BufferedFile{} topdir += string(filepath.Separator) - err = filepath.Walk(topdir, func(name string, fi os.FileInfo, err error) error { + walk := func(name string, fi os.FileInfo, err error) error { n := strings.TrimPrefix(name, topdir) if n == "" { // No need to process top level. Avoid bug with helmignore .* matching @@ -278,10 +278,45 @@ func LoadDir(dir string) (*chart.Chart, error) { files = append(files, &BufferedFile{Name: n, Data: data}) return nil - }) - if err != nil { + } + if err = filepath.Walk(topdir, symWalk(topdir, "", walk)); err != nil { return c, err } return LoadFiles(files) } + +// symWalk walks topdir with optional symbolic link dir, symdir. The symdir will +// be used as the path name sent to walkFn. +func symWalk(topdir, symdir string, walkFn filepath.WalkFunc) filepath.WalkFunc { + return func(name string, fi os.FileInfo, err error) error { + // Recover the symbolic path instead of the real path. + if symdir != "" { + relative, err := filepath.Rel(topdir, name) + if err != nil { + return err + } + name = filepath.Join(symdir, relative) + } + + // Recursively walk symlinked directories. + if isSymlink(fi) { + resolved, err := filepath.EvalSymlinks(name) + if err != nil { + return fmt.Errorf("error evaluating symlink %s: %s", name, err) + } + if fi, err = os.Lstat(resolved); err != nil { + return err + } + if fi.IsDir() { + return filepath.Walk(resolved, symWalk(resolved, name, walkFn)) + } + } + + return walkFn(name, fi, err) + } +} + +func isSymlink(fi os.FileInfo) bool { + return fi.Mode()&os.ModeSymlink != 0 +} diff --git a/pkg/chartutil/requirements_test.go b/pkg/chartutil/requirements_test.go index 1ddaa78a1..24388f86c 100644 --- a/pkg/chartutil/requirements_test.go +++ b/pkg/chartutil/requirements_test.go @@ -425,6 +425,19 @@ func TestDependentChartWithSubChartsHelmignore(t *testing.T) { } } +func TestDependentChartsWithSubChartsSymlink(t *testing.T) { + c, err := Load("testdata/joonix") + if err != nil { + t.Fatalf("Failed to load testdata: %s", err) + } + if c.Metadata.Name != "joonix" { + t.Fatalf("Unexpected chart name: %s", c.Metadata.Name) + } + if n := len(c.Dependencies); n != 1 { + t.Fatalf("Expected 1 dependency for this chart, but got %d", n) + } +} + func TestDependentChartsWithSubchartsAllSpecifiedInRequirements(t *testing.T) { c, err := Load("testdata/dependent-chart-with-all-in-requirements-yaml") if err != nil { diff --git a/pkg/chartutil/testdata/joonix/Chart.yaml b/pkg/chartutil/testdata/joonix/Chart.yaml new file mode 100644 index 000000000..c3464c56e --- /dev/null +++ b/pkg/chartutil/testdata/joonix/Chart.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +description: A Helm chart for Kubernetes +name: joonix +version: 1.2.3 diff --git a/pkg/chartutil/testdata/joonix/charts/frobnitz b/pkg/chartutil/testdata/joonix/charts/frobnitz new file mode 120000 index 000000000..fde1b78ac --- /dev/null +++ b/pkg/chartutil/testdata/joonix/charts/frobnitz @@ -0,0 +1 @@ +../../frobnitz \ No newline at end of file From d81780032a167816ec2c900857c7d074b8ae267c Mon Sep 17 00:00:00 2001 From: Igor Vuk Date: Thu, 23 Nov 2017 19:06:37 +0100 Subject: [PATCH 098/107] Fix a typo in install.go, update helm_install.md --- cmd/helm/install.go | 4 ++-- docs/helm/helm_install.md | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cmd/helm/install.go b/cmd/helm/install.go index 218ad7c22..e2f1ada66 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -76,8 +76,8 @@ 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 five different ways you can express the chart you want to install: diff --git a/docs/helm/helm_install.md b/docs/helm/helm_install.md index 7e206f721..f3a8ee06d 100644 --- a/docs/helm/helm_install.md +++ b/docs/helm/helm_install.md @@ -37,8 +37,8 @@ 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 five different ways you can express the chart you want to install: @@ -109,4 +109,4 @@ helm install [CHART] ### SEE ALSO * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 22-Nov-2017 +###### Auto generated by spf13/cobra on 23-Nov-2017 From 9e869700c0bbb76ebec94b7b12871d6fe27b59ab Mon Sep 17 00:00:00 2001 From: Arash Deshmeh Date: Thu, 23 Nov 2017 11:02:26 -0500 Subject: [PATCH 099/107] fix(helm): add --app-version flag to 'helm package' When 'helm package --app-version foo' is run, this will set the AppVersion field to 'foo' in the packaged chart. Signed-off-by: Arash Deshmeh --- cmd/helm/package.go | 7 +++++++ cmd/helm/package_test.go | 33 +++++++++++++++++++++++++++++++++ docs/helm/helm_package.md | 3 ++- 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/cmd/helm/package.go b/cmd/helm/package.go index 44c34a315..ed44382c7 100644 --- a/cmd/helm/package.go +++ b/cmd/helm/package.go @@ -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) } diff --git a/cmd/helm/package_test.go b/cmd/helm/package_test.go index eb6e02830..d338c29cd 100644 --- a/cmd/helm/package_test.go +++ b/cmd/helm/package_test.go @@ -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 { diff --git a/docs/helm/helm_package.md b/docs/helm/helm_package.md index c4b506641..71960f41e 100644 --- a/docs/helm/helm_package.md +++ b/docs/helm/helm_package.md @@ -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 @@ -46,4 +47,4 @@ helm package [flags] [CHART_PATH] [...] ### SEE ALSO * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 7-Nov-2017 +###### Auto generated by spf13/cobra on 24-Nov-2017 From c20ec8fedaef10e0642d20bfe554baeb932aa0ee Mon Sep 17 00:00:00 2001 From: Ralph Squillace Date: Sun, 26 Nov 2017 12:02:16 -0800 Subject: [PATCH 100/107] fixed bad link. --- docs/quickstart.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/quickstart.md b/docs/quickstart.md index 729a9c9e2..caad7abf6 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -21,7 +21,7 @@ my-cluster ``` If your cluster has Role-Based Access Control (RBAC) enabled, you may want -to [configure a service account and rules](service_account.md) before proceeding. +to [configure a service account and rules](rbac.md) before proceeding. ## Install Helm From 35616bd0df6d46b1f988bfdbb1f39c80d75fda3e Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Mon, 27 Nov 2017 09:39:26 -0800 Subject: [PATCH 101/107] fix links to service_accounts.md --- docs/index.md | 2 +- docs/tiller_ssl.md | 2 +- docs/using_helm.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/index.md b/docs/index.md index a8e4ac483..4ca93bd1f 100644 --- a/docs/index.md +++ b/docs/index.md @@ -6,7 +6,7 @@ - [Frequently Asked Questions](install_faq.md) - [Using Helm](using_helm.md) - Learn the Helm tools - [Plugins](plugins.md) - - [Service Accounts for Tiller](service_accounts.md) - Apply RBACs to Tiller + - [Role-based Access Control](rbac.md) - [TLS/SSL for Helm and Tiller](tiller_ssl.md) - Use Helm-to-Tiller encryption - [Developing Charts](charts.md) - An introduction to chart development - [Chart Lifecycle Hooks](charts_hooks.md) diff --git a/docs/tiller_ssl.md b/docs/tiller_ssl.md index 59d653e26..71ddd8080 100644 --- a/docs/tiller_ssl.md +++ b/docs/tiller_ssl.md @@ -199,7 +199,7 @@ start up. If you want to customize the manifest, you can save that output to a file and then use `kubectl create` to load it into your cluster. -> We strongly recommend enabling RBAC on your cluster and adding [service accounts](service_accounts.md) +> We strongly recommend enabling RBAC on your cluster and adding [service accounts](rbac.md) > with RBACS. Otherwise, you can remove the `--dry-run` and `--debug` flags. We also recommend diff --git a/docs/using_helm.md b/docs/using_helm.md index 531cdac44..d2e1768a8 100755 --- a/docs/using_helm.md +++ b/docs/using_helm.md @@ -498,7 +498,7 @@ accepts chart source code, and (after audit) packages those for you. In some cases you may wish to scope Tiller or deploy multiple Tillers to a single cluster. Here are some best practices when operating in those circumstances. 1. Tiller can be [installed](install.md) into any namespace. By default, it is installed into kube-system. You can run multiple Tillers provided they each run in their own namespace. -2. Limiting Tiller to only be able to install into specific namespaces and/or resource types is controlled by Kubernetes [RBAC](https://kubernetes.io/docs/admin/authorization/rbac/) roles and rolebindings. You can add a service account to Tiller when configuring Helm via `helm init --service-account `. You can find more information about that [here](service_accounts.md). +2. Limiting Tiller to only be able to install into specific namespaces and/or resource types is controlled by Kubernetes [RBAC](https://kubernetes.io/docs/admin/authorization/rbac/) roles and rolebindings. You can add a service account to Tiller when configuring Helm via `helm init --service-account `. You can find more information about that [here](rbac.md). 3. Release names are unique PER TILLER INSTANCE. 4. Charts should only contain resources that exist in a single namespace. 5. It is not recommended to have multiple Tillers configured to manage resources in the same namespace. From 44e5cecdcaee14c15055d20d6b9a72e80cd4794d Mon Sep 17 00:00:00 2001 From: Taylor Thomas Date: Sat, 11 Nov 2017 14:05:24 -0800 Subject: [PATCH 102/107] fix(tiller): Forces close of idle gRPC connections Possibly fixes #3121. This forces idle connections to drop after 10 minutes --- cmd/tiller/tiller.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cmd/tiller/tiller.go b/cmd/tiller/tiller.go index f9ec0d4fc..96eeddacb 100644 --- a/cmd/tiller/tiller.go +++ b/cmd/tiller/tiller.go @@ -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" @@ -155,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...) From 81eaf2f2636cc6eadb29d0fea71fd85d22812c97 Mon Sep 17 00:00:00 2001 From: Federico Gimenez Date: Wed, 29 Nov 2017 14:14:50 +0100 Subject: [PATCH 103/107] only check existence for the possibly kept manifests --- pkg/tiller/resource_policy.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/tiller/resource_policy.go b/pkg/tiller/resource_policy.go index e4e08d435..bc92f706a 100644 --- a/pkg/tiller/resource_policy.go +++ b/pkg/tiller/resource_policy.go @@ -38,12 +38,6 @@ func filterManifestsToKeep(manifests []Manifest, kubeClient environment.KubeClie keep := []Manifest{} for _, m := range manifests { - // check if m is in fact present from k8s client's POV. - output, err := kubeClient.Get(namespace, bytes.NewBufferString(m.Content)) - if err != nil || strings.Contains(output, kube.MissingGetHeader) { - continue - } - if m.Head.Metadata == nil || m.Head.Metadata.Annotations == nil || len(m.Head.Metadata.Annotations) == 0 { remaining = append(remaining, m) continue @@ -67,6 +61,12 @@ func filterManifestsToKeep(manifests []Manifest, kubeClient environment.KubeClie func summarizeKeptManifests(manifests []Manifest) string { message := "These resources were kept due to the resource policy:\n" for _, m := range manifests { + // check if m is in fact present from k8s client's POV. + output, err := kubeClient.Get(namespace, bytes.NewBufferString(m.Content)) + if err != nil || strings.Contains(output, kube.MissingGetHeader) { + continue + } + details := "[" + m.Head.Kind + "] " + m.Head.Metadata.Name + "\n" message = message + details } From 93bce130fbee835a2c136189b661c9a8ec0812cb Mon Sep 17 00:00:00 2001 From: Federico Gimenez Date: Wed, 29 Nov 2017 14:18:12 +0100 Subject: [PATCH 104/107] fix signatures --- pkg/tiller/release_modules.go | 4 ++-- pkg/tiller/resource_policy.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/tiller/release_modules.go b/pkg/tiller/release_modules.go index 57b8c4fee..876e1ba37 100644 --- a/pkg/tiller/release_modules.go +++ b/pkg/tiller/release_modules.go @@ -159,9 +159,9 @@ func DeleteRelease(rel *release.Release, vs chartutil.VersionSet, kubeClient env return rel.Manifest, []error{fmt.Errorf("corrupted release record. You must manually delete the resources: %s", err)} } - filesToKeep, filesToDelete := filterManifestsToKeep(files, kubeClient, rel.Namespace) + filesToKeep, filesToDelete := filterManifestsToKeep(files) if len(filesToKeep) > 0 { - kept = summarizeKeptManifests(filesToKeep) + kept = summarizeKeptManifests(filesToKeep, kubeClient, rel.Namespace) } errs = []error{} diff --git a/pkg/tiller/resource_policy.go b/pkg/tiller/resource_policy.go index bc92f706a..fe4684476 100644 --- a/pkg/tiller/resource_policy.go +++ b/pkg/tiller/resource_policy.go @@ -33,7 +33,7 @@ const resourcePolicyAnno = "helm.sh/resource-policy" // during an uninstallRelease action. const keepPolicy = "keep" -func filterManifestsToKeep(manifests []Manifest, kubeClient environment.KubeClient, namespace string) ([]Manifest, []Manifest) { +func filterManifestsToKeep(manifests []Manifest) ([]Manifest, []Manifest) { remaining := []Manifest{} keep := []Manifest{} @@ -58,7 +58,7 @@ func filterManifestsToKeep(manifests []Manifest, kubeClient environment.KubeClie return keep, remaining } -func summarizeKeptManifests(manifests []Manifest) string { +func summarizeKeptManifests(manifests []Manifest, kubeClient environment.KubeClient, namespace string) string { message := "These resources were kept due to the resource policy:\n" for _, m := range manifests { // check if m is in fact present from k8s client's POV. From a607fe798d9ea590d94e52541f2f01623a455c4f Mon Sep 17 00:00:00 2001 From: Federico Gimenez Date: Thu, 30 Nov 2017 08:49:48 +0100 Subject: [PATCH 105/107] iinitialize message only when at least one manifest is kept --- pkg/tiller/resource_policy.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/tiller/resource_policy.go b/pkg/tiller/resource_policy.go index fe4684476..66da1283f 100644 --- a/pkg/tiller/resource_policy.go +++ b/pkg/tiller/resource_policy.go @@ -59,7 +59,7 @@ func filterManifestsToKeep(manifests []Manifest) ([]Manifest, []Manifest) { } func summarizeKeptManifests(manifests []Manifest, kubeClient environment.KubeClient, namespace string) string { - message := "These resources were kept due to the resource policy:\n" + var message string for _, m := range manifests { // check if m is in fact present from k8s client's POV. output, err := kubeClient.Get(namespace, bytes.NewBufferString(m.Content)) @@ -68,6 +68,9 @@ func summarizeKeptManifests(manifests []Manifest, kubeClient environment.KubeCli } details := "[" + m.Head.Kind + "] " + m.Head.Metadata.Name + "\n" + if message == "" { + message = "These resources were kept due to the resource policy:\n" + } message = message + details } return message From 57f95213f356125da730aa98f09300bbebd14619 Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Fri, 1 Dec 2017 15:16:35 -0500 Subject: [PATCH 106/107] fix(sprig): Update to v2.14.1 that fixes an issue There was an issue with functions not being able to pass to each other. For example, the output of regex not being able to be passed to first or last due to type issues. This update fixes those problems --- glide.lock | 6 +++--- glide.yaml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/glide.lock b/glide.lock index 10cd55076..e24eca700 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: 3d0ff2a6cf119f719abbd2606da14a00073627972be81a6e68404ad92c2d4cd5 -updated: 2017-11-04T13:04:46.410949815+01:00 +hash: cdacf92805a7371d74694ab6a82d7475639e4b20113ff3bca961f42b6554cbb0 +updated: 2017-12-01T15:12:23.724268985-05:00 imports: - name: cloud.google.com/go version: 3b1ae45394a234c385be014e9a488f2bb6eef821 @@ -189,7 +189,7 @@ imports: - name: github.com/Masterminds/semver version: 517734cc7d6470c0d07130e40fd40bdeb9bcd3fd - name: github.com/Masterminds/sprig - version: efda631a76d70875162cdc25ffa0d0164bf69758 + version: b217b9c388de2cacde4354c536e520c52c055563 - name: github.com/Masterminds/vcs version: 3084677c2c188840777bff30054f2b553729d329 - name: github.com/mattn/go-runewidth diff --git a/glide.yaml b/glide.yaml index ef29fe246..5aa6899e5 100644 --- a/glide.yaml +++ b/glide.yaml @@ -14,7 +14,7 @@ import: - package: github.com/imdario/mergo version: 6633656539c1639d9d78127b7d47c622b5d7b6dc - package: github.com/Masterminds/sprig - version: ^2.14 + version: ^2.14.1 - package: github.com/ghodss/yaml - package: github.com/Masterminds/semver version: ~1.3.1 From 618094ccd2a37acb0adbdcd43885eb6aae0a712c Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Fri, 1 Dec 2017 12:53:50 -0800 Subject: [PATCH 107/107] fix TLS default path Without this change, running `helm list --tls` without setting $HELM_HOME causes helm to look for TLS certificates under /. --- cmd/helm/helm.go | 6 +++--- pkg/helm/helmpath/helmhome.go | 17 ++++++++++++++++- pkg/helm/helmpath/helmhome_unix_test.go | 3 +++ pkg/helm/helmpath/helmhome_windows_test.go | 3 +++ 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/cmd/helm/helm.go b/cmd/helm/helm.go index b262e577b..3810cfb8e 100644 --- a/cmd/helm/helm.go +++ b/cmd/helm/helm.go @@ -268,13 +268,13 @@ func newClient() helm.Interface { if tlsVerify || tlsEnable { if tlsCaCertFile == "" { - tlsCaCertFile = os.ExpandEnv(tlsCaCertDefault) + tlsCaCertFile = settings.Home.TLSCaCert() } if tlsCertFile == "" { - tlsCertFile = os.ExpandEnv(tlsCertDefault) + tlsCertFile = settings.Home.TLSCert() } if tlsKeyFile == "" { - tlsKeyFile = os.ExpandEnv(tlsKeyDefault) + tlsKeyFile = settings.Home.TLSKey() } debug("Key=%q, Cert=%q, CA=%q\n", tlsKeyFile, tlsCertFile, tlsCaCertFile) tlsopts := tlsutil.Options{KeyFile: tlsKeyFile, CertFile: tlsCertFile, InsecureSkipVerify: true} diff --git a/pkg/helm/helmpath/helmhome.go b/pkg/helm/helmpath/helmhome.go index 2f9877f85..b5ec4909e 100644 --- a/pkg/helm/helmpath/helmhome.go +++ b/pkg/helm/helmpath/helmhome.go @@ -82,7 +82,22 @@ func (h Home) Plugins() string { return h.Path("plugins") } -// Archive returns the path to download chart archives +// Archive returns the path to download chart archives. func (h Home) Archive() string { return h.Path("cache", "archive") } + +// TLSCaCert returns the path to fetch the CA certificate. +func (h Home) TLSCaCert() string { + return h.Path("ca.pem") +} + +// TLSCert returns the path to fetch the client certificate. +func (h Home) TLSCert() string { + return h.Path("cert.pem") +} + +// TLSKey returns the path to fetch the client public key. +func (h Home) TLSKey() string { + return h.Path("key.pem") +} diff --git a/pkg/helm/helmpath/helmhome_unix_test.go b/pkg/helm/helmpath/helmhome_unix_test.go index 153e506e0..494d0f6b4 100644 --- a/pkg/helm/helmpath/helmhome_unix_test.go +++ b/pkg/helm/helmpath/helmhome_unix_test.go @@ -38,6 +38,9 @@ func TestHelmHome(t *testing.T) { isEq(t, hh.CacheIndex("t"), "/r/repository/cache/t-index.yaml") isEq(t, hh.Starters(), "/r/starters") isEq(t, hh.Archive(), "/r/cache/archive") + isEq(t, hh.TLSCaCert(), "/r/ca.pem") + isEq(t, hh.TLSCert(), "/r/cert.pem") + isEq(t, hh.TLSKey(), "/r/key.pem") } func TestHelmHome_expand(t *testing.T) { diff --git a/pkg/helm/helmpath/helmhome_windows_test.go b/pkg/helm/helmpath/helmhome_windows_test.go index d29c29b60..e416bfd58 100644 --- a/pkg/helm/helmpath/helmhome_windows_test.go +++ b/pkg/helm/helmpath/helmhome_windows_test.go @@ -35,4 +35,7 @@ func TestHelmHome(t *testing.T) { isEq(t, hh.CacheIndex("t"), "r:\\repository\\cache\\t-index.yaml") isEq(t, hh.Starters(), "r:\\starters") isEq(t, hh.Archive(), "r:\\cache\\archive") + isEq(t, hh.TLSCaCert(), "r:\\ca.pem") + isEq(t, hh.TLSCert(), "r:\\cert.pem") + isEq(t, hh.TLSKey(), "r:\\key.pem") }