Merge branch 'master' of github.com:kubernetes/helm into upstream

pull/2862/head
Ryan Payton 8 years ago
commit 2bd6940061

@ -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: Binary downloads of the Helm client can be found at the following links:
- [OSX](https://kubernetes-helm.storage.googleapis.com/helm-v2.6.1-darwin-amd64.tar.gz) - [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.1-linux-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.1-linux-386.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.1-windows-amd64.tar.gz) - [Windows](https://kubernetes-helm.storage.googleapis.com/helm-v2.6.2-windows-amd64.tar.gz)
Unpack the `helm` binary and add it to your PATH and you are good to go! Unpack the `helm` binary and add it to your PATH and you are good to go!
macOS/[homebrew](https://brew.sh/) users can also use `brew install kubernetes-helm`. macOS/[homebrew](https://brew.sh/) users can also use `brew install kubernetes-helm`.
@ -53,7 +53,7 @@ Get started with the [Quick Start guide](https://docs.helm.sh/using_helm/#quicks
## Roadmap ## Roadmap
The [Helm roadmap is currently located on the wiki](https://github.com/kubernetes/helm/wiki/Roadmap). The [Helm roadmap uses Github milestones](https://github.com/kubernetes/helm/milestones) to track the progress of the project.
## Community, discussion, contribution, and support ## Community, discussion, contribution, and support

@ -96,7 +96,7 @@ func (d *dependencyUpdateCmd) run() error {
Getters: getter.All(settings), Getters: getter.All(settings),
} }
if d.verify { if d.verify {
man.Verify = downloader.VerifyIfPossible man.Verify = downloader.VerifyAlways
} }
if settings.Debug { if settings.Debug {
man.Debug = true man.Debug = true

@ -46,8 +46,8 @@ import (
const installDesc = ` const installDesc = `
This command installs a chart archive. This command installs a chart archive.
The install argument must be either a relative path to a chart directory or the The install argument must be a chart reference, a path to a packaged chart,
name of a chart in the current working directory. a path to an unpacked chart directory or a URL.
To override values in a chart, use either the '--values' flag and pass in a file To override values in a chart, use either the '--values' flag and pass in a file
or use the '--set' flag and pass configuration from the command line. or use the '--set' flag and pass configuration from the command line.

@ -30,7 +30,6 @@ import (
"strings" "strings"
"github.com/Masterminds/semver" "github.com/Masterminds/semver"
"k8s.io/helm/pkg/repo" "k8s.io/helm/pkg/repo"
) )
@ -147,6 +146,8 @@ func (i *Index) SearchLiteral(term string, threshold int) []*Result {
term = strings.ToLower(term) term = strings.ToLower(term)
buf := []*Result{} buf := []*Result{}
for k, v := range i.lines { for k, v := range i.lines {
k = strings.ToLower(k)
v = strings.ToLower(v)
res := strings.Index(v, term) res := strings.Index(v, term)
if score := i.calcScore(res, v); res != -1 && score < threshold { if score := i.calcScore(res, v); res != -1 && score < threshold {
parts := strings.Split(k, verSep) // Remove version, if it is there. parts := strings.Split(k, verSep) // Remove version, if it is there.
@ -231,5 +232,5 @@ func (s scoreSorter) Less(a, b int) bool {
func indstr(name string, ref *repo.ChartVersion) string { func indstr(name string, ref *repo.ChartVersion) string {
i := ref.Name + sep + name + "/" + ref.Name + sep + i := ref.Name + sep + name + "/" + ref.Name + sep +
ref.Description + sep + strings.Join(ref.Keywords, " ") ref.Description + sep + strings.Join(ref.Keywords, " ")
return strings.ToLower(i) return i
} }

@ -135,7 +135,7 @@ func TestAll(t *testing.T) {
func TestAddRepo_Sort(t *testing.T) { func TestAddRepo_Sort(t *testing.T) {
i := loadTestIndex(t, true) i := loadTestIndex(t, true)
sr, err := i.Search("testing/santa-maria", 100, false) sr, err := i.Search("TESTING/SANTA-MARIA", 100, false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -202,6 +202,14 @@ func TestSearchByName(t *testing.T) {
{Name: "ztesting/pinta"}, {Name: "ztesting/pinta"},
}, },
}, },
{
name: "description upper search, two results",
query: "TWO",
expect: []*Result{
{Name: "testing/pinta"},
{Name: "ztesting/pinta"},
},
},
{ {
name: "nothing found", name: "nothing found",
query: "mayflower", query: "mayflower",
@ -209,7 +217,7 @@ func TestSearchByName(t *testing.T) {
}, },
{ {
name: "regexp, one result", name: "regexp, one result",
query: "th[ref]*", query: "Th[ref]*",
expect: []*Result{ expect: []*Result{
{Name: "testing/santa-maria"}, {Name: "testing/santa-maria"},
}, },

@ -26,6 +26,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/Masterminds/semver"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/helm/pkg/chartutil" "k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/engine" "k8s.io/helm/pkg/engine"
@ -35,6 +36,7 @@ import (
util "k8s.io/helm/pkg/releaseutil" util "k8s.io/helm/pkg/releaseutil"
"k8s.io/helm/pkg/tiller" "k8s.io/helm/pkg/tiller"
"k8s.io/helm/pkg/timeconv" "k8s.io/helm/pkg/timeconv"
tversion "k8s.io/helm/pkg/version"
) )
const templateDesc = ` const templateDesc = `
@ -61,6 +63,7 @@ type templateCmd struct {
showNotes bool showNotes bool
releaseName string releaseName string
renderFiles []string renderFiles []string
kubeVersion string
} }
func newTemplateCmd(out io.Writer) *cobra.Command { func newTemplateCmd(out io.Writer) *cobra.Command {
@ -84,6 +87,7 @@ func newTemplateCmd(out io.Writer) *cobra.Command {
f.StringVar(&t.namespace, "namespace", "", "namespace to install the release into") f.StringVar(&t.namespace, "namespace", "", "namespace to install the release into")
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.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.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)")
return cmd return cmd
} }
@ -171,7 +175,22 @@ func (t *templateCmd) run(cmd *cobra.Command, args []string) error {
// Set up engine. // Set up engine.
renderer := engine.New() renderer := engine.New()
vals, err := chartutil.ToRenderValues(c, config, options) caps := &chartutil.Capabilities{
APIVersions: chartutil.DefaultVersionSet,
KubeVersion: chartutil.DefaultKubeVersion,
TillerVersion: tversion.GetVersionProto(),
}
// If --kube-versionis set, try to parse it as SemVer, and override the
// kubernetes version
if t.kubeVersion != "" {
kv, err := semver.NewVersion(t.kubeVersion)
if err != nil {
return fmt.Errorf("could not parse a kubernetes version: %v", err)
}
caps.KubeVersion.Major = fmt.Sprint(kv.Major())
caps.KubeVersion.Minor = fmt.Sprint(kv.Minor())
}
vals, err := chartutil.ToRenderValuesCaps(c, config, options, caps)
if err != nil { if err != nil {
return err return err
} }

@ -104,6 +104,13 @@ func TestTemplateCmd(t *testing.T) {
expectKey: "subchart1/templates/service.yaml", expectKey: "subchart1/templates/service.yaml",
expectValue: "release-name: \"foobar-YWJj-baz\"", expectValue: "release-name: \"foobar-YWJj-baz\"",
}, },
{
name: "check_kube_version",
desc: "verify --kube-version overrides the kubernetes version",
args: []string{chartPath, "--kube-version", "1.6"},
expectKey: "subchart1/templates/service.yaml",
expectValue: "kube-version/major: \"1\"\n kube-version/minor: \"6\"",
},
} }
var buf bytes.Buffer var buf bytes.Buffer

@ -87,7 +87,7 @@ in the future.) It is considered good practice to add a hook weight, and set it
to `0` if weight is not important. to `0` if weight is not important.
### Hook resources are not managed with correponding releases ### Hook resources are not managed with corresponding releases
The resources that a hook creates are not tracked or managed as part of the The resources that a hook creates are not tracked or managed as part of the
release. Once Tiller verifies that the hook has reached its ready state, it release. Once Tiller verifies that the hook has reached its ready state, it
@ -180,5 +180,4 @@ It is also possible to define policies that determine when to delete correspondi
"helm.sh/hook-delete-policy": hook-succeeded "helm.sh/hook-delete-policy": hook-succeeded
``` ```
When using `"helm.sh/hook-delete-policy"` annoation, you can choose its value from `"hook-succeeded"` and `"hook-failed"`. The value `"hook-succeeded"` specifies Tiller should delete the hook after the hook is successfully excuted, while the value `"hook-failed"`specifies Tiller should delete the hook if the hook is failed during execuation. When using `"helm.sh/hook-delete-policy"` annotation, you can choose its value from `"hook-succeeded"` and `"hook-failed"`. The value `"hook-succeeded"` specifies Tiller should delete the hook after the hook is successfully executed, while the value `"hook-failed"`specifies Tiller should delete the hook if the hook failed during execution.

@ -21,7 +21,9 @@ We use Make to build our programs. The simplest way to get started is:
$ make bootstrap build $ make bootstrap build
``` ```
NOTE: This will fail if not run from the path: `$GOPATH/src/k8s.io/helm`. NOTE: This will fail if not running from the path `$GOPATH/src/k8s.io/helm`. The
directory `k8s.io` should not be a symlink or `build` will not find the relevant
packages.
This will build both Helm and Tiller. `make bootstrap` will attempt to This will build both Helm and Tiller. `make bootstrap` will attempt to
install certain tools if they are missing. install certain tools if they are missing.

@ -8,8 +8,8 @@ install a chart archive
This command installs a chart archive. This command installs a chart archive.
The install argument must be either a relative path to a chart directory or the The install argument must be a chart reference, a path to a packaged chart,
name of a chart in the current working directory. a path to an unpacked chart directory or a URL.
To override values in a chart, use either the '--values' flag and pass in a file To override values in a chart, use either the '--values' flag and pass in a file
or use the '--set' flag and pass configuration from the command line. or use the '--set' flag and pass configuration from the command line.

@ -26,6 +26,7 @@ helm template [flags] CHART
``` ```
-x, --execute stringArray only execute the given templates -x, --execute stringArray only execute the given templates
--kube-version string override the Kubernetes version used as Capabilities.KubeVersion.Major/Minor (e.g. 1.7)
-n, --name string release name (default "RELEASE-NAME") -n, --name string release name (default "RELEASE-NAME")
--name-template string specify template used to name the release --name-template string specify template used to name the release
--namespace string namespace to install the release into --namespace string namespace to install the release into
@ -47,4 +48,4 @@ helm template [flags] CHART
### SEE ALSO ### SEE ALSO
* [helm](helm.md) - The Helm package manager for Kubernetes. * [helm](helm.md) - The Helm package manager for Kubernetes.
###### Auto generated by spf13/cobra on 24-Aug-2017 ###### Auto generated by spf13/cobra on 11-Sep-2017

@ -18,8 +18,8 @@ helm\-install \- install a chart archive
This command installs a chart archive. This command installs a chart archive.
.PP .PP
The install argument must be either a relative path to a chart directory or the The install argument must be a chart reference, a path to a packaged chart,
name of a chart in the current working directory. a path to an unpacked chart directory or a URL.
.PP .PP
To override values in a chart, use either the '\-\-values' flag and pass in a file To override values in a chart, use either the '\-\-values' flag and pass in a file

@ -57,6 +57,7 @@ Tools layered on top of Helm or Tiller.
- [Monocular](https://github.com/helm/monocular) - Web UI for Helm Chart repositories - [Monocular](https://github.com/helm/monocular) - Web UI for Helm Chart repositories
- [Helm Chart Publisher](https://github.com/luizbafilho/helm-chart-publisher) - HTTP API for publishing Helm Charts in an easy way - [Helm Chart Publisher](https://github.com/luizbafilho/helm-chart-publisher) - HTTP API for publishing Helm Charts in an easy way
- [Armada](https://github.com/att-comdev/armada) - Manage prefixed releases throughout various Kubernetes namespaces, and removes completed jobs for complex deployments. Used by the [Openstack-Helm](https://github.com/openstack/openstack-helm) team. - [Armada](https://github.com/att-comdev/armada) - Manage prefixed releases throughout various Kubernetes namespaces, and removes completed jobs for complex deployments. Used by the [Openstack-Helm](https://github.com/openstack/openstack-helm) team.
- [ChartMuseum](https://github.com/chartmuseum/chartmuseum) - Helm Chart Repository with support for Amazon S3 and Google Cloud Storage
## Helm Included ## Helm Included

46
glide.lock generated

@ -1,5 +1,5 @@
hash: 54e64255ab9112d0183766264214969a8add57903fbe9e96034f9640b9c9cd82 hash: 0759b118eb4017d612af767460cdec467d6f78013ad1efff1c82676f1df84a75
updated: 2017-07-10T10:52:19.616678852-04:00 updated: 2017-09-26T15:21:30.833774-07:00
imports: imports:
- name: cloud.google.com/go - name: cloud.google.com/go
version: 3b1ae45394a234c385be014e9a488f2bb6eef821 version: 3b1ae45394a234c385be014e9a488f2bb6eef821
@ -8,7 +8,7 @@ imports:
- name: github.com/asaskevich/govalidator - name: github.com/asaskevich/govalidator
version: 7664702784775e51966f0885f5cd27435916517b version: 7664702784775e51966f0885f5cd27435916517b
- name: github.com/Azure/go-autorest - name: github.com/Azure/go-autorest
version: d7c034a8af24eda120dd6460bfcd6d9ed14e43ca version: 58f6f26e200fa5dfb40c9cd1c83f3e2c860d779d
- name: github.com/beorn7/perks - name: github.com/beorn7/perks
version: 3ac7bf7a47d159a033b107610db8a1b6575507a4 version: 3ac7bf7a47d159a033b107610db8a1b6575507a4
subpackages: subpackages:
@ -68,10 +68,6 @@ imports:
version: ba18e35c5c1b36ef6334cad706eb681153d2d379 version: ba18e35c5c1b36ef6334cad706eb681153d2d379
- name: github.com/exponent-io/jsonpath - name: github.com/exponent-io/jsonpath
version: d6023ce2651d8eafb5c75bb0c7167536102ec9f5 version: d6023ce2651d8eafb5c75bb0c7167536102ec9f5
- name: github.com/facebookgo/atomicfile
version: 2de1f203e7d5e386a6833233882782932729f27e
- name: github.com/facebookgo/symwalk
version: 42004b9f322246749dd73ad71008b1f3160c0052
- name: github.com/fatih/camelcase - name: github.com/fatih/camelcase
version: f6a740d52f961c60348ebb109adde9f4635d7540 version: f6a740d52f961c60348ebb109adde9f4635d7540
- name: github.com/ghodss/yaml - name: github.com/ghodss/yaml
@ -137,20 +133,20 @@ imports:
subpackages: subpackages:
- lru - lru
- name: github.com/golang/protobuf - name: github.com/golang/protobuf
version: 2bba0603135d7d7f5cb73b2125beeda19c09f4ef version: 4bd1920723d7b7c925de087aa32e2187708897f7
subpackages: subpackages:
- proto - proto
- ptypes/any - ptypes/any
- ptypes/timestamp - ptypes/timestamp
- name: github.com/google/gofuzz - name: github.com/google/gofuzz
version: bbcb9da2d746f8bdbd6a936686a0a6067ada0ec5 version: 44d81051d367757e1c7c6a5a86423ece9afcf63c
- name: github.com/gosuri/uitable - name: github.com/gosuri/uitable
version: 36ee7e946282a3fb1cfecd476ddc9b35d8847e42 version: 36ee7e946282a3fb1cfecd476ddc9b35d8847e42
subpackages: subpackages:
- util/strutil - util/strutil
- util/wordwrap - util/wordwrap
- name: github.com/grpc-ecosystem/go-grpc-prometheus - name: github.com/grpc-ecosystem/go-grpc-prometheus
version: 0c1b191dbfe51efdabe3c14b9f6f3b96429e0722 version: 2500245aa6110c562d17020fb31a2c133d737799
- name: github.com/hashicorp/golang-lru - name: github.com/hashicorp/golang-lru
version: a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4 version: a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4
- name: github.com/howeyc/gopass - name: github.com/howeyc/gopass
@ -172,7 +168,7 @@ imports:
- name: github.com/Masterminds/semver - name: github.com/Masterminds/semver
version: 517734cc7d6470c0d07130e40fd40bdeb9bcd3fd version: 517734cc7d6470c0d07130e40fd40bdeb9bcd3fd
- name: github.com/Masterminds/sprig - name: github.com/Masterminds/sprig
version: 9526be0327b26ad31aa70296a7b10704883976d5 version: 4c164950cd0a8d3724ddb78982e2c56dc7f47112
- name: github.com/Masterminds/vcs - name: github.com/Masterminds/vcs
version: 3084677c2c188840777bff30054f2b553729d329 version: 3084677c2c188840777bff30054f2b553729d329
- name: github.com/mattn/go-runewidth - name: github.com/mattn/go-runewidth
@ -223,7 +219,7 @@ imports:
- name: github.com/spf13/pflag - name: github.com/spf13/pflag
version: 9ff6c6923cfffbcd502984b8e0c80539a94968b7 version: 9ff6c6923cfffbcd502984b8e0c80539a94968b7
- name: github.com/technosophos/moniker - name: github.com/technosophos/moniker
version: ab470f5e105a44d0c87ea21bacd6a335c4816d83 version: 9f956786b91d9786ca11aa5be6104542fa911546
- name: github.com/ugorji/go - name: github.com/ugorji/go
version: ded73eae5db7e7a0ef6f55aace87a2873c5d2b74 version: ded73eae5db7e7a0ef6f55aace87a2873c5d2b74
subpackages: subpackages:
@ -254,7 +250,7 @@ imports:
- lex/httplex - lex/httplex
- trace - trace
- name: golang.org/x/oauth2 - name: golang.org/x/oauth2
version: 3c3a985cb79f52a3190fbc056984415ca6763d01 version: a6bd8cefa1811bd24b86f8902872e4e8225f74c4
- name: golang.org/x/sys - name: golang.org/x/sys
version: 8f0908ab3b2457e2e15403d3697c9ef5cb4b57a9 version: 8f0908ab3b2457e2e15403d3697c9ef5cb4b57a9
subpackages: subpackages:
@ -302,34 +298,14 @@ imports:
- name: k8s.io/api - name: k8s.io/api
version: 4fe9229aaa9d704f8a2a21cdcd50de2bbb6e1b57 version: 4fe9229aaa9d704f8a2a21cdcd50de2bbb6e1b57
subpackages: subpackages:
- admissionregistration/v1alpha1
- apps/v1beta1
- authentication/v1
- authentication/v1beta1
- authorization/v1
- authorization/v1beta1
- autoscaling/v1
- autoscaling/v2alpha1
- batch/v1
- batch/v2alpha1
- certificates/v1beta1
- core/v1 - core/v1
- extensions/v1beta1
- networking/v1
- policy/v1beta1
- rbac/v1alpha1
- rbac/v1beta1
- settings/v1alpha1
- storage/v1
- storage/v1beta1
- name: k8s.io/apiserver - name: k8s.io/apiserver
version: 087d1a2efeb6296f04bb0f54e7af9890052aa6d7 version: 2308857ad3b8b18abf74ff734853973eda9da94d
subpackages: subpackages:
- pkg/admission - pkg/admission
- pkg/apis/apiserver - pkg/apis/apiserver
- pkg/apis/apiserver/install - pkg/apis/apiserver/install
- pkg/apis/apiserver/v1alpha1 - pkg/apis/apiserver/v1alpha1
- pkg/apis/audit
- pkg/authentication/authenticator - pkg/authentication/authenticator
- pkg/authentication/serviceaccount - pkg/authentication/serviceaccount
- pkg/authentication/user - pkg/authentication/user
@ -338,7 +314,7 @@ imports:
- pkg/util/feature - pkg/util/feature
- pkg/util/flag - pkg/util/flag
- name: k8s.io/kubernetes - name: k8s.io/kubernetes
version: d3ada0119e776222f11ec7945e6d860061339aad version: d3faa3f8f2e85c8089e80a661955626ae24abf80
subpackages: subpackages:
- cmd/kubeadm/app/apis/kubeadm - cmd/kubeadm/app/apis/kubeadm
- federation/apis/federation - federation/apis/federation

@ -14,13 +14,13 @@ import:
- package: github.com/imdario/mergo - package: github.com/imdario/mergo
version: 6633656539c1639d9d78127b7d47c622b5d7b6dc version: 6633656539c1639d9d78127b7d47c622b5d7b6dc
- package: github.com/Masterminds/sprig - package: github.com/Masterminds/sprig
version: ^2.12 version: ^2.13
- package: github.com/ghodss/yaml - package: github.com/ghodss/yaml
- package: github.com/Masterminds/semver - package: github.com/Masterminds/semver
version: ~1.3.1 version: ~1.3.1
- package: github.com/technosophos/moniker - package: github.com/technosophos/moniker
- package: github.com/golang/protobuf - package: github.com/golang/protobuf
version: 2bba0603135d7d7f5cb73b2125beeda19c09f4ef version: 4bd1920723d7b7c925de087aa32e2187708897f7
subpackages: subpackages:
- proto - proto
- ptypes/any - ptypes/any
@ -38,8 +38,6 @@ import:
- package: github.com/gobwas/glob - package: github.com/gobwas/glob
version: ^0.2.1 version: ^0.2.1
- package: github.com/evanphx/json-patch - package: github.com/evanphx/json-patch
- package: github.com/facebookgo/atomicfile
- package: github.com/facebookgo/symwalk
- package: github.com/BurntSushi/toml - package: github.com/BurntSushi/toml
version: ~0.3.0 version: ~0.3.0
- package: github.com/naoina/go-stringutil - package: github.com/naoina/go-stringutil
@ -56,7 +54,7 @@ import:
# hacks for kubernetes v1.7 # hacks for kubernetes v1.7
- package: cloud.google.com/go - package: cloud.google.com/go
- package: github.com/Azure/go-autorest - package: github.com/Azure/go-autorest
version: d7c034a8af24eda120dd6460bfcd6d9ed14e43ca version: v8.0.0
- package: github.com/dgrijalva/jwt-go - package: github.com/dgrijalva/jwt-go
- package: github.com/docker/spdystream - package: github.com/docker/spdystream
- package: github.com/go-openapi/analysis - package: github.com/go-openapi/analysis
@ -81,7 +79,6 @@ import:
ignore: ignore:
- k8s.io/client-go - k8s.io/client-go
- k8s.io/apimachinery - k8s.io/apimachinery
testImports: testImports:
- package: github.com/stretchr/testify - package: github.com/stretchr/testify
version: ^1.1.4 version: ^1.1.4

@ -16,12 +16,26 @@ limitations under the License.
package chartutil package chartutil
import ( import (
"fmt"
"runtime"
"k8s.io/apimachinery/pkg/version" "k8s.io/apimachinery/pkg/version"
tversion "k8s.io/helm/pkg/proto/hapi/version" tversion "k8s.io/helm/pkg/proto/hapi/version"
) )
// DefaultVersionSet is the default version set, which includes only Core V1 ("v1"). var (
var DefaultVersionSet = NewVersionSet("v1") // DefaultVersionSet is the default version set, which includes only Core V1 ("v1").
DefaultVersionSet = NewVersionSet("v1")
// DefaultKubeVersion is the default kubernetes version
DefaultKubeVersion = &version.Info{
Major: "1",
Minor: "7",
GoVersion: runtime.Version(),
Compiler: runtime.Compiler,
Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH),
}
)
// Capabilities describes the capabilities of the Kubernetes cluster that Tiller is attached to. // Capabilities describes the capabilities of the Kubernetes cluster that Tiller is attached to.
type Capabilities struct { type Capabilities struct {

@ -183,7 +183,7 @@ func ToYaml(v interface{}) string {
// This is not a general-purpose YAML parser, and will not parse all valid // This is not a general-purpose YAML parser, and will not parse all valid
// YAML documents. Additionally, because its intended use is within templates // YAML documents. Additionally, because its intended use is within templates
// it tolerates errors. It will insert the returned error message string into // it tolerates errors. It will insert the returned error message string into
// m["error"] in the returned map. // m["Error"] in the returned map.
func FromYaml(str string) map[string]interface{} { func FromYaml(str string) map[string]interface{} {
m := map[string]interface{}{} m := map[string]interface{}{}
@ -225,7 +225,7 @@ func ToJson(v interface{}) string {
// This is not a general-purpose JSON parser, and will not parse all valid // This is not a general-purpose JSON parser, and will not parse all valid
// YAML documents. Additionally, because its intended use is within templates // YAML documents. Additionally, because its intended use is within templates
// it tolerates errors. It will insert the returned error message string into // it tolerates errors. It will insert the returned error message string into
// m["error"] in the returned map. // m["Error"] in the returned map.
func FromJson(str string) map[string]interface{} { func FromJson(str string) map[string]interface{} {
m := map[string]interface{}{} m := map[string]interface{}{}

@ -28,7 +28,6 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/facebookgo/symwalk"
"github.com/golang/protobuf/ptypes/any" "github.com/golang/protobuf/ptypes/any"
"k8s.io/helm/pkg/ignore" "k8s.io/helm/pkg/ignore"
@ -244,7 +243,7 @@ func LoadDir(dir string) (*chart.Chart, error) {
files := []*BufferedFile{} files := []*BufferedFile{}
topdir += string(filepath.Separator) topdir += string(filepath.Separator)
err = symwalk.Walk(topdir, func(name string, fi os.FileInfo, err error) error { err = filepath.Walk(topdir, func(name string, fi os.FileInfo, err error) error {
n := strings.TrimPrefix(name, topdir) n := strings.TrimPrefix(name, topdir)
// Normalize to / since it will also work on Windows // Normalize to / since it will also work on Windows

@ -23,6 +23,7 @@ import (
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
"k8s.io/helm/pkg/proto/hapi/chart" "k8s.io/helm/pkg/proto/hapi/chart"
"k8s.io/helm/pkg/version"
) )
const ( const (
@ -230,7 +231,7 @@ func getAliasDependency(charts []*chart.Chart, aliasChart *Dependency) *chart.Ch
if existingChart.Metadata.Name != aliasChart.Name { if existingChart.Metadata.Name != aliasChart.Name {
continue continue
} }
if existingChart.Metadata.Version != aliasChart.Version { if !version.IsCompatibleRange(aliasChart.Version, existingChart.Metadata.Version) {
continue continue
} }
chartFound = *existingChart chartFound = *existingChart
@ -266,7 +267,7 @@ func ProcessRequirementsEnabled(c *chart.Chart, v *chart.Config) error {
for _, existingDependency := range c.Dependencies { for _, existingDependency := range c.Dependencies {
var dependencyFound bool var dependencyFound bool
for _, req := range reqs.Dependencies { for _, req := range reqs.Dependencies {
if existingDependency.Metadata.Name == req.Name && existingDependency.Metadata.Version == req.Version { if existingDependency.Metadata.Name == req.Name && version.IsCompatibleRange(req.Version, existingDependency.Metadata.Version) {
dependencyFound = true dependencyFound = true
break break
} }

@ -21,6 +21,7 @@ import (
"strconv" "strconv"
"k8s.io/helm/pkg/proto/hapi/chart" "k8s.io/helm/pkg/proto/hapi/chart"
"k8s.io/helm/pkg/version"
) )
func TestLoadRequirements(t *testing.T) { func TestLoadRequirements(t *testing.T) {
@ -347,11 +348,24 @@ func TestGetAliasDependency(t *testing.T) {
t.Fatalf("Dependency chart name should be %s but got %s", req.Dependencies[0].Name, aliasChart.Metadata.Name) t.Fatalf("Dependency chart name should be %s but got %s", req.Dependencies[0].Name, aliasChart.Metadata.Name)
} }
if req.Dependencies[0].Version != "" {
if !version.IsCompatibleRange(req.Dependencies[0].Version, aliasChart.Metadata.Version) {
t.Fatalf("Dependency chart version is not in the compatible range")
}
}
// Failure case // Failure case
req.Dependencies[0].Name = "something-else" req.Dependencies[0].Name = "something-else"
if aliasChart := getAliasDependency(c.Dependencies, req.Dependencies[0]); aliasChart != nil { if aliasChart := getAliasDependency(c.Dependencies, req.Dependencies[0]); aliasChart != nil {
t.Fatalf("expected no chart but got %s", aliasChart.Metadata.Name) t.Fatalf("expected no chart but got %s", aliasChart.Metadata.Name)
} }
req.Dependencies[0].Version = "something else which is not in the compatible range"
if version.IsCompatibleRange(req.Dependencies[0].Version, aliasChart.Metadata.Version) {
t.Fatalf("Dependency chart version which is not in the compatible range should cause a failure other than a success ")
}
} }
func TestDependentChartAliases(t *testing.T) { func TestDependentChartAliases(t *testing.T) {

@ -6,6 +6,8 @@ metadata:
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
namespace: "{{ .Release.Namespace }}" namespace: "{{ .Release.Namespace }}"
release-name: "{{ .Release.Name }}" release-name: "{{ .Release.Name }}"
kube-version/major: "{{ .Capabilities.KubeVersion.Major }}"
kube-version/minor: "{{ .Capabilities.KubeVersion.Minor }}"
spec: spec:
type: {{ .Values.service.type }} type: {{ .Values.service.type }}
ports: ports:

@ -157,6 +157,9 @@ func (c *Client) Get(namespace string, reader io.Reader) (string, error) {
if err != nil { if err != nil {
return "", err return "", err
} }
var objPods = make(map[string][]api.Pod)
missing := []string{} missing := []string{}
err = perform(infos, func(info *resource.Info) error { err = perform(infos, func(info *resource.Info) error {
c.Log("Doing get for %s: %q", info.Mapping.GroupVersionKind.Kind, info.Name) c.Log("Doing get for %s: %q", info.Mapping.GroupVersionKind.Kind, info.Name)
@ -171,12 +174,26 @@ func (c *Client) Get(namespace string, reader io.Reader) (string, error) {
gvk := info.ResourceMapping().GroupVersionKind gvk := info.ResourceMapping().GroupVersionKind
vk := gvk.Version + "/" + gvk.Kind vk := gvk.Version + "/" + gvk.Kind
objs[vk] = append(objs[vk], info.Object) objs[vk] = append(objs[vk], info.Object)
//Get the relation pods
objPods, err = c.getSelectRelationPod(info, objPods)
if err != nil {
c.Log("Warning: get the relation pod is failed, err:%s", err.Error())
}
return nil return nil
}) })
if err != nil { if err != nil {
return "", err return "", err
} }
//here, we will add the objPods to the objs
for key, podItems := range objPods {
for i := range podItems {
objs[key+"(related)"] = append(objs[key+"(related)"], &podItems[i])
}
}
// Ok, now we have all the objects grouped by types (say, by v1/Pod, v1/Service, etc.), so // Ok, now we have all the objects grouped by types (say, by v1/Pod, v1/Service, etc.), so
// spin through them and print them. Printer is cool since it prints the header only when // spin through them and print them. Printer is cool since it prints the header only when
// an object type changes, so we can just rely on that. Problem is it doesn't seem to keep // an object type changes, so we can just rely on that. Problem is it doesn't seem to keep
@ -628,3 +645,67 @@ func (c *Client) watchPodUntilComplete(timeout time.Duration, info *resource.Inf
return err return err
} }
//get an kubernetes resources's relation pods
// kubernetes resource used select labels to relate pods
func (c *Client) getSelectRelationPod(info *resource.Info, objPods map[string][]api.Pod) (map[string][]api.Pod, error) {
if info == nil {
return objPods, nil
}
c.Log("get relation pod of object: %s/%s/%s", info.Namespace, info.Mapping.GroupVersionKind.Kind, info.Name)
versioned, err := c.AsVersionedObject(info.Object)
if runtime.IsNotRegisteredError(err) {
return objPods, nil
}
if err != nil {
return objPods, err
}
// We can ignore this error because it will only error if it isn't a type that doesn't
// have pods. In that case, we don't care
selector, _ := getSelectorFromObject(versioned)
selectorString := labels.Set(selector).AsSelector().String()
// If we have an empty selector, this likely is a service or config map, so bail out now
if selectorString == "" {
return objPods, nil
}
client, _ := c.ClientSet()
pods, err := client.Core().Pods(info.Namespace).List(metav1.ListOptions{
FieldSelector: fields.Everything().String(),
LabelSelector: labels.Set(selector).AsSelector().String(),
})
if err != nil {
return objPods, err
}
for _, pod := range pods.Items {
if pod.APIVersion == "" {
pod.APIVersion = "v1"
}
if pod.Kind == "" {
pod.Kind = "Pod"
}
vk := pod.GroupVersionKind().Version + "/" + pod.GroupVersionKind().Kind
if !isFoundPod(objPods[vk], pod) {
objPods[vk] = append(objPods[vk], pod)
}
}
return objPods, nil
}
func isFoundPod(podItem []api.Pod, pod api.Pod) bool {
for _, value := range podItem {
if (value.Namespace == pod.Namespace) && (value.Name == pod.Name) {
return true
}
}
return false
}

@ -122,22 +122,22 @@ func (c *Client) waitForResources(timeout time.Duration, created Result) error {
services = append(services, *svc) services = append(services, *svc)
} }
} }
isReady := podsReady(pods) && servicesReady(services) && volumesReady(pvc) && deploymentsReady(deployments) isReady := c.podsReady(pods) && c.servicesReady(services) && c.volumesReady(pvc) && c.deploymentsReady(deployments)
c.Log("resources ready: %v", isReady)
return isReady, nil return isReady, nil
}) })
} }
func podsReady(pods []v1.Pod) bool { func (c *Client) podsReady(pods []v1.Pod) bool {
for _, pod := range pods { for _, pod := range pods {
if !podutil.IsPodReady(&pod) { if !podutil.IsPodReady(&pod) {
c.Log("Pod is not ready: %s/%s", pod.GetNamespace(), pod.GetName())
return false return false
} }
} }
return true return true
} }
func servicesReady(svc []v1.Service) bool { func (c *Client) servicesReady(svc []v1.Service) bool {
for _, s := range svc { for _, s := range svc {
// ExternalName Services are external to cluster so helm shouldn't be checking to see if they're 'ready' (i.e. have an IP Set) // ExternalName Services are external to cluster so helm shouldn't be checking to see if they're 'ready' (i.e. have an IP Set)
if s.Spec.Type == v1.ServiceTypeExternalName { if s.Spec.Type == v1.ServiceTypeExternalName {
@ -146,28 +146,32 @@ func servicesReady(svc []v1.Service) bool {
// Make sure the service is not explicitly set to "None" before checking the IP // Make sure the service is not explicitly set to "None" before checking the IP
if s.Spec.ClusterIP != v1.ClusterIPNone && !helper.IsServiceIPSet(&s) { if s.Spec.ClusterIP != v1.ClusterIPNone && !helper.IsServiceIPSet(&s) {
c.Log("Service is not ready: %s/%s", s.GetNamespace(), s.GetName())
return false return false
} }
// This checks if the service has a LoadBalancer and that balancer has an Ingress defined // This checks if the service has a LoadBalancer and that balancer has an Ingress defined
if s.Spec.Type == v1.ServiceTypeLoadBalancer && s.Status.LoadBalancer.Ingress == nil { if s.Spec.Type == v1.ServiceTypeLoadBalancer && s.Status.LoadBalancer.Ingress == nil {
c.Log("Service is not ready: %s/%s", s.GetNamespace(), s.GetName())
return false return false
} }
} }
return true return true
} }
func volumesReady(vols []v1.PersistentVolumeClaim) bool { func (c *Client) volumesReady(vols []v1.PersistentVolumeClaim) bool {
for _, v := range vols { for _, v := range vols {
if v.Status.Phase != v1.ClaimBound { if v.Status.Phase != v1.ClaimBound {
c.Log("PersistentVolumeClaim is not ready: %s/%s", v.GetNamespace(), v.GetName())
return false return false
} }
} }
return true return true
} }
func deploymentsReady(deployments []deployment) bool { func (c *Client) deploymentsReady(deployments []deployment) bool {
for _, v := range deployments { for _, v := range deployments {
if !(v.replicaSets.Status.ReadyReplicas >= *v.deployment.Spec.Replicas-deploymentutil.MaxUnavailable(*v.deployment)) { if !(v.replicaSets.Status.ReadyReplicas >= *v.deployment.Spec.Replicas-deploymentutil.MaxUnavailable(*v.deployment)) {
c.Log("Deployment is not ready: %s/%s", v.deployment.GetNamespace(), v.deployment.GetName())
return false return false
} }
} }

@ -68,7 +68,7 @@ func TestBadChart(t *testing.T) {
func TestInvalidYaml(t *testing.T) { func TestInvalidYaml(t *testing.T) {
m := All(badYamlFileDir).Messages m := All(badYamlFileDir).Messages
if len(m) != 1 { if len(m) != 1 {
t.Errorf("All didn't fail with expected errors, got %#v", m) t.Fatalf("All didn't fail with expected errors, got %#v", m)
} }
if !strings.Contains(m[0].Err.Error(), "deliberateSyntaxError") { if !strings.Contains(m[0].Err.Error(), "deliberateSyntaxError") {
t.Errorf("All didn't have the error for deliberateSyntaxError") t.Errorf("All didn't have the error for deliberateSyntaxError")
@ -78,7 +78,7 @@ func TestInvalidYaml(t *testing.T) {
func TestBadValues(t *testing.T) { func TestBadValues(t *testing.T) {
m := All(badValuesFileDir).Messages m := All(badValuesFileDir).Messages
if len(m) != 1 { if len(m) != 1 {
t.Errorf("All didn't fail with expected errors, got %#v", m) t.Fatalf("All didn't fail with expected errors, got %#v", m)
} }
if !strings.Contains(m[0].Err.Error(), "cannot unmarshal") { if !strings.Contains(m[0].Err.Error(), "cannot unmarshal") {
t.Errorf("All didn't have the error for invalid key format: %s", m[0].Err) t.Errorf("All didn't have the error for invalid key format: %s", m[0].Err)

@ -21,10 +21,8 @@ import (
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
"runtime"
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
"k8s.io/apimachinery/pkg/version"
"k8s.io/helm/pkg/chartutil" "k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/engine" "k8s.io/helm/pkg/engine"
"k8s.io/helm/pkg/lint/support" "k8s.io/helm/pkg/lint/support"
@ -55,14 +53,8 @@ func Templates(linter *support.Linter) {
options := chartutil.ReleaseOptions{Name: "testRelease", Time: timeconv.Now(), Namespace: "testNamespace"} options := chartutil.ReleaseOptions{Name: "testRelease", Time: timeconv.Now(), Namespace: "testNamespace"}
caps := &chartutil.Capabilities{ caps := &chartutil.Capabilities{
APIVersions: chartutil.DefaultVersionSet, APIVersions: chartutil.DefaultVersionSet,
KubeVersion: &version.Info{ KubeVersion: chartutil.DefaultKubeVersion,
Major: "1",
Minor: "7",
GoVersion: runtime.Version(),
Compiler: runtime.Compiler,
Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH),
},
TillerVersion: tversion.GetVersionProto(), TillerVersion: tversion.GetVersionProto(),
} }
valuesToRender, err := chartutil.ToRenderValuesCaps(chart, chart.Values, options, caps) valuesToRender, err := chartutil.ToRenderValuesCaps(chart, chart.Values, options, caps)

@ -23,7 +23,6 @@ import (
"os" "os"
"time" "time"
"github.com/facebookgo/atomicfile"
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
) )
@ -135,20 +134,9 @@ func (r *RepoFile) Remove(name string) bool {
// WriteFile writes a repositories file to the given path. // WriteFile writes a repositories file to the given path.
func (r *RepoFile) WriteFile(path string, perm os.FileMode) error { func (r *RepoFile) WriteFile(path string, perm os.FileMode) error {
f, err := atomicfile.New(path, perm)
if err != nil {
return err
}
data, err := yaml.Marshal(r) data, err := yaml.Marshal(r)
if err != nil { if err != nil {
return err return err
} }
return ioutil.WriteFile(path, data, perm)
_, err = f.File.Write(data)
if err != nil {
return err
}
return f.Close()
} }

@ -201,18 +201,10 @@ func TestWriteFile(t *testing.T) {
t.Errorf("failed to create test-file (%v)", err) t.Errorf("failed to create test-file (%v)", err)
} }
defer os.Remove(repoFile.Name()) defer os.Remove(repoFile.Name())
if err := sampleRepository.WriteFile(repoFile.Name(), 744); err != nil {
fileMode := os.FileMode(0744)
if err := sampleRepository.WriteFile(repoFile.Name(), fileMode); err != nil {
t.Errorf("failed to write file (%v)", err) t.Errorf("failed to write file (%v)", err)
} }
info, _ := os.Stat(repoFile.Name())
mode := info.Mode()
if mode != fileMode {
t.Errorf("incorrect file mode: %s (expected %s)", mode, fileMode)
}
repos, err := LoadRepositoriesFile(repoFile.Name()) repos, err := LoadRepositoriesFile(repoFile.Name())
if err != nil { if err != nil {
t.Errorf("failed to load file (%v)", err) t.Errorf("failed to load file (%v)", err)

@ -20,6 +20,8 @@ import (
"sort" "sort"
"strconv" "strconv"
"github.com/golang/protobuf/proto"
rspb "k8s.io/helm/pkg/proto/hapi/release" rspb "k8s.io/helm/pkg/proto/hapi/release"
) )
@ -129,5 +131,5 @@ func newRecord(key string, rls *rspb.Release) *record {
lbs.set("STATUS", rspb.Status_Code_name[int32(rls.Info.Status.Code)]) lbs.set("STATUS", rspb.Status_Code_name[int32(rls.Info.Status.Code)])
lbs.set("VERSION", strconv.Itoa(int(rls.Version))) lbs.set("VERSION", strconv.Itoa(int(rls.Version)))
return &record{key: key, lbs: lbs, rls: rls} return &record{key: key, lbs: lbs, rls: proto.Clone(rls).(*rspb.Release)}
} }

@ -32,6 +32,7 @@ var InstallOrder SortOrder = []string{
"LimitRange", "LimitRange",
"Secret", "Secret",
"ConfigMap", "ConfigMap",
"StorageClass",
"PersistentVolume", "PersistentVolume",
"PersistentVolumeClaim", "PersistentVolumeClaim",
"ServiceAccount", "ServiceAccount",
@ -74,6 +75,7 @@ var UninstallOrder SortOrder = []string{
"ServiceAccount", "ServiceAccount",
"PersistentVolumeClaim", "PersistentVolumeClaim",
"PersistentVolume", "PersistentVolume",
"StorageClass",
"ConfigMap", "ConfigMap",
"Secret", "Secret",
"LimitRange", "LimitRange",
@ -116,8 +118,12 @@ func (k *kindSorter) Less(i, j int) bool {
b := k.manifests[j] b := k.manifests[j]
first, aok := k.ordering[a.Head.Kind] first, aok := k.ordering[a.Head.Kind]
second, bok := k.ordering[b.Head.Kind] second, bok := k.ordering[b.Head.Kind]
// if same kind (including unknown) sub sort alphanumeric
if first == second { if first == second {
// same kind (including unknown) so sub sort alphanumeric // if both are unknown and of different kind sort by kind alphabetically
if !aok && !bok && a.Head.Kind != b.Head.Kind {
return a.Head.Kind < b.Head.Kind
}
return a.Name < b.Name return a.Name < b.Name
} }
// unknown kind is last // unknown kind is last

@ -49,6 +49,10 @@ func TestKindSorter(t *testing.T) {
Name: "r", Name: "r",
Head: &util.SimpleHead{Kind: "Deployment"}, Head: &util.SimpleHead{Kind: "Deployment"},
}, },
{
Name: "1",
Head: &util.SimpleHead{Kind: "StorageClass"},
},
{ {
Name: "!", Name: "!",
Head: &util.SimpleHead{Kind: "HonkyTonkSet"}, Head: &util.SimpleHead{Kind: "HonkyTonkSet"},
@ -128,8 +132,8 @@ func TestKindSorter(t *testing.T) {
order SortOrder order SortOrder
expected string expected string
}{ }{
{"install", InstallOrder, "abcdefghijklmnopqrstuvw!"}, {"install", InstallOrder, "abcde1fghijklmnopqrstuvw!"},
{"uninstall", UninstallOrder, "wvmutsrqponlkjihgfedcba!"}, {"uninstall", UninstallOrder, "wvmutsrqponlkjihgf1edcba!"},
} { } {
var buf bytes.Buffer var buf bytes.Buffer
t.Run(test.description, func(t *testing.T) { t.Run(test.description, func(t *testing.T) {
@ -175,7 +179,7 @@ func TestKindSorterSubSort(t *testing.T) {
Head: &util.SimpleHead{Kind: "ClusterRoleBinding"}, Head: &util.SimpleHead{Kind: "ClusterRoleBinding"},
}, },
{ {
Name: "u3", Name: "u2",
Head: &util.SimpleHead{Kind: "Unknown"}, Head: &util.SimpleHead{Kind: "Unknown"},
}, },
{ {
@ -183,8 +187,8 @@ func TestKindSorterSubSort(t *testing.T) {
Head: &util.SimpleHead{Kind: "Unknown"}, Head: &util.SimpleHead{Kind: "Unknown"},
}, },
{ {
Name: "u2", Name: "t3",
Head: &util.SimpleHead{Kind: "Unknown"}, Head: &util.SimpleHead{Kind: "Unknown2"},
}, },
} }
for _, test := range []struct { for _, test := range []struct {
@ -193,7 +197,7 @@ func TestKindSorterSubSort(t *testing.T) {
expected string expected string
}{ }{
// expectation is sorted by kind (unknown is last) and then sub sorted alphabetically within each group // expectation is sorted by kind (unknown is last) and then sub sorted alphabetically within each group
{"cm,clusterRole,clusterRoleBinding,Unknown", InstallOrder, "01Aa!zu1u2u3"}, {"cm,clusterRole,clusterRoleBinding,Unknown,Unknown2", InstallOrder, "01Aa!zu1u2t3"},
} { } {
var buf bytes.Buffer var buf bytes.Buffer
t.Run(test.description, func(t *testing.T) { t.Run(test.description, func(t *testing.T) {

@ -155,7 +155,7 @@ func (s *ReleaseServer) performUpdate(originalRelease, updatedRelease *release.R
updatedRelease.Info.Status.Code = release.Status_FAILED updatedRelease.Info.Status.Code = release.Status_FAILED
updatedRelease.Info.Description = msg updatedRelease.Info.Description = msg
s.recordRelease(originalRelease, true) s.recordRelease(originalRelease, true)
s.recordRelease(updatedRelease, false) s.recordRelease(updatedRelease, true)
return res, err return res, err
} }

@ -20,6 +20,8 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/golang/protobuf/proto"
"k8s.io/helm/pkg/helm" "k8s.io/helm/pkg/helm"
"k8s.io/helm/pkg/proto/hapi/chart" "k8s.io/helm/pkg/proto/hapi/chart"
"k8s.io/helm/pkg/proto/hapi/release" "k8s.io/helm/pkg/proto/hapi/release"
@ -59,10 +61,7 @@ func TestUpdateRelease(t *testing.T) {
t.Errorf("Expected release namespace '%s', got '%s'.", rel.Namespace, res.Release.Namespace) t.Errorf("Expected release namespace '%s', got '%s'.", rel.Namespace, res.Release.Namespace)
} }
updated, err := rs.env.Releases.Get(res.Release.Name, res.Release.Version) updated := compareStoredAndReturnedRelease(t, *rs, *res)
if err != nil {
t.Errorf("Expected release for %s (%v).", res.Release.Name, rs.env.Releases)
}
if len(updated.Hooks) != 1 { if len(updated.Hooks) != 1 {
t.Fatalf("Expected 1 hook, got %d", len(updated.Hooks)) t.Fatalf("Expected 1 hook, got %d", len(updated.Hooks))
@ -79,8 +78,8 @@ func TestUpdateRelease(t *testing.T) {
t.Errorf("Expected event 0 to be pre upgrade") t.Errorf("Expected event 0 to be pre upgrade")
} }
if len(res.Release.Manifest) == 0 { if len(updated.Manifest) == 0 {
t.Errorf("No manifest returned: %v", res.Release) t.Errorf("Expected manifest in %v", res)
} }
if res.Release.Config == nil { if res.Release.Config == nil {
@ -89,12 +88,8 @@ func TestUpdateRelease(t *testing.T) {
t.Errorf("Expected release values %q, got %q", rel.Config.Raw, res.Release.Config.Raw) t.Errorf("Expected release values %q, got %q", rel.Config.Raw, res.Release.Config.Raw)
} }
if len(updated.Manifest) == 0 {
t.Errorf("Expected manifest in %v", res)
}
if !strings.Contains(updated.Manifest, "---\n# Source: hello/templates/hello\nhello: world") { if !strings.Contains(updated.Manifest, "---\n# Source: hello/templates/hello\nhello: world") {
t.Errorf("unexpected output: %s", rel.Manifest) t.Errorf("unexpected output: %s", updated.Manifest)
} }
if res.Release.Version != 2 { if res.Release.Version != 2 {
@ -167,6 +162,7 @@ func TestUpdateRelease_ReuseValues(t *testing.T) {
if res.Release.Config != nil && res.Release.Config.Raw != expect { if res.Release.Config != nil && res.Release.Config.Raw != expect {
t.Errorf("Expected request config to be %q, got %q", expect, res.Release.Config.Raw) t.Errorf("Expected request config to be %q, got %q", expect, res.Release.Config.Raw)
} }
compareStoredAndReturnedRelease(t, *rs, *res)
} }
func TestUpdateRelease_ResetReuseValues(t *testing.T) { func TestUpdateRelease_ResetReuseValues(t *testing.T) {
@ -196,6 +192,7 @@ func TestUpdateRelease_ResetReuseValues(t *testing.T) {
if res.Release.Config != nil && res.Release.Config.Raw != "" { if res.Release.Config != nil && res.Release.Config.Raw != "" {
t.Errorf("Expected chart config to be empty, got %q", res.Release.Config.Raw) t.Errorf("Expected chart config to be empty, got %q", res.Release.Config.Raw)
} }
compareStoredAndReturnedRelease(t, *rs, *res)
} }
func TestUpdateReleaseFailure(t *testing.T) { func TestUpdateReleaseFailure(t *testing.T) {
@ -204,6 +201,7 @@ func TestUpdateReleaseFailure(t *testing.T) {
rel := releaseStub() rel := releaseStub()
rs.env.Releases.Create(rel) rs.env.Releases.Create(rel)
rs.env.KubeClient = newUpdateFailingKubeClient() rs.env.KubeClient = newUpdateFailingKubeClient()
rs.Log = t.Logf
req := &services.UpdateReleaseRequest{ req := &services.UpdateReleaseRequest{
Name: rel.Name, Name: rel.Name,
@ -225,6 +223,8 @@ func TestUpdateReleaseFailure(t *testing.T) {
t.Errorf("Expected FAILED release. Got %d", updatedStatus) t.Errorf("Expected FAILED release. Got %d", updatedStatus)
} }
compareStoredAndReturnedRelease(t, *rs, *res)
edesc := "Upgrade \"angry-panda\" failed: Failed update in kube client" edesc := "Upgrade \"angry-panda\" failed: Failed update in kube client"
if got := res.Release.Info.Description; got != edesc { if got := res.Release.Info.Description; got != edesc {
t.Errorf("Expected description %q, got %q", edesc, got) t.Errorf("Expected description %q, got %q", edesc, got)
@ -285,3 +285,16 @@ func TestUpdateReleaseNoChanges(t *testing.T) {
t.Fatalf("Failed updated: %s", err) t.Fatalf("Failed updated: %s", err)
} }
} }
func compareStoredAndReturnedRelease(t *testing.T, rs ReleaseServer, res services.UpdateReleaseResponse) *release.Release {
storedRelease, err := rs.env.Releases.Get(res.Release.Name, res.Release.Version)
if err != nil {
t.Fatalf("Expected release for %s (%v).", res.Release.Name, rs.env.Releases)
}
if !proto.Equal(storedRelease, res.Release) {
t.Errorf("Stored release doesn't match returned Release")
}
return storedRelease
}

Loading…
Cancel
Save