From bc817a1914fb7fd70ee3dfb2c40c2d8f61d1fd18 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Mon, 14 May 2018 11:44:49 -0700 Subject: [PATCH 001/146] replace with a link to the latest releases page This removes a step required every time we release Helm, making it simpler to cut a new release. Signed-off-by: jgleonard --- README.md | 7 +------ docs/release_checklist.md | 25 ------------------------- 2 files changed, 1 insertion(+), 31 deletions(-) diff --git a/README.md b/README.md index fb2e16bce..fc091056e 100644 --- a/README.md +++ b/README.md @@ -32,12 +32,7 @@ Think of it like apt/yum/homebrew for Kubernetes. ## Install -Binary downloads of the Helm client can be found at the following links: - -- [OSX](https://kubernetes-helm.storage.googleapis.com/helm-v2.8.2-darwin-amd64.tar.gz) -- [Linux](https://kubernetes-helm.storage.googleapis.com/helm-v2.8.2-linux-amd64.tar.gz) -- [Linux 32-bit](https://kubernetes-helm.storage.googleapis.com/helm-v2.8.2-linux-386.tar.gz) -- [Windows](https://kubernetes-helm.storage.googleapis.com/helm-v2.8.2-windows-amd64.tar.gz) +Binary downloads of the Helm client can be found on [the latest Releases page](https://github.com/kubernetes/helm/releases/latest). Unpack the `helm` binary and add it to your PATH and you are good to go! diff --git a/docs/release_checklist.md b/docs/release_checklist.md index 26506985c..d678e7748 100644 --- a/docs/release_checklist.md +++ b/docs/release_checklist.md @@ -94,31 +94,6 @@ index 2109a0a..6f5a1a4 100644 BuildMetadata = "unreleased" ``` -The README stores links to the latest release for helm. We want to change the version to the first release candidate which we are releasing (more on that in step 5). - -```shell -$ git diff README.md -diff --git a/README.md b/README.md -index 022afd79..547839e2 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.8.0-darwin-amd64.tar.gz) -+- [Linux](https://kubernetes-helm.storage.googleapis.com/helm-v2.8.0-linux-amd64.tar.gz) -+- [Linux 32-bit](https://kubernetes-helm.storage.googleapis.com/helm-v2.8.0-linux-386.tar.gz) -+- [Windows](https://kubernetes-helm.storage.googleapis.com/helm-v2.8.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`. -``` - For patch releases, the old version number will be the latest patch release, so just bump the patch number, incrementing Z by one. ```shell From 61156e66565aaf5903efabcc5710846989a20f84 Mon Sep 17 00:00:00 2001 From: Rajat Jindal Date: Sat, 12 May 2018 17:37:09 -0700 Subject: [PATCH 002/146] fix lint warning Signed-off-by: jgleonard --- pkg/downloader/manager.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index 89a839b54..9ee1f6f6d 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -99,11 +99,7 @@ func (m *Manager) Build() error { } // Now we need to fetch every package here into charts/ - if err := m.downloadAll(lock.Dependencies); err != nil { - return err - } - - return nil + return m.downloadAll(lock.Dependencies) } // Update updates a local charts directory. From 21cce62d53b7a4f2431455bf70312830b994b429 Mon Sep 17 00:00:00 2001 From: AdamDang Date: Thu, 17 May 2018 00:05:06 +0800 Subject: [PATCH 003/146] Update capabilities.go Signed-off-by: jgleonard --- pkg/chartutil/capabilities.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/chartutil/capabilities.go b/pkg/chartutil/capabilities.go index c87c0368e..d26aa1707 100644 --- a/pkg/chartutil/capabilities.go +++ b/pkg/chartutil/capabilities.go @@ -42,7 +42,7 @@ var ( type Capabilities struct { // List of all supported API versions APIVersions VersionSet - // KubeVerison is the Kubernetes version + // KubeVersion is the Kubernetes version KubeVersion *version.Info // TillerVersion is the Tiller version // From ab9349c425ab232992121b1d4a1c547dfdb0294b Mon Sep 17 00:00:00 2001 From: jgleonard Date: Thu, 1 Nov 2018 14:56:46 -0400 Subject: [PATCH 004/146] add child NOTES.txt rendering Signed-off-by: jgleonard --- pkg/tiller/release_install_test.go | 4 ++-- pkg/tiller/release_server.go | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pkg/tiller/release_install_test.go b/pkg/tiller/release_install_test.go index a244e4b72..73976571e 100644 --- a/pkg/tiller/release_install_test.go +++ b/pkg/tiller/release_install_test.go @@ -291,8 +291,8 @@ func TestInstallRelease_WithChartAndDependencyNotes(t *testing.T) { t.Logf("rel: %v", rel) - if rel.Info.Status.Notes != notesText { - t.Fatalf("Expected '%s', got '%s'", notesText, rel.Info.Status.Notes) + if !strings.Contains(rel.Info.Status.Notes, notesText) || !strings.Contains(rel.Info.Status.Notes, notesText+" child") { + t.Fatalf("Expected '%s', got '%s'", notesText+"\n"+notesText+" child", rel.Info.Status.Notes) } if rel.Info.Description != "Install complete" { diff --git a/pkg/tiller/release_server.go b/pkg/tiller/release_server.go index 1a2b3c4da..e223d9f32 100644 --- a/pkg/tiller/release_server.go +++ b/pkg/tiller/release_server.go @@ -20,7 +20,6 @@ import ( "bytes" "errors" "fmt" - "path" "regexp" "strings" @@ -289,17 +288,18 @@ func (s *ReleaseServer) renderResources(ch *chart.Chart, values chartutil.Values // text file. We have to spin through this map because the file contains path information, so we // look for terminating NOTES.txt. We also remove it from the files so that we don't have to skip // it in the sortHooks. - notes := "" + var notesBuffer bytes.Buffer for k, v := range files { if strings.HasSuffix(k, notesFileSuffix) { - // Only apply the notes if it belongs to the parent chart - // Note: Do not use filePath.Join since it creates a path with \ which is not expected - if k == path.Join(ch.Metadata.Name, "templates", notesFileSuffix) { - notes = v + // If buffer contains data, add newline before adding more + if notesBuffer.Len() > 0 { + notesBuffer.WriteString("\n") } + notesBuffer.WriteString(v) delete(files, k) } } + notes := notesBuffer.String() // Sort hooks, manifests, and partials. Only hooks and manifests are returned, // as partials are not used after renderer.Render. Empty manifests are also From 1518f961af426bfb4ce8f4ef515c4d90b1a475fb Mon Sep 17 00:00:00 2001 From: jgleonard Date: Thu, 1 Nov 2018 14:57:01 -0400 Subject: [PATCH 005/146] fix(helm): add --render-subchart-notes flag to 'helm install' and 'helm upgrade' When 'helm --render-subchart-notes ...' is run, this will include the notes from the subchart when rendered via Tiller. Closes #2751 Signed-off-by: jgleonard --- _proto/hapi/services/tiller.proto | 4 + cmd/helm/install.go | 3 + cmd/helm/upgrade.go | 3 + pkg/helm/client.go | 2 + pkg/helm/option.go | 16 +++ pkg/proto/hapi/services/tiller.pb.go | 176 +++++++++++++++------------ pkg/tiller/release_install.go | 2 +- pkg/tiller/release_install_test.go | 35 +++++- pkg/tiller/release_server.go | 15 ++- pkg/tiller/release_server_test.go | 6 + pkg/tiller/release_update.go | 2 +- pkg/urlutil/urlutil_test.go | 4 +- 12 files changed, 179 insertions(+), 89 deletions(-) diff --git a/_proto/hapi/services/tiller.proto b/_proto/hapi/services/tiller.proto index 8daef0cb3..e54f60581 100644 --- a/_proto/hapi/services/tiller.proto +++ b/_proto/hapi/services/tiller.proto @@ -209,6 +209,8 @@ message UpdateReleaseRequest { bool reuse_values = 10; // Force resource update through delete/recreate if needed. bool force = 11; + // Render subchart notes if enabled + bool subNotes = 12; } // UpdateReleaseResponse is the response to an update request. @@ -273,6 +275,8 @@ message InstallReleaseRequest { bool wait = 9; bool disable_crd_hook = 10; + + bool subNotes = 11; } // InstallReleaseResponse is the response from a release installation. diff --git a/cmd/helm/install.go b/cmd/helm/install.go index d1c24c213..bffb96746 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -129,6 +129,7 @@ type installCmd struct { password string devel bool depUp bool + subNotes bool certFile string keyFile string @@ -209,6 +210,7 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command { 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") + f.BoolVar(&inst.subNotes, "render-subchart-notes", false, "render subchart notes along with the parent") return cmd } @@ -276,6 +278,7 @@ func (i *installCmd) run() error { helm.InstallReuseName(i.replace), helm.InstallDisableHooks(i.disableHooks), helm.InstallDisableCRDHook(i.disableCRDHook), + helm.InstallSubNotes(i.subNotes), helm.InstallTimeout(i.timeout), helm.InstallWait(i.wait)) if err != nil { diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go index 4dd433a39..41a4d7d5c 100644 --- a/cmd/helm/upgrade.go +++ b/cmd/helm/upgrade.go @@ -78,6 +78,7 @@ type upgradeCmd struct { username string password string devel bool + subNotes bool certFile string keyFile string @@ -139,6 +140,7 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command { 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-0'. If --version is set, this is ignored.") + f.BoolVar(&upgrade.subNotes, "render-subchart-notes", false, "render subchart notes along with parent") f.MarkDeprecated("disable-hooks", "use --no-hooks instead") @@ -224,6 +226,7 @@ func (u *upgradeCmd) run() error { helm.UpgradeTimeout(u.timeout), helm.ResetValues(u.resetValues), helm.ReuseValues(u.reuseValues), + helm.UpgradeSubNotes(u.subNotes), helm.UpgradeWait(u.wait)) if err != nil { return fmt.Errorf("UPGRADE FAILED: %v", prettyError(err)) diff --git a/pkg/helm/client.go b/pkg/helm/client.go index 465ca0af8..3d246086f 100644 --- a/pkg/helm/client.go +++ b/pkg/helm/client.go @@ -95,6 +95,7 @@ func (h *Client) InstallReleaseFromChart(chart *chart.Chart, ns string, opts ... req := &reqOpts.instReq req.Chart = chart req.Namespace = ns + req.SubNotes = reqOpts.subNotes req.DryRun = reqOpts.dryRun req.DisableHooks = reqOpts.disableHooks req.DisableCrdHook = reqOpts.disableCRDHook @@ -171,6 +172,7 @@ func (h *Client) UpdateReleaseFromChart(rlsName string, chart *chart.Chart, opts req.DryRun = reqOpts.dryRun req.Name = rlsName req.DisableHooks = reqOpts.disableHooks + req.SubNotes = reqOpts.subNotes req.Recreate = reqOpts.recreate req.Force = reqOpts.force req.ResetValues = reqOpts.resetValues diff --git a/pkg/helm/option.go b/pkg/helm/option.go index 602e1e3a3..045d45c1d 100644 --- a/pkg/helm/option.go +++ b/pkg/helm/option.go @@ -53,6 +53,8 @@ type options struct { disableHooks bool // if set, skip CRD hook only disableCRDHook bool + // if set, render SubChart Notes + subNotes bool // name of release releaseName string // tls.Config to use for rpc if tls enabled @@ -311,6 +313,20 @@ func InstallReuseName(reuse bool) InstallOption { } } +// InstallSubNotes will (if true) instruct Tiller to render SubChart Notes +func InstallSubNotes(enable bool) InstallOption { + return func(opts *options) { + opts.subNotes = enable + } +} + +// UpgradeSubNotes will (if true) instruct Tiller to render SubChart Notes +func UpgradeSubNotes(enable bool) UpdateOption { + return func(opts *options) { + opts.subNotes = enable + } +} + // RollbackDisableHooks will disable hooks for a rollback operation func RollbackDisableHooks(disable bool) RollbackOption { return func(opts *options) { diff --git a/pkg/proto/hapi/services/tiller.pb.go b/pkg/proto/hapi/services/tiller.pb.go index 4d23bcdad..43c8ddcce 100644 --- a/pkg/proto/hapi/services/tiller.pb.go +++ b/pkg/proto/hapi/services/tiller.pb.go @@ -376,6 +376,8 @@ type UpdateReleaseRequest struct { ReuseValues bool `protobuf:"varint,10,opt,name=reuse_values,json=reuseValues" json:"reuse_values,omitempty"` // Force resource update through delete/recreate if needed. Force bool `protobuf:"varint,11,opt,name=force" json:"force,omitempty"` + // Render subchart notes if enabled + SubNotes bool `protobuf:"varint,12,opt,name=subNotes" json:"subNotes,omitempty"` } func (m *UpdateReleaseRequest) Reset() { *m = UpdateReleaseRequest{} } @@ -460,6 +462,13 @@ func (m *UpdateReleaseRequest) GetForce() bool { return false } +func (m *UpdateReleaseRequest) GetSubNotes() bool { + if m != nil { + return m.SubNotes + } + return false +} + // UpdateReleaseResponse is the response to an update request. type UpdateReleaseResponse struct { Release *hapi_release5.Release `protobuf:"bytes,1,opt,name=release" json:"release,omitempty"` @@ -601,6 +610,7 @@ type InstallReleaseRequest struct { // before marking the release as successful. It will wait for as long as timeout Wait bool `protobuf:"varint,9,opt,name=wait" json:"wait,omitempty"` DisableCrdHook bool `protobuf:"varint,10,opt,name=disable_crd_hook,json=disableCrdHook" json:"disable_crd_hook,omitempty"` + SubNotes bool `protobuf:"varint,11,opt,name=subNotes" json:"subNotes,omitempty"` } func (m *InstallReleaseRequest) Reset() { *m = InstallReleaseRequest{} } @@ -678,6 +688,13 @@ func (m *InstallReleaseRequest) GetDisableCrdHook() bool { return false } +func (m *InstallReleaseRequest) GetSubNotes() bool { + if m != nil { + return m.SubNotes + } + return false +} + // InstallReleaseResponse is the response from a release installation. type InstallReleaseResponse struct { Release *hapi_release5.Release `protobuf:"bytes,1,opt,name=release" json:"release,omitempty"` @@ -1376,83 +1393,84 @@ var _ReleaseService_serviceDesc = grpc.ServiceDesc{ func init() { proto.RegisterFile("hapi/services/tiller.proto", fileDescriptor0) } var fileDescriptor0 = []byte{ - // 1235 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x57, 0xdd, 0x6e, 0xe3, 0xc4, - 0x17, 0xaf, 0xf3, 0x9d, 0x93, 0x6e, 0xfe, 0xd9, 0x69, 0xda, 0xba, 0xfe, 0x2f, 0xa8, 0x18, 0xc1, - 0x66, 0x17, 0x36, 0x85, 0xc0, 0x0d, 0x12, 0x42, 0xea, 0x66, 0xa3, 0xb6, 0x50, 0xba, 0x92, 0xb3, - 0x5d, 0x24, 0x04, 0x44, 0x6e, 0x32, 0x69, 0xcd, 0x3a, 0x76, 0xf0, 0x8c, 0xcb, 0xf6, 0x96, 0x3b, - 0xde, 0x8a, 0x77, 0xe0, 0x92, 0x4b, 0x78, 0x10, 0x34, 0x5f, 0xae, 0x27, 0xb5, 0x5b, 0xd3, 0x9b, - 0x78, 0x66, 0xce, 0xf7, 0xef, 0x9c, 0x39, 0x73, 0x02, 0xd6, 0x85, 0xbb, 0xf4, 0xf6, 0x08, 0x8e, - 0x2e, 0xbd, 0x29, 0x26, 0x7b, 0xd4, 0xf3, 0x7d, 0x1c, 0xf5, 0x97, 0x51, 0x48, 0x43, 0xd4, 0x65, - 0xb4, 0xbe, 0xa2, 0xf5, 0x05, 0xcd, 0xda, 0xe2, 0x12, 0xd3, 0x0b, 0x37, 0xa2, 0xe2, 0x57, 0x70, - 0x5b, 0xdb, 0xe9, 0xf3, 0x30, 0x98, 0x7b, 0xe7, 0x92, 0x20, 0x4c, 0x44, 0xd8, 0xc7, 0x2e, 0xc1, - 0xea, 0xab, 0x09, 0x29, 0x9a, 0x17, 0xcc, 0x43, 0x49, 0xf8, 0xbf, 0x46, 0xa0, 0x98, 0xd0, 0x49, - 0x14, 0x07, 0x92, 0xb8, 0xa3, 0x11, 0x09, 0x75, 0x69, 0x4c, 0x34, 0x63, 0x97, 0x38, 0x22, 0x5e, - 0x18, 0xa8, 0xaf, 0xa0, 0xd9, 0x7f, 0x94, 0x60, 0xe3, 0xd8, 0x23, 0xd4, 0x11, 0x82, 0xc4, 0xc1, - 0xbf, 0xc4, 0x98, 0x50, 0xd4, 0x85, 0xaa, 0xef, 0x2d, 0x3c, 0x6a, 0x1a, 0xbb, 0x46, 0xaf, 0xec, - 0x88, 0x0d, 0xda, 0x82, 0x5a, 0x38, 0x9f, 0x13, 0x4c, 0xcd, 0xd2, 0xae, 0xd1, 0x6b, 0x3a, 0x72, - 0x87, 0xbe, 0x82, 0x3a, 0x09, 0x23, 0x3a, 0x39, 0xbb, 0x32, 0xcb, 0xbb, 0x46, 0xaf, 0x3d, 0xf8, - 0xa0, 0x9f, 0x85, 0x53, 0x9f, 0x59, 0x1a, 0x87, 0x11, 0xed, 0xb3, 0x9f, 0xe7, 0x57, 0x4e, 0x8d, - 0xf0, 0x2f, 0xd3, 0x3b, 0xf7, 0x7c, 0x8a, 0x23, 0xb3, 0x22, 0xf4, 0x8a, 0x1d, 0x3a, 0x00, 0xe0, - 0x7a, 0xc3, 0x68, 0x86, 0x23, 0xb3, 0xca, 0x55, 0xf7, 0x0a, 0xa8, 0x7e, 0xc9, 0xf8, 0x9d, 0x26, - 0x51, 0x4b, 0xf4, 0x25, 0xac, 0x0b, 0x48, 0x26, 0xd3, 0x70, 0x86, 0x89, 0x59, 0xdb, 0x2d, 0xf7, - 0xda, 0x83, 0x1d, 0xa1, 0x4a, 0xc1, 0x3f, 0x16, 0xa0, 0x0d, 0xc3, 0x19, 0x76, 0x5a, 0x82, 0x9d, - 0xad, 0x09, 0x7a, 0x04, 0xcd, 0xc0, 0x5d, 0x60, 0xb2, 0x74, 0xa7, 0xd8, 0xac, 0x73, 0x0f, 0xaf, - 0x0f, 0xec, 0x9f, 0xa0, 0xa1, 0x8c, 0xdb, 0x03, 0xa8, 0x89, 0xd0, 0x50, 0x0b, 0xea, 0xa7, 0x27, - 0xdf, 0x9c, 0xbc, 0xfc, 0xee, 0xa4, 0xb3, 0x86, 0x1a, 0x50, 0x39, 0xd9, 0xff, 0x76, 0xd4, 0x31, - 0xd0, 0x43, 0x78, 0x70, 0xbc, 0x3f, 0x7e, 0x35, 0x71, 0x46, 0xc7, 0xa3, 0xfd, 0xf1, 0xe8, 0x45, - 0xa7, 0x64, 0xbf, 0x0b, 0xcd, 0xc4, 0x67, 0x54, 0x87, 0xf2, 0xfe, 0x78, 0x28, 0x44, 0x5e, 0x8c, - 0xc6, 0xc3, 0x8e, 0x61, 0xff, 0x6e, 0x40, 0x57, 0x4f, 0x11, 0x59, 0x86, 0x01, 0xc1, 0x2c, 0x47, - 0xd3, 0x30, 0x0e, 0x92, 0x1c, 0xf1, 0x0d, 0x42, 0x50, 0x09, 0xf0, 0x5b, 0x95, 0x21, 0xbe, 0x66, - 0x9c, 0x34, 0xa4, 0xae, 0xcf, 0xb3, 0x53, 0x76, 0xc4, 0x06, 0x7d, 0x0a, 0x0d, 0x19, 0x3a, 0x31, - 0x2b, 0xbb, 0xe5, 0x5e, 0x6b, 0xb0, 0xa9, 0x03, 0x22, 0x2d, 0x3a, 0x09, 0x9b, 0x7d, 0x00, 0xdb, - 0x07, 0x58, 0x79, 0x22, 0xf0, 0x52, 0x15, 0xc3, 0xec, 0xba, 0x0b, 0xcc, 0x9d, 0x61, 0x76, 0xdd, - 0x05, 0x46, 0x26, 0xd4, 0x65, 0xb9, 0x71, 0x77, 0xaa, 0x8e, 0xda, 0xda, 0x14, 0xcc, 0x9b, 0x8a, - 0x64, 0x5c, 0x59, 0x9a, 0x3e, 0x84, 0x0a, 0xbb, 0x09, 0x5c, 0x4d, 0x6b, 0x80, 0x74, 0x3f, 0x8f, - 0x82, 0x79, 0xe8, 0x70, 0xba, 0x9e, 0xaa, 0xf2, 0x6a, 0xaa, 0x0e, 0xd3, 0x56, 0x87, 0x61, 0x40, - 0x71, 0x40, 0xef, 0xe7, 0xff, 0x31, 0xec, 0x64, 0x68, 0x92, 0x01, 0xec, 0x41, 0x5d, 0xba, 0xc6, - 0xb5, 0xe5, 0xe2, 0xaa, 0xb8, 0xec, 0xbf, 0x4b, 0xd0, 0x3d, 0x5d, 0xce, 0x5c, 0x8a, 0x15, 0xe9, - 0x16, 0xa7, 0x1e, 0x43, 0x95, 0x77, 0x14, 0x89, 0xc5, 0x43, 0xa1, 0x5b, 0xb4, 0x9d, 0x21, 0xfb, - 0x75, 0x04, 0x1d, 0x3d, 0x85, 0xda, 0xa5, 0xeb, 0xc7, 0x98, 0x70, 0x20, 0x12, 0xd4, 0x24, 0x27, - 0x6f, 0x47, 0x8e, 0xe4, 0x40, 0xdb, 0x50, 0x9f, 0x45, 0x57, 0xac, 0x9f, 0xf0, 0x2b, 0xd8, 0x70, - 0x6a, 0xb3, 0xe8, 0xca, 0x89, 0x03, 0xf4, 0x3e, 0x3c, 0x98, 0x79, 0xc4, 0x3d, 0xf3, 0xf1, 0xe4, - 0x22, 0x0c, 0xdf, 0x10, 0x7e, 0x0b, 0x1b, 0xce, 0xba, 0x3c, 0x3c, 0x64, 0x67, 0xc8, 0x62, 0x95, - 0x34, 0x8d, 0xb0, 0x4b, 0xb1, 0x59, 0xe3, 0xf4, 0x64, 0xcf, 0x30, 0xa4, 0xde, 0x02, 0x87, 0x31, - 0xe5, 0x57, 0xa7, 0xec, 0xa8, 0x2d, 0x7a, 0x0f, 0xd6, 0x23, 0x4c, 0x30, 0x9d, 0x48, 0x2f, 0x1b, - 0x5c, 0xb2, 0xc5, 0xcf, 0x5e, 0x0b, 0xb7, 0x10, 0x54, 0x7e, 0x75, 0x3d, 0x6a, 0x36, 0x39, 0x89, - 0xaf, 0x85, 0x58, 0x4c, 0xb0, 0x12, 0x03, 0x25, 0x16, 0x13, 0x2c, 0xc5, 0xba, 0x50, 0x9d, 0x87, - 0xd1, 0x14, 0x9b, 0x2d, 0x4e, 0x13, 0x1b, 0xfb, 0x10, 0x36, 0x57, 0x40, 0xbe, 0x6f, 0xbe, 0xfe, - 0x31, 0x60, 0xcb, 0x09, 0x7d, 0xff, 0xcc, 0x9d, 0xbe, 0x29, 0x90, 0xb1, 0x14, 0xb8, 0xa5, 0xdb, - 0xc1, 0x2d, 0x67, 0x80, 0x9b, 0x2a, 0xc2, 0x8a, 0x56, 0x84, 0x1a, 0xec, 0xd5, 0x7c, 0xd8, 0x6b, - 0x3a, 0xec, 0x0a, 0xd3, 0x7a, 0x0a, 0xd3, 0x04, 0xb0, 0x46, 0x1a, 0xb0, 0xaf, 0x61, 0xfb, 0x46, - 0x94, 0xf7, 0x85, 0xec, 0xcf, 0x12, 0x6c, 0x1e, 0x05, 0x84, 0xba, 0xbe, 0xbf, 0x82, 0x58, 0x52, - 0xcf, 0x46, 0xe1, 0x7a, 0x2e, 0xfd, 0x97, 0x7a, 0x2e, 0x6b, 0x90, 0xab, 0xfc, 0x54, 0x52, 0xf9, - 0x29, 0x54, 0xe3, 0x5a, 0x67, 0xa9, 0xad, 0x74, 0x16, 0xf4, 0x0e, 0x80, 0x28, 0x4a, 0xae, 0x5c, - 0x40, 0xdb, 0xe4, 0x27, 0x27, 0xb2, 0x91, 0xa8, 0x6c, 0x34, 0xb2, 0xb3, 0x91, 0xae, 0xf0, 0x1e, - 0x74, 0x94, 0x3f, 0xd3, 0x68, 0xc6, 0x7d, 0x92, 0x55, 0xde, 0x96, 0xe7, 0xc3, 0x68, 0xc6, 0xbc, - 0xb2, 0x8f, 0x60, 0x6b, 0x15, 0xd4, 0xfb, 0x26, 0xe8, 0x37, 0x03, 0xb6, 0x4f, 0x03, 0x2f, 0x33, - 0x45, 0x59, 0x45, 0x7d, 0x03, 0xb4, 0x52, 0x06, 0x68, 0x5d, 0xa8, 0x2e, 0xe3, 0xe8, 0x1c, 0xcb, - 0x24, 0x88, 0x4d, 0x1a, 0x8d, 0x8a, 0x86, 0x86, 0x3d, 0x01, 0xf3, 0xa6, 0x0f, 0xf7, 0x8c, 0x88, - 0x79, 0x9d, 0xbc, 0x19, 0x4d, 0xf1, 0x3e, 0xd8, 0x1b, 0xf0, 0xf0, 0x00, 0xd3, 0xd7, 0xe2, 0x02, - 0xc9, 0xf0, 0xec, 0x11, 0xa0, 0xf4, 0xe1, 0xb5, 0x3d, 0x79, 0xa4, 0xdb, 0x53, 0x03, 0x94, 0xe2, - 0x57, 0x5c, 0xf6, 0x17, 0x5c, 0xf7, 0xa1, 0x47, 0x68, 0x18, 0x5d, 0xdd, 0x06, 0x5d, 0x07, 0xca, - 0x0b, 0xf7, 0xad, 0x7c, 0x52, 0xd8, 0xd2, 0x3e, 0xe0, 0x1e, 0x24, 0xa2, 0xd2, 0x83, 0xf4, 0x03, - 0x6d, 0x14, 0x7b, 0xa0, 0x7f, 0x00, 0xf4, 0x0a, 0x27, 0xb3, 0xc2, 0x1d, 0x6f, 0x9b, 0x4a, 0x42, - 0x49, 0x2f, 0x49, 0x13, 0xea, 0x53, 0x1f, 0xbb, 0x41, 0xbc, 0x94, 0x69, 0x53, 0x5b, 0xfb, 0x47, - 0xd8, 0xd0, 0xb4, 0x4b, 0x3f, 0x59, 0x3c, 0xe4, 0x5c, 0x6a, 0x67, 0x4b, 0xf4, 0x39, 0xd4, 0xc4, - 0x00, 0xc5, 0x75, 0xb7, 0x07, 0x8f, 0x74, 0xbf, 0xb9, 0x92, 0x38, 0x90, 0x13, 0x97, 0x23, 0x79, - 0x07, 0x7f, 0x35, 0xa0, 0xad, 0x46, 0x02, 0x31, 0xde, 0x21, 0x0f, 0xd6, 0xd3, 0xb3, 0x0f, 0x7a, - 0x92, 0x3f, 0xfd, 0xad, 0x8c, 0xb0, 0xd6, 0xd3, 0x22, 0xac, 0x22, 0x02, 0x7b, 0xed, 0x13, 0x03, - 0x11, 0xe8, 0xac, 0x8e, 0x24, 0xe8, 0x59, 0xb6, 0x8e, 0x9c, 0x19, 0xc8, 0xea, 0x17, 0x65, 0x57, - 0x66, 0xd1, 0x25, 0xaf, 0x19, 0x7d, 0x8e, 0x40, 0x77, 0xaa, 0xd1, 0x47, 0x17, 0x6b, 0xaf, 0x30, - 0x7f, 0x62, 0xf7, 0x67, 0x78, 0xa0, 0xbd, 0x85, 0x28, 0x07, 0xad, 0xac, 0xa9, 0xc4, 0xfa, 0xa8, - 0x10, 0x6f, 0x62, 0x6b, 0x01, 0x6d, 0xbd, 0x49, 0xa1, 0x1c, 0x05, 0x99, 0xef, 0x83, 0xf5, 0x71, - 0x31, 0xe6, 0xc4, 0x1c, 0x81, 0xce, 0x6a, 0x0f, 0xc9, 0xcb, 0x63, 0x4e, 0xbf, 0xcb, 0xcb, 0x63, - 0x5e, 0x6b, 0xb2, 0xd7, 0x90, 0x0b, 0x70, 0xdd, 0x42, 0xd0, 0xe3, 0xdc, 0x84, 0xe8, 0x9d, 0xc7, - 0xea, 0xdd, 0xcd, 0x98, 0x98, 0x58, 0xc2, 0xff, 0x56, 0x5e, 0x63, 0x94, 0x03, 0x4d, 0xf6, 0x68, - 0x62, 0x3d, 0x2b, 0xc8, 0xbd, 0x12, 0x94, 0xec, 0x4a, 0xb7, 0x04, 0xa5, 0xb7, 0xbc, 0x5b, 0x82, - 0x5a, 0x69, 0x70, 0xf6, 0x1a, 0xf2, 0xa0, 0xed, 0xc4, 0x81, 0x34, 0xcd, 0xda, 0x02, 0xca, 0x91, - 0xbe, 0xd9, 0xd5, 0xac, 0x27, 0x05, 0x38, 0xaf, 0xef, 0xf7, 0x73, 0xf8, 0xbe, 0xa1, 0x58, 0xcf, - 0x6a, 0xfc, 0xdf, 0xef, 0x67, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0x5d, 0xc3, 0xd5, 0x55, 0xeb, - 0x0f, 0x00, 0x00, + // 1257 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x57, 0xdf, 0x6f, 0xe3, 0xc4, + 0x13, 0xaf, 0xf3, 0x3b, 0x93, 0x36, 0xdf, 0x74, 0x9b, 0xb6, 0xae, 0xbf, 0x07, 0x2a, 0x46, 0x70, + 0xb9, 0x83, 0x4b, 0x21, 0xf0, 0x82, 0x84, 0x90, 0x7a, 0xb9, 0xa8, 0x2d, 0x94, 0x9c, 0xe4, 0x5c, + 0x0f, 0x09, 0x01, 0x91, 0x9b, 0x6c, 0x5a, 0x73, 0x8e, 0x1d, 0xbc, 0xeb, 0x72, 0x7d, 0xe5, 0x8d, + 0xff, 0x8a, 0xff, 0x83, 0x57, 0xde, 0xf9, 0x13, 0x40, 0xde, 0x1f, 0xae, 0xd7, 0xb5, 0x5b, 0xd3, + 0x97, 0x78, 0x77, 0x67, 0x76, 0x66, 0xf6, 0xf3, 0x99, 0x9d, 0x9d, 0x80, 0x71, 0x69, 0xaf, 0x9c, + 0x03, 0x82, 0x83, 0x2b, 0x67, 0x86, 0xc9, 0x01, 0x75, 0x5c, 0x17, 0x07, 0xfd, 0x55, 0xe0, 0x53, + 0x1f, 0x75, 0x23, 0x59, 0x5f, 0xca, 0xfa, 0x5c, 0x66, 0xec, 0xb0, 0x1d, 0xb3, 0x4b, 0x3b, 0xa0, + 0xfc, 0x97, 0x6b, 0x1b, 0xbb, 0xc9, 0x75, 0xdf, 0x5b, 0x38, 0x17, 0x42, 0xc0, 0x5d, 0x04, 0xd8, + 0xc5, 0x36, 0xc1, 0xf2, 0xab, 0x6c, 0x92, 0x32, 0xc7, 0x5b, 0xf8, 0x42, 0xf0, 0x7f, 0x45, 0x40, + 0x31, 0xa1, 0xd3, 0x20, 0xf4, 0x84, 0x70, 0x4f, 0x11, 0x12, 0x6a, 0xd3, 0x90, 0x28, 0xce, 0xae, + 0x70, 0x40, 0x1c, 0xdf, 0x93, 0x5f, 0x2e, 0x33, 0xff, 0x28, 0xc1, 0xd6, 0xa9, 0x43, 0xa8, 0xc5, + 0x37, 0x12, 0x0b, 0xff, 0x12, 0x62, 0x42, 0x51, 0x17, 0xaa, 0xae, 0xb3, 0x74, 0xa8, 0xae, 0xed, + 0x6b, 0xbd, 0xb2, 0xc5, 0x27, 0x68, 0x07, 0x6a, 0xfe, 0x62, 0x41, 0x30, 0xd5, 0x4b, 0xfb, 0x5a, + 0xaf, 0x69, 0x89, 0x19, 0xfa, 0x0a, 0xea, 0xc4, 0x0f, 0xe8, 0xf4, 0xfc, 0x5a, 0x2f, 0xef, 0x6b, + 0xbd, 0xf6, 0xe0, 0x83, 0x7e, 0x16, 0x4e, 0xfd, 0xc8, 0xd3, 0xc4, 0x0f, 0x68, 0x3f, 0xfa, 0x79, + 0x7e, 0x6d, 0xd5, 0x08, 0xfb, 0x46, 0x76, 0x17, 0x8e, 0x4b, 0x71, 0xa0, 0x57, 0xb8, 0x5d, 0x3e, + 0x43, 0x47, 0x00, 0xcc, 0xae, 0x1f, 0xcc, 0x71, 0xa0, 0x57, 0x99, 0xe9, 0x5e, 0x01, 0xd3, 0x2f, + 0x23, 0x7d, 0xab, 0x49, 0xe4, 0x10, 0x7d, 0x09, 0xeb, 0x1c, 0x92, 0xe9, 0xcc, 0x9f, 0x63, 0xa2, + 0xd7, 0xf6, 0xcb, 0xbd, 0xf6, 0x60, 0x8f, 0x9b, 0x92, 0xf0, 0x4f, 0x38, 0x68, 0x43, 0x7f, 0x8e, + 0xad, 0x16, 0x57, 0x8f, 0xc6, 0x04, 0x3d, 0x82, 0xa6, 0x67, 0x2f, 0x31, 0x59, 0xd9, 0x33, 0xac, + 0xd7, 0x59, 0x84, 0x37, 0x0b, 0xe6, 0x4f, 0xd0, 0x90, 0xce, 0xcd, 0x01, 0xd4, 0xf8, 0xd1, 0x50, + 0x0b, 0xea, 0x67, 0xe3, 0x6f, 0xc6, 0x2f, 0xbf, 0x1b, 0x77, 0xd6, 0x50, 0x03, 0x2a, 0xe3, 0xc3, + 0x6f, 0x47, 0x1d, 0x0d, 0x6d, 0xc2, 0xc6, 0xe9, 0xe1, 0xe4, 0xd5, 0xd4, 0x1a, 0x9d, 0x8e, 0x0e, + 0x27, 0xa3, 0x17, 0x9d, 0x92, 0xf9, 0x2e, 0x34, 0xe3, 0x98, 0x51, 0x1d, 0xca, 0x87, 0x93, 0x21, + 0xdf, 0xf2, 0x62, 0x34, 0x19, 0x76, 0x34, 0xf3, 0x77, 0x0d, 0xba, 0x2a, 0x45, 0x64, 0xe5, 0x7b, + 0x04, 0x47, 0x1c, 0xcd, 0xfc, 0xd0, 0x8b, 0x39, 0x62, 0x13, 0x84, 0xa0, 0xe2, 0xe1, 0xb7, 0x92, + 0x21, 0x36, 0x8e, 0x34, 0xa9, 0x4f, 0x6d, 0x97, 0xb1, 0x53, 0xb6, 0xf8, 0x04, 0x7d, 0x0a, 0x0d, + 0x71, 0x74, 0xa2, 0x57, 0xf6, 0xcb, 0xbd, 0xd6, 0x60, 0x5b, 0x05, 0x44, 0x78, 0xb4, 0x62, 0x35, + 0xf3, 0x08, 0x76, 0x8f, 0xb0, 0x8c, 0x84, 0xe3, 0x25, 0x33, 0x26, 0xf2, 0x6b, 0x2f, 0x31, 0x0b, + 0x26, 0xf2, 0x6b, 0x2f, 0x31, 0xd2, 0xa1, 0x2e, 0xd2, 0x8d, 0x85, 0x53, 0xb5, 0xe4, 0xd4, 0xa4, + 0xa0, 0xdf, 0x36, 0x24, 0xce, 0x95, 0x65, 0xe9, 0x43, 0xa8, 0x44, 0x37, 0x81, 0x99, 0x69, 0x0d, + 0x90, 0x1a, 0xe7, 0x89, 0xb7, 0xf0, 0x2d, 0x26, 0x57, 0xa9, 0x2a, 0xa7, 0xa9, 0x3a, 0x4e, 0x7a, + 0x1d, 0xfa, 0x1e, 0xc5, 0x1e, 0x7d, 0x58, 0xfc, 0xa7, 0xb0, 0x97, 0x61, 0x49, 0x1c, 0xe0, 0x00, + 0xea, 0x22, 0x34, 0x66, 0x2d, 0x17, 0x57, 0xa9, 0x65, 0xfe, 0x53, 0x82, 0xee, 0xd9, 0x6a, 0x6e, + 0x53, 0x2c, 0x45, 0x77, 0x04, 0xf5, 0x18, 0xaa, 0xac, 0xa2, 0x08, 0x2c, 0x36, 0xb9, 0x6d, 0x5e, + 0x76, 0x86, 0xd1, 0xaf, 0xc5, 0xe5, 0xe8, 0x29, 0xd4, 0xae, 0x6c, 0x37, 0xc4, 0x84, 0x01, 0x11, + 0xa3, 0x26, 0x34, 0x59, 0x39, 0xb2, 0x84, 0x06, 0xda, 0x85, 0xfa, 0x3c, 0xb8, 0x8e, 0xea, 0x09, + 0xbb, 0x82, 0x0d, 0xab, 0x36, 0x0f, 0xae, 0xad, 0xd0, 0x43, 0xef, 0xc3, 0xc6, 0xdc, 0x21, 0xf6, + 0xb9, 0x8b, 0xa7, 0x97, 0xbe, 0xff, 0x86, 0xb0, 0x5b, 0xd8, 0xb0, 0xd6, 0xc5, 0xe2, 0x71, 0xb4, + 0x86, 0x8c, 0x28, 0x93, 0x66, 0x01, 0xb6, 0x29, 0xd6, 0x6b, 0x4c, 0x1e, 0xcf, 0x23, 0x0c, 0xa9, + 0xb3, 0xc4, 0x7e, 0x48, 0xd9, 0xd5, 0x29, 0x5b, 0x72, 0x8a, 0xde, 0x83, 0xf5, 0x00, 0x13, 0x4c, + 0xa7, 0x22, 0xca, 0x06, 0xdb, 0xd9, 0x62, 0x6b, 0xaf, 0x79, 0x58, 0x08, 0x2a, 0xbf, 0xda, 0x0e, + 0xd5, 0x9b, 0x4c, 0xc4, 0xc6, 0x7c, 0x5b, 0x48, 0xb0, 0xdc, 0x06, 0x72, 0x5b, 0x48, 0xb0, 0xd8, + 0xd6, 0x85, 0xea, 0xc2, 0x0f, 0x66, 0x58, 0x6f, 0x31, 0x19, 0x9f, 0x44, 0x51, 0x92, 0xf0, 0x7c, + 0xec, 0x53, 0x4c, 0xf4, 0x75, 0x1e, 0xa5, 0x9c, 0x9b, 0xc7, 0xb0, 0x9d, 0x22, 0xe0, 0xa1, 0x5c, + 0xfe, 0xa5, 0xc1, 0x8e, 0xe5, 0xbb, 0xee, 0xb9, 0x3d, 0x7b, 0x53, 0x80, 0xcd, 0x04, 0xf0, 0xa5, + 0xbb, 0x81, 0x2f, 0x67, 0x00, 0x9f, 0x48, 0xd0, 0x8a, 0x92, 0xa0, 0x0a, 0x25, 0xd5, 0x7c, 0x4a, + 0x6a, 0x2a, 0x25, 0x12, 0xef, 0x7a, 0x02, 0xef, 0x18, 0xcc, 0x46, 0x02, 0x4c, 0xf3, 0x6b, 0xd8, + 0xbd, 0x75, 0xca, 0x87, 0x42, 0xf6, 0x77, 0x09, 0xb6, 0x4f, 0x3c, 0x42, 0x6d, 0xd7, 0x4d, 0x21, + 0x16, 0xe7, 0xba, 0x56, 0x38, 0xd7, 0x4b, 0xff, 0x25, 0xd7, 0xcb, 0x0a, 0xe4, 0x92, 0x9f, 0x4a, + 0x82, 0x9f, 0x42, 0xf9, 0xaf, 0x54, 0x9d, 0x5a, 0xaa, 0xea, 0xa0, 0x77, 0x00, 0x78, 0xc2, 0x32, + 0xe3, 0x1c, 0xda, 0x26, 0x5b, 0x19, 0x8b, 0x22, 0x23, 0xd9, 0x68, 0x64, 0xb3, 0x91, 0xcc, 0xfe, + 0x1e, 0x74, 0x64, 0x3c, 0xb3, 0x60, 0xce, 0x62, 0x12, 0x37, 0xa0, 0x2d, 0xd6, 0x87, 0xc1, 0x3c, + 0x8a, 0x4a, 0x49, 0xf7, 0x56, 0x2a, 0xdd, 0x4f, 0x60, 0x27, 0x0d, 0xf8, 0x43, 0xc9, 0xfb, 0x4d, + 0x83, 0xdd, 0x33, 0xcf, 0xc9, 0xa4, 0x2f, 0x2b, 0xe1, 0x6f, 0x01, 0x5a, 0xca, 0x00, 0xb4, 0x0b, + 0xd5, 0x55, 0x18, 0x5c, 0x60, 0x41, 0x10, 0x9f, 0x24, 0x91, 0xaa, 0x28, 0x48, 0x99, 0x53, 0xd0, + 0x6f, 0xc7, 0xf0, 0xc0, 0x13, 0x45, 0x51, 0xc7, 0x6f, 0x4d, 0x93, 0xbf, 0x2b, 0xe6, 0x16, 0x6c, + 0x1e, 0x61, 0xfa, 0x9a, 0x5f, 0x2e, 0x71, 0x3c, 0x73, 0x04, 0x28, 0xb9, 0x78, 0xe3, 0x4f, 0x2c, + 0xa9, 0xfe, 0x64, 0xe3, 0x25, 0xf5, 0xa5, 0x96, 0xf9, 0x05, 0xb3, 0x7d, 0xec, 0x10, 0xea, 0x07, + 0xd7, 0x77, 0x41, 0xd7, 0x81, 0xf2, 0xd2, 0x7e, 0x2b, 0x9e, 0xa2, 0x68, 0x68, 0x1e, 0xb1, 0x08, + 0xe2, 0xad, 0x22, 0x82, 0xe4, 0xc3, 0xae, 0x15, 0x7b, 0xd8, 0x7f, 0x00, 0xf4, 0x0a, 0xc7, 0x3d, + 0xc6, 0x3d, 0x6f, 0xa2, 0x24, 0xa1, 0xa4, 0xa6, 0xab, 0x0e, 0xf5, 0x99, 0x8b, 0x6d, 0x2f, 0x5c, + 0x09, 0xda, 0xe4, 0xd4, 0xfc, 0x11, 0xb6, 0x14, 0xeb, 0x22, 0xce, 0xe8, 0x3c, 0xe4, 0x42, 0x58, + 0x8f, 0x86, 0xe8, 0x73, 0xa8, 0xf1, 0xc6, 0x8b, 0xd9, 0x6e, 0x0f, 0x1e, 0xa9, 0x71, 0x33, 0x23, + 0xa1, 0x27, 0x3a, 0x35, 0x4b, 0xe8, 0x0e, 0xfe, 0x6c, 0x40, 0x5b, 0xb6, 0x12, 0xbc, 0x2d, 0x44, + 0x0e, 0xac, 0x27, 0x7b, 0x26, 0xf4, 0x24, 0xbf, 0x6b, 0x4c, 0xb5, 0xbe, 0xc6, 0xd3, 0x22, 0xaa, + 0xfc, 0x04, 0xe6, 0xda, 0x27, 0x1a, 0x22, 0xd0, 0x49, 0xb7, 0x32, 0xe8, 0x59, 0xb6, 0x8d, 0x9c, + 0xde, 0xc9, 0xe8, 0x17, 0x55, 0x97, 0x6e, 0xd1, 0x15, 0xcb, 0x19, 0xb5, 0xff, 0x40, 0xf7, 0x9a, + 0x51, 0x5b, 0x1e, 0xe3, 0xa0, 0xb0, 0x7e, 0xec, 0xf7, 0x67, 0xd8, 0x50, 0xde, 0x49, 0x94, 0x83, + 0x56, 0x56, 0x37, 0x63, 0x7c, 0x54, 0x48, 0x37, 0xf6, 0xb5, 0x84, 0xb6, 0x5a, 0xa4, 0x50, 0x8e, + 0x81, 0xcc, 0xb7, 0xc3, 0xf8, 0xb8, 0x98, 0x72, 0xec, 0x8e, 0x40, 0x27, 0x5d, 0x43, 0xf2, 0x78, + 0xcc, 0xa9, 0x77, 0x79, 0x3c, 0xe6, 0x95, 0x26, 0x73, 0x0d, 0xd9, 0x00, 0x37, 0x25, 0x04, 0x3d, + 0xce, 0x25, 0x44, 0xad, 0x3c, 0x46, 0xef, 0x7e, 0xc5, 0xd8, 0xc5, 0x0a, 0xfe, 0x97, 0x7a, 0xa9, + 0x51, 0x0e, 0x34, 0xd9, 0x6d, 0x8b, 0xf1, 0xac, 0xa0, 0x76, 0xea, 0x50, 0xa2, 0x2a, 0xdd, 0x71, + 0x28, 0xb5, 0xe4, 0xdd, 0x71, 0xa8, 0x54, 0x81, 0x33, 0xd7, 0x90, 0x03, 0x6d, 0x2b, 0xf4, 0x84, + 0xeb, 0xa8, 0x2c, 0xa0, 0x9c, 0xdd, 0xb7, 0xab, 0x9a, 0xf1, 0xa4, 0x80, 0xe6, 0xcd, 0xfd, 0x7e, + 0x0e, 0xdf, 0x37, 0xa4, 0xea, 0x79, 0x8d, 0xfd, 0x6b, 0xfe, 0xec, 0xdf, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xbd, 0x2a, 0xa3, 0x1f, 0x23, 0x10, 0x00, 0x00, } diff --git a/pkg/tiller/release_install.go b/pkg/tiller/release_install.go index 0b8f4da5b..d7781c0d9 100644 --- a/pkg/tiller/release_install.go +++ b/pkg/tiller/release_install.go @@ -84,7 +84,7 @@ func (s *ReleaseServer) prepareRelease(req *services.InstallReleaseRequest) (*re return nil, err } - hooks, manifestDoc, notesTxt, err := s.renderResources(req.Chart, valuesToRender, caps.APIVersions) + hooks, manifestDoc, notesTxt, err := s.renderResources(req.Chart, valuesToRender, req.SubNotes, caps.APIVersions) if err != nil { // Return a release with partial data so that client can show debugging // information. diff --git a/pkg/tiller/release_install_test.go b/pkg/tiller/release_install_test.go index 73976571e..1d1b08e90 100644 --- a/pkg/tiller/release_install_test.go +++ b/pkg/tiller/release_install_test.go @@ -268,7 +268,7 @@ func TestInstallRelease_WrongTillerVersion(t *testing.T) { } } -func TestInstallRelease_WithChartAndDependencyNotes(t *testing.T) { +func TestInstallRelease_WithChartAndDependencyParentNotes(t *testing.T) { c := helm.NewContext() rs := rsFixture() @@ -291,6 +291,39 @@ func TestInstallRelease_WithChartAndDependencyNotes(t *testing.T) { t.Logf("rel: %v", rel) + if rel.Info.Status.Notes != notesText { + t.Fatalf("Expected '%s', got '%s'", notesText, rel.Info.Status.Notes) + } + + if rel.Info.Description != "Install complete" { + t.Errorf("unexpected description: %s", rel.Info.Description) + } +} + +func TestInstallRelease_WithChartAndDependencyAllNotes(t *testing.T) { + c := helm.NewContext() + rs := rsFixture() + + req := installRequest(withSubNotes(), + withChart( + withNotes(notesText), + withDependency(withNotes(notesText+" child")), + )) + res, err := rs.InstallRelease(c, req) + if err != nil { + t.Fatalf("Failed install: %s", err) + } + if res.Release.Name == "" { + t.Errorf("Expected release name.") + } + + rel, err := rs.env.Releases.Get(res.Release.Name, res.Release.Version) + if err != nil { + t.Errorf("Expected release for %s (%v).", res.Release.Name, rs.env.Releases) + } + + t.Logf("rel: %v", rel) + if !strings.Contains(rel.Info.Status.Notes, notesText) || !strings.Contains(rel.Info.Status.Notes, notesText+" child") { t.Fatalf("Expected '%s', got '%s'", notesText+"\n"+notesText+" child", rel.Info.Status.Notes) } diff --git a/pkg/tiller/release_server.go b/pkg/tiller/release_server.go index e223d9f32..29379d374 100644 --- a/pkg/tiller/release_server.go +++ b/pkg/tiller/release_server.go @@ -20,6 +20,7 @@ import ( "bytes" "errors" "fmt" + "path" "regexp" "strings" @@ -259,7 +260,7 @@ func GetVersionSet(client discovery.ServerGroupsInterface) (chartutil.VersionSet return chartutil.NewVersionSet(versions...), nil } -func (s *ReleaseServer) renderResources(ch *chart.Chart, values chartutil.Values, vs chartutil.VersionSet) ([]*release.Hook, *bytes.Buffer, string, error) { +func (s *ReleaseServer) renderResources(ch *chart.Chart, values chartutil.Values, subNotes bool, vs chartutil.VersionSet) ([]*release.Hook, *bytes.Buffer, string, error) { // Guard to make sure Tiller is at the right version to handle this chart. sver := version.GetVersion() if ch.Metadata.TillerVersion != "" && @@ -291,14 +292,18 @@ func (s *ReleaseServer) renderResources(ch *chart.Chart, values chartutil.Values var notesBuffer bytes.Buffer for k, v := range files { if strings.HasSuffix(k, notesFileSuffix) { - // If buffer contains data, add newline before adding more - if notesBuffer.Len() > 0 { - notesBuffer.WriteString("\n") + if subNotes || (k == path.Join(ch.Metadata.Name, "templates", notesFileSuffix)) { + + // If buffer contains data, add newline before adding more + if notesBuffer.Len() > 0 { + notesBuffer.WriteString("\n") + } + notesBuffer.WriteString(v) } - notesBuffer.WriteString(v) delete(files, k) } } + notes := notesBuffer.String() // Sort hooks, manifests, and partials. Only hooks and manifests are returned, diff --git a/pkg/tiller/release_server_test.go b/pkg/tiller/release_server_test.go index 96cb84a75..78c16e679 100644 --- a/pkg/tiller/release_server_test.go +++ b/pkg/tiller/release_server_test.go @@ -228,6 +228,12 @@ func withChart(chartOpts ...chartOption) installOption { } } +func withSubNotes() installOption { + return func(opts *installOptions) { + opts.SubNotes = true + } +} + func installRequest(opts ...installOption) *services.InstallReleaseRequest { reqOpts := &installOptions{ &services.InstallReleaseRequest{ diff --git a/pkg/tiller/release_update.go b/pkg/tiller/release_update.go index 6f5d37331..c4e4820e7 100644 --- a/pkg/tiller/release_update.go +++ b/pkg/tiller/release_update.go @@ -113,7 +113,7 @@ func (s *ReleaseServer) prepareUpdate(req *services.UpdateReleaseRequest) (*rele return nil, nil, err } - hooks, manifestDoc, notesTxt, err := s.renderResources(req.Chart, valuesToRender, caps.APIVersions) + hooks, manifestDoc, notesTxt, err := s.renderResources(req.Chart, valuesToRender, req.SubNotes, caps.APIVersions) if err != nil { return nil, nil, err } diff --git a/pkg/urlutil/urlutil_test.go b/pkg/urlutil/urlutil_test.go index f0c82c0a9..b3a142392 100644 --- a/pkg/urlutil/urlutil_test.go +++ b/pkg/urlutil/urlutil_test.go @@ -65,8 +65,8 @@ func TestEqual(t *testing.T) { func TestExtractHostname(t *testing.T) { tests := map[string]string{ - "http://example.com": "example.com", - "https://example.com/foo": "example.com", + "http://example.com": "example.com", + "https://example.com/foo": "example.com", "https://example.com:31337/not/with/a/bang/but/a/whimper": "example.com", } for start, expect := range tests { From 66e79227b2ff666ba66f48db992fc1f9c1ff464c Mon Sep 17 00:00:00 2001 From: jgleonard Date: Thu, 1 Nov 2018 15:11:38 -0400 Subject: [PATCH 006/146] make docs Signed-off-by: jgleonard --- docs/helm/helm_install.md | 3 ++- docs/helm/helm_upgrade.md | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/helm/helm_install.md b/docs/helm/helm_install.md index 05cdf1e4a..5406126fa 100644 --- a/docs/helm/helm_install.md +++ b/docs/helm/helm_install.md @@ -93,6 +93,7 @@ helm install [CHART] [flags] --no-crd-hook prevent CRD hooks from running, but run other hooks --no-hooks prevent hooks from running during install --password string chart repository password where to locate the requested chart + --render-subchart-notes render subchart notes along with the parent --replace re-use the given name, even if that name is already used. This is unsafe in production --repo string chart repository url where to locate the requested chart --set stringArray set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) @@ -128,4 +129,4 @@ helm install [CHART] [flags] * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 10-Aug-2018 +###### Auto generated by spf13/cobra on 1-Nov-2018 diff --git a/docs/helm/helm_upgrade.md b/docs/helm/helm_upgrade.md index f18bcf6a7..df5bfe6ca 100644 --- a/docs/helm/helm_upgrade.md +++ b/docs/helm/helm_upgrade.md @@ -79,6 +79,7 @@ helm upgrade [RELEASE] [CHART] [flags] --no-hooks disable pre/post upgrade hooks --password string chart repository password where to locate the requested chart --recreate-pods performs pods restart for the resource if applicable + --render-subchart-notes render subchart notes along with parent --repo string chart repository url where to locate the requested chart --reset-values when upgrading, reset the values to the ones built into the chart --reuse-values when upgrading, reuse the last release's values and merge in any overrides from the command line via --set and -f. If '--reset-values' is specified, this is ignored. @@ -115,4 +116,4 @@ helm upgrade [RELEASE] [CHART] [flags] * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 24-Aug-2018 +###### Auto generated by spf13/cobra on 1-Nov-2018 From 7b66bc7775086cac8fc7ee66ef5af8927e91facf Mon Sep 17 00:00:00 2001 From: jgleonard Date: Thu, 1 Nov 2018 15:12:14 -0400 Subject: [PATCH 007/146] gofmt -s Signed-off-by: jgleonard --- pkg/proto/hapi/services/tiller.pb.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/proto/hapi/services/tiller.pb.go b/pkg/proto/hapi/services/tiller.pb.go index 813f15c33..e8eda8769 100644 --- a/pkg/proto/hapi/services/tiller.pb.go +++ b/pkg/proto/hapi/services/tiller.pb.go @@ -633,7 +633,7 @@ type InstallReleaseRequest struct { DisableCrdHook bool `protobuf:"varint,10,opt,name=disable_crd_hook,json=disableCrdHook" json:"disable_crd_hook,omitempty"` // Description, if set, will set the description for the installed release Description string `protobuf:"bytes,11,opt,name=description" json:"description,omitempty"` - SubNotes bool `protobuf:"varint,12,opt,name=subNotes" json:"subNotes,omitempty"` + SubNotes bool `protobuf:"varint,12,opt,name=subNotes" json:"subNotes,omitempty"` } func (m *InstallReleaseRequest) Reset() { *m = InstallReleaseRequest{} } @@ -711,7 +711,6 @@ func (m *InstallReleaseRequest) GetDisableCrdHook() bool { return false } - func (m *InstallReleaseRequest) GetSubNotes() bool { if m != nil { return m.SubNotes From b846560f4829ef725a425c43955e2c321755063a Mon Sep 17 00:00:00 2001 From: jgleonard Date: Wed, 7 Nov 2018 13:34:12 -0500 Subject: [PATCH 008/146] formatting Signed-off-by: jgleonard --- _proto/hapi/services/tiller.proto | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_proto/hapi/services/tiller.proto b/_proto/hapi/services/tiller.proto index add468c73..1edd86025 100644 --- a/_proto/hapi/services/tiller.proto +++ b/_proto/hapi/services/tiller.proto @@ -212,7 +212,7 @@ message UpdateReleaseRequest { bool force = 11; // Description, if set, will set the description for the updated release string description = 12; - // Render subchart notes if enabled + // Render subchart notes if enabled bool subNotes = 13; } @@ -284,7 +284,7 @@ message InstallReleaseRequest { // Description, if set, will set the description for the installed release string description = 11; - bool subNotes = 12; + bool subNotes = 12; } From 9030e7ba7513b44fcdffe060c6a89c11c0f54160 Mon Sep 17 00:00:00 2001 From: jgleonard Date: Wed, 7 Nov 2018 13:35:12 -0500 Subject: [PATCH 009/146] fold subNotes into updateReq and instReq Signed-off-by: jgleonard --- pkg/helm/client.go | 2 -- pkg/helm/option.go | 6 ++---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/pkg/helm/client.go b/pkg/helm/client.go index fcd30c106..771c7f3d1 100644 --- a/pkg/helm/client.go +++ b/pkg/helm/client.go @@ -95,7 +95,6 @@ func (h *Client) InstallReleaseFromChart(chart *chart.Chart, ns string, opts ... req := &reqOpts.instReq req.Chart = chart req.Namespace = ns - req.SubNotes = reqOpts.subNotes req.DryRun = reqOpts.dryRun req.DisableHooks = reqOpts.disableHooks req.DisableCrdHook = reqOpts.disableCRDHook @@ -172,7 +171,6 @@ func (h *Client) UpdateReleaseFromChart(rlsName string, chart *chart.Chart, opts req.DryRun = reqOpts.dryRun req.Name = rlsName req.DisableHooks = reqOpts.disableHooks - req.SubNotes = reqOpts.subNotes req.Recreate = reqOpts.recreate req.Force = reqOpts.force req.ResetValues = reqOpts.resetValues diff --git a/pkg/helm/option.go b/pkg/helm/option.go index 04d394254..a34c4b8ae 100644 --- a/pkg/helm/option.go +++ b/pkg/helm/option.go @@ -54,8 +54,6 @@ type options struct { // if set, skip CRD hook only disableCRDHook bool // if set, render SubChart Notes - subNotes bool - // name of release releaseName string // tls.Config to use for rpc if tls enabled tlsConfig *tls.Config @@ -344,14 +342,14 @@ func InstallReuseName(reuse bool) InstallOption { // InstallSubNotes will (if true) instruct Tiller to render SubChart Notes func InstallSubNotes(enable bool) InstallOption { return func(opts *options) { - opts.subNotes = enable + opts.instReq.SubNotes = enable } } // UpgradeSubNotes will (if true) instruct Tiller to render SubChart Notes func UpgradeSubNotes(enable bool) UpdateOption { return func(opts *options) { - opts.subNotes = enable + opts.updateReq.SubNotes = enable } } From 5ac37fba9952e2df8a29c42500ee5746c3325c74 Mon Sep 17 00:00:00 2001 From: Morten Torkildsen Date: Thu, 15 Nov 2018 11:58:07 -0800 Subject: [PATCH 010/146] fix(helm): Fix linebreaks when printing custom resources The output from helm status is not correct for custom resources. The HumanReadablePrinter from Kubernetes only outputs the column names when the type differs from the previous one. This makes the output inconsistent and also creates problems for putting in the correct line breaks. This PR sets up a new printer for each type, thereby making sure that all types are printed with the correct use of line breaks and with column names. Signed-off-by: Morten Torkildsen --- pkg/kube/client.go | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/pkg/kube/client.go b/pkg/kube/client.go index 0cc68b71b..f86621b3f 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -211,18 +211,15 @@ func (c *Client) Get(namespace string, reader io.Reader) (string, error) { // an object type changes, so we can just rely on that. Problem is it doesn't seem to keep // track of tab widths. buf := new(bytes.Buffer) - p, _ := get.NewHumanPrintFlags().ToPrinter("") - index := 0 + printFlags := get.NewHumanPrintFlags() for t, ot := range objs { - kindHeader := fmt.Sprintf("==> %s", t) - if index == 0 { - kindHeader = kindHeader + "\n" - } + kindHeader := fmt.Sprintf("==> %s\n", t) if _, err = buf.WriteString(kindHeader); err != nil { return "", err } + typePrinter, _ := printFlags.ToPrinter("") for _, o := range ot { - if err := p.PrintObj(o, buf); err != nil { + if err := typePrinter.PrintObj(o, buf); err != nil { c.Log("failed to print object type %s, object: %q :\n %v", t, o, err) return "", err } @@ -230,7 +227,6 @@ func (c *Client) Get(namespace string, reader io.Reader) (string, error) { if _, err := buf.WriteString("\n"); err != nil { return "", err } - index += 1 } if len(missing) > 0 { buf.WriteString(MissingGetHeader) From 97465abda0b6a9e9934092c6245070fd91088023 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Wed, 28 Nov 2018 09:59:32 -0800 Subject: [PATCH 011/146] fix(windows): fix unit tests on Windows (#4897) Signed-off-by: Matthew Fisher --- .appveyor.yml | 6 +++--- cmd/helm/helm_test.go | 5 +++-- cmd/helm/package_test.go | 11 ++++++++++- cmd/helm/template_test.go | 2 +- cmd/helm/verify_test.go | 2 +- pkg/chartutil/load.go | 1 + pkg/chartutil/requirements_test.go | 9 ++++++++- pkg/chartutil/testdata/joonix/charts/.gitkeep | 0 pkg/chartutil/testdata/joonix/charts/frobnitz | 1 - pkg/getter/plugingetter_test.go | 5 +++++ pkg/repo/index.go | 7 +++++-- pkg/repo/index_test.go | 2 +- 12 files changed, 38 insertions(+), 13 deletions(-) create mode 100644 pkg/chartutil/testdata/joonix/charts/.gitkeep delete mode 120000 pkg/chartutil/testdata/joonix/charts/frobnitz diff --git a/.appveyor.yml b/.appveyor.yml index d7ba1d9fd..40d02927d 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -6,10 +6,10 @@ environment: install: - ps: iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/fishworks/gofish/master/scripts/install.ps1')) - gofish init - - gofish install dep - - dep ensure -v + - gofish install glide + - glide install --strip-vendor cache: - - vendor -> Gopkg.lock + - vendor -> glide.lock build: "off" deploy: "off" test_script: diff --git a/cmd/helm/helm_test.go b/cmd/helm/helm_test.go index 3551eb534..6e915fa7b 100644 --- a/cmd/helm/helm_test.go +++ b/cmd/helm/helm_test.go @@ -29,6 +29,7 @@ import ( "github.com/spf13/cobra" + "k8s.io/client-go/util/homedir" "k8s.io/helm/pkg/helm" "k8s.io/helm/pkg/helm/environment" "k8s.io/helm/pkg/helm/helmpath" @@ -167,7 +168,7 @@ func TestRootCmd(t *testing.T) { { name: "defaults", args: []string{"home"}, - home: filepath.Join(os.Getenv("HOME"), "/.helm"), + home: filepath.Join(homedir.HomeDir(), ".helm"), }, { name: "with --home set", @@ -236,7 +237,7 @@ func TestTLSFlags(t *testing.T) { homePath := os.Getenv("HELM_HOME") if homePath == "" { - homePath = filepath.Join(os.Getenv("HOME"), ".helm") + homePath = filepath.Join(homedir.HomeDir(), ".helm") } home := helmpath.Home(homePath) diff --git a/cmd/helm/package_test.go b/cmd/helm/package_test.go index 7ed9829a5..d3bd25af7 100644 --- a/cmd/helm/package_test.go +++ b/cmd/helm/package_test.go @@ -17,10 +17,12 @@ package main import ( "bytes" + "fmt" "io/ioutil" "os" "path/filepath" "regexp" + "runtime" "testing" "github.com/spf13/cobra" @@ -53,6 +55,13 @@ func TestSetVersion(t *testing.T) { func TestPackage(t *testing.T) { + statExe := "stat" + statFileMsg := "no such file or directory" + if runtime.GOOS == "windows" { + statExe = "FindFirstFile" + statFileMsg = "The system cannot find the file specified." + } + tests := []struct { name string flags map[string]string @@ -106,7 +115,7 @@ func TestPackage(t *testing.T) { name: "package --destination does-not-exist", args: []string{"testdata/testcharts/alpine"}, flags: map[string]string{"destination": "does-not-exist"}, - expect: "stat does-not-exist: no such file or directory", + expect: fmt.Sprintf("Failed to save: %s does-not-exist: %s", statExe, statFileMsg), err: true, }, { diff --git a/cmd/helm/template_test.go b/cmd/helm/template_test.go index ec989ea67..98044eff0 100644 --- a/cmd/helm/template_test.go +++ b/cmd/helm/template_test.go @@ -75,7 +75,7 @@ func TestTemplateCmd(t *testing.T) { { name: "check_execute_absolute", desc: "verify --execute single template", - args: []string{subchart1ChartPath, "-x", subchart1AbsChartPath + "/" + "templates/service.yaml", "--set", "service.name=apache"}, + args: []string{subchart1ChartPath, "-x", filepath.Join(subchart1AbsChartPath, "templates", "service.yaml"), "--set", "service.name=apache"}, expectKey: "subchart1/templates/service.yaml", expectValue: "protocol: TCP\n name: apache", }, diff --git a/cmd/helm/verify_test.go b/cmd/helm/verify_test.go index 4d683df75..d4a580c23 100644 --- a/cmd/helm/verify_test.go +++ b/cmd/helm/verify_test.go @@ -28,7 +28,7 @@ func TestVerifyCmd(t *testing.T) { statPathMsg := "no such file or directory" statFileMsg := statPathMsg if runtime.GOOS == "windows" { - statExe = "GetFileAttributesEx" + statExe = "FindFirstFile" statPathMsg = "The system cannot find the path specified." statFileMsg = "The system cannot find the file specified." } diff --git a/pkg/chartutil/load.go b/pkg/chartutil/load.go index b3daefac7..9f1c80c85 100644 --- a/pkg/chartutil/load.go +++ b/pkg/chartutil/load.go @@ -43,6 +43,7 @@ import ( // If a .helmignore file is present, the directory loader will skip loading any files // matching it. But .helmignore is not evaluated when reading out of an archive. func Load(name string) (*chart.Chart, error) { + name = filepath.FromSlash(name) fi, err := os.Stat(name) if err != nil { return nil, err diff --git a/pkg/chartutil/requirements_test.go b/pkg/chartutil/requirements_test.go index 0afde17e1..e433f92ea 100644 --- a/pkg/chartutil/requirements_test.go +++ b/pkg/chartutil/requirements_test.go @@ -15,6 +15,8 @@ limitations under the License. package chartutil import ( + "os" + "path/filepath" "sort" "testing" @@ -426,7 +428,12 @@ func TestDependentChartWithSubChartsHelmignore(t *testing.T) { } func TestDependentChartsWithSubChartsSymlink(t *testing.T) { - c, err := Load("testdata/joonix") + joonix := "testdata/joonix" + if err := os.Symlink(filepath.Join("..", "..", "frobnitz"), filepath.Join(joonix, "charts", "frobnitz")); err != nil { + t.Fatal(err) + } + defer os.RemoveAll(filepath.Join(joonix, "charts", "frobnitz")) + c, err := Load(joonix) if err != nil { t.Fatalf("Failed to load testdata: %s", err) } diff --git a/pkg/chartutil/testdata/joonix/charts/.gitkeep b/pkg/chartutil/testdata/joonix/charts/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/pkg/chartutil/testdata/joonix/charts/frobnitz b/pkg/chartutil/testdata/joonix/charts/frobnitz deleted file mode 120000 index fde1b78ac..000000000 --- a/pkg/chartutil/testdata/joonix/charts/frobnitz +++ /dev/null @@ -1 +0,0 @@ -../../frobnitz \ No newline at end of file diff --git a/pkg/getter/plugingetter_test.go b/pkg/getter/plugingetter_test.go index 9bfe6144d..7c0bd6c1e 100644 --- a/pkg/getter/plugingetter_test.go +++ b/pkg/getter/plugingetter_test.go @@ -18,6 +18,7 @@ package getter import ( "os" "path/filepath" + "runtime" "strings" "testing" @@ -67,6 +68,10 @@ func TestCollectPlugins(t *testing.T) { } func TestPluginGetter(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("TODO: refactor this test to work on windows") + } + oldhh := os.Getenv("HELM_HOME") defer os.Setenv("HELM_HOME", oldhh) os.Setenv("HELM_HOME", "") diff --git a/pkg/repo/index.go b/pkg/repo/index.go index 01bf4a8ca..9031463f3 100644 --- a/pkg/repo/index.go +++ b/pkg/repo/index.go @@ -22,6 +22,7 @@ import ( "fmt" "io/ioutil" "os" + "path" "path/filepath" "sort" "strings" @@ -110,7 +111,7 @@ func (i IndexFile) Add(md *chart.Metadata, filename, baseURL, digest string) { _, file := filepath.Split(filename) u, err = urlutil.URLJoin(baseURL, file) if err != nil { - u = filepath.Join(baseURL, file) + u = path.Join(baseURL, file) } } cr := &ChartVersion{ @@ -246,9 +247,11 @@ func IndexDirectory(dir, baseURL string) (*IndexFile, error) { var parentDir string parentDir, fname = filepath.Split(fname) + // filepath.Split appends an extra slash to the end of parentDir. We want to strip that out. + parentDir = strings.TrimSuffix(parentDir, string(os.PathSeparator)) parentURL, err := urlutil.URLJoin(baseURL, parentDir) if err != nil { - parentURL = filepath.Join(baseURL, parentDir) + parentURL = path.Join(baseURL, parentDir) } c, err := chartutil.Load(arch) diff --git a/pkg/repo/index_test.go b/pkg/repo/index_test.go index 2ce817ce3..7c9239b7a 100644 --- a/pkg/repo/index_test.go +++ b/pkg/repo/index_test.go @@ -272,7 +272,7 @@ func verifyLocalIndex(t *testing.T, i *IndexFile) { } func TestIndexDirectory(t *testing.T) { - dir := "testdata/repository" + dir := filepath.Join("testdata", "repository") index, err := IndexDirectory(dir, "http://localhost:8080") if err != nil { t.Fatal(err) From c18d7726ac36e538c85a222f9833cb62f2275b17 Mon Sep 17 00:00:00 2001 From: Tariq Ibrahim Date: Wed, 28 Nov 2018 10:01:22 -0800 Subject: [PATCH 012/146] Adding link labels to doc links for more conspicuity (#4904) Signed-off-by: tariqibrahim --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7958a9adb..aba3388a6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -178,7 +178,7 @@ contributing to Helm. All issue types follow the same general lifecycle. Differe 1. Submit a pull request. Coding conventions and standards are explained in the official developer docs: -https://github.com/helm/helm/blob/master/docs/developers.md +[Developers Guide](docs/developers.md) The next section contains more information on the workflow followed for PRs From 8fcefd7d959ce10448507944b2418f29da532f5d Mon Sep 17 00:00:00 2001 From: Jintao Zhang Date: Thu, 29 Nov 2018 02:05:33 +0800 Subject: [PATCH 013/146] Fix doc charts indent (#4940) Signed-off-by: Jintao Zhang --- docs/charts.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/charts.md b/docs/charts.md index 2f7605350..64fc68934 100644 --- a/docs/charts.md +++ b/docs/charts.md @@ -259,27 +259,27 @@ Tags - The tags field is a YAML list of labels to associate with this chart. In the top parent's values, all charts with tags can be enabled or disabled by specifying the tag and a boolean value. -```` +```yaml # parentchart/requirements.yaml dependencies: - - name: subchart1 - repository: http://localhost:10191 - version: 0.1.0 - condition: subchart1.enabled,global.subchart1.enabled - tags: - - front-end - - subchart1 - - - name: subchart2 - repository: http://localhost:10191 - version: 0.1.0 - condition: subchart2.enabled,global.subchart2.enabled - tags: - - back-end + - name: subchart1 + repository: http://localhost:10191 + version: 0.1.0 + condition: subchart1.enabled,global.subchart1.enabled + tags: + - front-end + - subchart1 + + - name: subchart2 + repository: http://localhost:10191 + version: 0.1.0 + condition: subchart2.enabled,global.subchart2.enabled + tags: + - back-end - subchart2 -```` -```` +``` +```yaml # parentchart/values.yaml subchart1: From 865c1d3c7757a12271e0d9dca805f8d54b5f6456 Mon Sep 17 00:00:00 2001 From: Abu Hanifa Date: Thu, 29 Nov 2018 00:06:04 +0600 Subject: [PATCH 014/146] Error message if anyone try to create multiple helm chart at a time (#4952) * error message for creating multiple helm chart at a time Signed-off-by: hanif * Update cmd/helm/create.go Co-Authored-By: a8uhnf Signed-off-by: hanif --- cmd/helm/create.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmd/helm/create.go b/cmd/helm/create.go index 7f0f99af8..0d278c8b5 100644 --- a/cmd/helm/create.go +++ b/cmd/helm/create.go @@ -75,6 +75,9 @@ func newCreateCmd(out io.Writer) *cobra.Command { if len(args) == 0 { return errors.New("the name of the new chart is required") } + if len(args) > 1 { + return errors.New("command 'create' doesn't support multiple arguments") + } cc.name = args[0] return cc.run() }, From ea158a6aad9d741791e0f77cb34a541fdd9bde64 Mon Sep 17 00:00:00 2001 From: Ishaan Malhi <12560808+OrthoDex@users.noreply.github.com> Date: Wed, 28 Nov 2018 23:42:41 +0530 Subject: [PATCH 015/146] docs: add documentation for the helmignore file (#4966) * docs: add documentation for the helmignore file Signed-off-by: Ishaan Malhi * docs: rearrange helmignore docs under chart template developer's guide Signed-off-by: Ishaan Malhi --- docs/README.md | 1 + docs/chart_template_guide/helm_ignore_file.md | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 docs/chart_template_guide/helm_ignore_file.md diff --git a/docs/README.md b/docs/README.md index 4ca93bd1f..ed13cc22a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -24,6 +24,7 @@ - [Variables](chart_template_guide/variables.md) - [Named Templates (Partials)](chart_template_guide/named_templates.md) - [Accessing Files Inside Templates](chart_template_guide/accessing_files.md) + - [Ignoring unwanted files and folders](chart_template_guide/helm_ignore_file.md) - [Creating a NOTES.txt File](chart_template_guide/notes_files.md) - [Subcharts and Global Values](chart_template_guide/subcharts_and_globals.md) - [Debugging Templates](chart_template_guide/debugging.md) diff --git a/docs/chart_template_guide/helm_ignore_file.md b/docs/chart_template_guide/helm_ignore_file.md new file mode 100644 index 000000000..6793bdfec --- /dev/null +++ b/docs/chart_template_guide/helm_ignore_file.md @@ -0,0 +1,23 @@ +# The .helmignore file + +The `.helmignore` file is used to specify files you don't want to include in your helm chart. + +If this file exists, the `helm package` command will ignore all the files that match the pattern specified in the `.helmignore` file while packaging your application. + +This can help in avoiding unncessary or sensitive files or directories from being added in your helm chart. + +The `.helmignore` file supports Unix shell glob matching, relative path matching, and negation (prefixed with !). Only one pattern per line is considered. + +Here is an example `.helmignore` file: + +``` +# comment +.git +*/temp* +*/*/temp* +temp? +``` + +**We'd love your help** making this document better. To add, correct, or remove +information, [file an issue](https://github.com/helm/helm/issues) or +send us a pull request. From 5584e5c5d815143aada08438cf6e936f7f79e6b3 Mon Sep 17 00:00:00 2001 From: Martin Hickey Date: Wed, 28 Nov 2018 18:22:39 +0000 Subject: [PATCH 016/146] Update chart doc with details about the license file (#4977) Signed-off-by: Martin Hickey --- docs/charts.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/charts.md b/docs/charts.md index 64fc68934..5a895fd49 100644 --- a/docs/charts.md +++ b/docs/charts.md @@ -124,7 +124,14 @@ project is: ## Chart LICENSE, README and NOTES Charts can also contain files that describe the installation, configuration, usage and license of a -chart. A README for a chart should be formatted in Markdown (README.md), and should generally +chart. + +A LICENSE is a plain text file containing the [license](https://en.wikipedia.org/wiki/Software_license) +for the chart. The chart can contain a license as it may have programming logic in the templates and +would therefore not be configuration only. There can also be separate license(s) for the application +installed by the chart, if required. + +A README for a chart should be formatted in Markdown (README.md), and should generally contain: - A description of the application or service the chart provides From ede43a313dde2611ea63e89546af46854b4121d4 Mon Sep 17 00:00:00 2001 From: Morten Torkildsen Date: Thu, 15 Nov 2018 13:41:25 -0800 Subject: [PATCH 017/146] fix(helm): Print details for pod resource Due to a regression from a previous change, details about pod resources does not show up in the status output. This makes sure that the pod type from core are passed in to the printer so the details are shown in the output. Signed-off-by: Morten Torkildsen --- pkg/kube/client.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/kube/client.go b/pkg/kube/client.go index 0cc68b71b..6a7877d6b 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -48,6 +48,7 @@ import ( "k8s.io/client-go/kubernetes/scheme" watchtools "k8s.io/client-go/tools/watch" "k8s.io/kubernetes/pkg/api/legacyscheme" + "k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/kubectl/cmd/get" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "k8s.io/kubernetes/pkg/kubectl/validation" @@ -202,7 +203,9 @@ func (c *Client) Get(namespace string, reader io.Reader) (string, error) { //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]) + pod := &core.Pod{} + legacyscheme.Scheme.Convert(&podItems[i], pod, nil) + objs[key+"(related)"] = append(objs[key+"(related)"], pod) } } From 75b4afaa33a02ff01f041cf58a01535bca770cd6 Mon Sep 17 00:00:00 2001 From: Luke Hoban Date: Wed, 28 Nov 2018 11:15:49 -0800 Subject: [PATCH 018/146] Allow missing trailing '/' in --repo url (#4956) Apply the same procedure to allow missing trailing slash in repo base URLs used in `repo/chart` inputs to `--repo` inputs. Fixes #4954. Signed-off-by: Luke Hoban --- pkg/repo/chartrepo.go | 4 +++- pkg/repo/chartrepo_test.go | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/pkg/repo/chartrepo.go b/pkg/repo/chartrepo.go index cd9d6c547..c512c5b7e 100644 --- a/pkg/repo/chartrepo.go +++ b/pkg/repo/chartrepo.go @@ -270,10 +270,12 @@ func ResolveReferenceURL(baseURL, refURL string) (string, error) { return "", fmt.Errorf("failed to parse %s as URL: %v", refURL, err) } + // We need a trailing slash for ResolveReference to work, but make sure there isn't already one + parsedBaseURL.Path = strings.TrimSuffix(parsedBaseURL.Path, "/") + "/" + resolvedURL := parsedBaseURL.ResolveReference(parsedRefURL) // if the base URL contains query string parameters, // propagate them to the child URL but only if the // refURL is relative to baseURL - resolvedURL := parsedBaseURL.ResolveReference(parsedRefURL) if (resolvedURL.Hostname() == parsedBaseURL.Hostname()) && (resolvedURL.Port() == parsedBaseURL.Port()) { resolvedURL.RawQuery = parsedBaseURL.RawQuery } diff --git a/pkg/repo/chartrepo_test.go b/pkg/repo/chartrepo_test.go index 19071872d..a2f1daeb8 100644 --- a/pkg/repo/chartrepo_test.go +++ b/pkg/repo/chartrepo_test.go @@ -287,6 +287,14 @@ func TestResolveReferenceURL(t *testing.T) { t.Errorf("%s", chartURL) } + chartURL, err = ResolveReferenceURL("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 = ResolveReferenceURL("http://localhost:8123/charts/?st=2018-08-06T22%3A59%3A04Z&se=2018-08-07T22%3A59%3A04Z&sp=rl&sv=2018-03-28&sr=c&sig=cyqM4%2F5G7HNk%2F3faaHSDMaWxFxefCglvZlYSnmQBwiY%3D", "nginx-0.2.0.tgz") if err != nil { t.Errorf("%s", err) From 5bf38a2d7d572c4317e18c4ecbe7023403b979bb Mon Sep 17 00:00:00 2001 From: Matt Tucker Date: Wed, 28 Nov 2018 11:30:35 -0700 Subject: [PATCH 019/146] fix(storage): when pruning release versions, never delete the last deployed revision Signed-off-by: Matt Tucker --- pkg/storage/storage.go | 40 ++++++++++++++++++++++++----- pkg/storage/storage_test.go | 51 +++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 7 deletions(-) diff --git a/pkg/storage/storage.go b/pkg/storage/storage.go index 6d5f589b9..e0e39ac0c 100644 --- a/pkg/storage/storage.go +++ b/pkg/storage/storage.go @@ -181,21 +181,37 @@ func (s *Storage) removeLeastRecent(name string, max int) error { if len(h) <= max { return nil } - overage := len(h) - max // We want oldest to newest relutil.SortByRevision(h) + lastDeployed, err := s.Deployed(name) + if err != nil { + return err + } + + var toDelete []*rspb.Release + for _, rel := range h { + // once we have enough releases to delete to reach the max, stop + if len(h)-len(toDelete) == max { + break + } + if lastDeployed != nil { + if rel.GetVersion() != lastDeployed.GetVersion() { + toDelete = append(toDelete, rel) + } + } else { + toDelete = append(toDelete, rel) + } + } + // Delete as many as possible. In the case of API throughput limitations, // multiple invocations of this function will eventually delete them all. - toDelete := h[0:overage] errors := []error{} for _, rel := range toDelete { - key := makeKey(name, rel.Version) - _, innerErr := s.Delete(name, rel.Version) - if innerErr != nil { - s.Log("error pruning %s from release history: %s", key, innerErr) - errors = append(errors, innerErr) + err = s.deleteReleaseVersion(name, rel.GetVersion()) + if err != nil { + errors = append(errors, err) } } @@ -210,6 +226,16 @@ func (s *Storage) removeLeastRecent(name string, max int) error { } } +func (s *Storage) deleteReleaseVersion(name string, version int32) error { + key := makeKey(name, version) + _, err := s.Delete(name, version) + if err != nil { + s.Log("error pruning %s from release history: %s", key, err) + return err + } + return nil +} + // Last fetches the last revision of the named release. func (s *Storage) Last(name string) (*rspb.Release, error) { s.Log("getting last revision of %q", name) diff --git a/pkg/storage/storage_test.go b/pkg/storage/storage_test.go index 19d786ad9..f7f3a86c7 100644 --- a/pkg/storage/storage_test.go +++ b/pkg/storage/storage_test.go @@ -293,6 +293,57 @@ func TestStorageRemoveLeastRecent(t *testing.T) { } } +func TestStorageDontDeleteDeployed(t *testing.T) { + storage := Init(driver.NewMemory()) + storage.Log = t.Logf + storage.MaxHistory = 3 + + const name = "angry-bird" + + // setup storage with test releases + setup := func() { + // release records + rls0 := ReleaseTestData{Name: name, Version: 1, Status: rspb.Status_SUPERSEDED}.ToRelease() + rls1 := ReleaseTestData{Name: name, Version: 2, Status: rspb.Status_DEPLOYED}.ToRelease() + rls2 := ReleaseTestData{Name: name, Version: 3, Status: rspb.Status_FAILED}.ToRelease() + rls3 := ReleaseTestData{Name: name, Version: 4, Status: rspb.Status_FAILED}.ToRelease() + + // create the release records in the storage + assertErrNil(t.Fatal, storage.Create(rls0), "Storing release 'angry-bird' (v1)") + assertErrNil(t.Fatal, storage.Create(rls1), "Storing release 'angry-bird' (v2)") + assertErrNil(t.Fatal, storage.Create(rls2), "Storing release 'angry-bird' (v3)") + assertErrNil(t.Fatal, storage.Create(rls3), "Storing release 'angry-bird' (v4)") + } + setup() + + rls5 := ReleaseTestData{Name: name, Version: 5, Status: rspb.Status_FAILED}.ToRelease() + assertErrNil(t.Fatal, storage.Create(rls5), "Storing release 'angry-bird' (v5)") + + // On inserting the 5th record, we expect a total of 3 releases, but we expect version 2 + // (the only deployed release), to still exist + hist, err := storage.History(name) + if err != nil { + t.Fatal(err) + } else if len(hist) != storage.MaxHistory { + for _, item := range hist { + t.Logf("%s %v", item.Name, item.Version) + } + t.Fatalf("expected %d items in history, got %d", storage.MaxHistory, len(hist)) + } + + expectedVersions := map[int32]bool{ + 2: true, + 4: true, + 5: true, + } + + for _, item := range hist { + if !expectedVersions[item.GetVersion()] { + t.Errorf("Release version %d, found when not expected", item.GetVersion()) + } + } +} + func TestStorageLast(t *testing.T) { storage := Init(driver.NewMemory()) From c095b9232dfd6631f0ce02ba1cb5ff35909153d8 Mon Sep 17 00:00:00 2001 From: Tariq Ibrahim Date: Wed, 28 Nov 2018 15:19:26 -0800 Subject: [PATCH 020/146] avoid kubernetes import for slice contains logic (#4963) * avoid kubernetes import for slice contains logic Signed-off-by: tariqibrahim * fix review comments Signed-off-by: tariqibrahim --- cmd/helm/inspect.go | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/cmd/helm/inspect.go b/cmd/helm/inspect.go index c1861f7c5..844116bc5 100644 --- a/cmd/helm/inspect.go +++ b/cmd/helm/inspect.go @@ -18,15 +18,13 @@ package main import ( "fmt" - "io" - "strings" - "github.com/ghodss/yaml" "github.com/golang/protobuf/ptypes/any" "github.com/spf13/cobra" + "io" + "strings" "k8s.io/helm/pkg/chartutil" - "k8s.io/kubernetes/pkg/util/slice" ) const inspectDesc = ` @@ -256,9 +254,23 @@ func (i *inspectCmd) run() error { func findReadme(files []*any.Any) (file *any.Any) { for _, file := range files { - if slice.ContainsString(readmeFileNames, strings.ToLower(file.TypeUrl), nil) { + if containsString(readmeFileNames, strings.ToLower(file.TypeUrl), nil) { return file } } return nil } + +// containsString checks if a given slice of strings contains the provided string. +// If a modifier func is provided, it is called with the slice item before the comparison. +func containsString(slice []string, s string, modifier func(s string) string) bool { + for _, item := range slice { + if item == s { + return true + } + if modifier != nil && modifier(item) == s { + return true + } + } + return false +} From e2a0e7fa545585a29c1e9602e6320479788eb9a6 Mon Sep 17 00:00:00 2001 From: Michael Merrill Date: Thu, 29 Nov 2018 13:09:10 -0500 Subject: [PATCH 021/146] Fix for existing CRDs are deleted when crd-install hook is introduced (#4709) Signed-off-by: mmerrill3 --- pkg/tiller/hooks.go | 7 +++++++ pkg/tiller/hooks_test.go | 33 ++++++++++++++++++++++++--------- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/pkg/tiller/hooks.go b/pkg/tiller/hooks.go index 0fb7c92f8..472301022 100644 --- a/pkg/tiller/hooks.go +++ b/pkg/tiller/hooks.go @@ -174,6 +174,13 @@ func (file *manifestFile) sort(result *result) error { isUnknownHook = true break } + if e == release.Hook_CRD_INSTALL { + result.generic = append(result.generic, Manifest{ + Name: file.path, + Content: m, + Head: &entry, + }) + } h.Events = append(h.Events, e) } diff --git a/pkg/tiller/hooks_test.go b/pkg/tiller/hooks_test.go index 8bd928500..86c89b8f3 100644 --- a/pkg/tiller/hooks_test.go +++ b/pkg/tiller/hooks_test.go @@ -131,6 +131,21 @@ metadata: name: example-test annotations: "helm.sh/hook": test-success +`, + }, + { + name: []string{"ninth"}, + path: "nine", + kind: []string{"CustomResourceDefinition"}, + hooks: map[string][]release.Hook_Event{"ninth": {release.Hook_CRD_INSTALL}}, + manifest: `apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: ninth + labels: + doesnot: matter + annotations: + "helm.sh/hook": crd-install `, }, } @@ -146,22 +161,22 @@ metadata: } // This test will fail if 'six' or 'seven' was added. - if len(generic) != 2 { - t.Errorf("Expected 2 generic manifests, got %d", len(generic)) + // changed to account for CustomResourceDefinition with crd-install hook being added to generic list of manifests + if len(generic) != 3 { + t.Errorf("Expected 3 generic manifests, got %d", len(generic)) } - if len(hs) != 4 { - t.Errorf("Expected 4 hooks, got %d", len(hs)) + // changed to account for 5 hooks now that there is a crd-install hook added as member 9 of the data list. It was 4 before. + if len(hs) != 5 { + t.Errorf("Expected 5 hooks, got %d", len(hs)) } for _, out := range hs { + t.Logf("Checking name %s path %s and kind %s", out.Name, out.Path, out.Kind) found := false for _, expect := range data { if out.Path == expect.path { found = true - if out.Path != expect.path { - t.Errorf("Expected path %s, got %s", expect.path, out.Path) - } nameFound := false for _, expectedName := range expect.name { if out.Name == expectedName { @@ -209,8 +224,8 @@ metadata: name := sh.Metadata.Name - //only keep track of non-hook manifests - if err == nil && s.hooks[name] == nil { + //only keep track of non-hook manifests, that are not CustomResourceDefinitions with crd-install + if err == nil && (s.hooks[name] == nil || s.hooks[name][0] == release.Hook_CRD_INSTALL) { another := Manifest{ Content: m, Name: name, From 55a338579a5b3150f3b9466b4fe471a6f0118f70 Mon Sep 17 00:00:00 2001 From: Morten Torkildsen Date: Thu, 29 Nov 2018 15:50:23 -0800 Subject: [PATCH 022/146] fix(helm): Allow custom resources in hooks (#4986) Currently the code that handles hooks uses a builder that creates the versioned types rather than unstructured. This results in an error whenever a custom resource is used in the hook as the type will not be registered in the scheme used in Helm. This changes this to use a builder that created unstructured resources and only converts to the versioned type when needed. Signed-off-by: Morten Torkildsen --- pkg/kube/client.go | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/pkg/kube/client.go b/pkg/kube/client.go index 0cc68b71b..5535364fe 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -179,7 +179,11 @@ func (c *Client) Get(namespace string, reader io.Reader) (string, error) { vk := gvk.Version + "/" + gvk.Kind internalObj, err := asInternal(info) if err != nil { - c.Log("Warning: conversion to internal type failed: %v", err) + // If the problem is just that the resource is not registered, don't print any + // error. This is normal for custom resources. + if !runtime.IsNotRegisteredError(err) { + c.Log("Warning: conversion to internal type failed: %v", err) + } // Add the unstructured object in this situation. It will still get listed, just // with less information. objs[vk] = append(objs[vk], info.Object) @@ -358,7 +362,7 @@ func (c *Client) watchTimeout(t time.Duration) ResourceActorFunc { // // Handling for other kinds will be added as necessary. func (c *Client) WatchUntilReady(namespace string, reader io.Reader, timeout int64, shouldWait bool) error { - infos, err := c.Build(namespace, reader) + infos, err := c.BuildUnstructured(namespace, reader) if err != nil { return err } @@ -605,12 +609,13 @@ func (c *Client) watchUntilReady(timeout time.Duration, info *resource.Info) err // // This operates on an event returned from a watcher. func (c *Client) waitForJob(e watch.Event, name string) (bool, error) { - o, ok := e.Object.(*batch.Job) - if !ok { - return true, fmt.Errorf("Expected %s to be a *batch.Job, got %T", name, e.Object) + job := &batch.Job{} + err := legacyscheme.Scheme.Convert(e.Object, job, nil) + if err != nil { + return true, err } - for _, c := range o.Status.Conditions { + for _, c := range job.Status.Conditions { if c.Type == batch.JobComplete && c.Status == v1.ConditionTrue { return true, nil } else if c.Type == batch.JobFailed && c.Status == v1.ConditionTrue { @@ -618,7 +623,7 @@ func (c *Client) waitForJob(e watch.Event, name string) (bool, error) { } } - c.Log("%s: Jobs active: %d, jobs failed: %d, jobs succeeded: %d", name, o.Status.Active, o.Status.Failed, o.Status.Succeeded) + c.Log("%s: Jobs active: %d, jobs failed: %d, jobs succeeded: %d", name, job.Status.Active, job.Status.Failed, job.Status.Succeeded) return false, nil } From 58be8e461c9ab8e86ea2ad519601e1a288f21e8c Mon Sep 17 00:00:00 2001 From: Martin Hickey Date: Fri, 30 Nov 2018 18:04:37 +0000 Subject: [PATCH 023/146] Update messaging in value parsing to improve traceability (#4974) Closes #4736 Signed-off-by: Martin Hickey --- pkg/chartutil/requirements.go | 6 +++--- pkg/chartutil/values.go | 28 ++++++++++++++-------------- pkg/chartutil/values_test.go | 2 +- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/pkg/chartutil/requirements.go b/pkg/chartutil/requirements.go index 566123122..0f1128305 100644 --- a/pkg/chartutil/requirements.go +++ b/pkg/chartutil/requirements.go @@ -428,7 +428,7 @@ func processImportValues(c *chart.Chart) error { } // create value map from child to be merged into parent vm := pathToMap(nm["parent"], vv.AsMap()) - b = coalesceTables(cvals, vm) + b = coalesceTables(cvals, vm, c.Metadata.Name) case string: nm := map[string]string{ "child": "exports." + iv, @@ -441,14 +441,14 @@ func processImportValues(c *chart.Chart) error { log.Printf("Warning: ImportValues missing table: %v", err) continue } - b = coalesceTables(b, vm.AsMap()) + b = coalesceTables(b, vm.AsMap(), c.Metadata.Name) } } // set our formatted import values r.ImportValues = outiv } } - b = coalesceTables(b, cvals) + b = coalesceTables(b, cvals, c.Metadata.Name) y, err := yaml.Marshal(b) if err != nil { return err diff --git a/pkg/chartutil/values.go b/pkg/chartutil/values.go index a47073b67..352524c13 100644 --- a/pkg/chartutil/values.go +++ b/pkg/chartutil/values.go @@ -203,7 +203,7 @@ func coalesceDeps(chrt *chart.Chart, dest map[string]interface{}) (map[string]in dvmap := dv.(map[string]interface{}) // Get globals out of dest and merge them into dvmap. - coalesceGlobals(dvmap, dest) + coalesceGlobals(dvmap, dest, chrt.Metadata.Name) var err error // Now coalesce the rest of the values. @@ -219,20 +219,20 @@ func coalesceDeps(chrt *chart.Chart, dest map[string]interface{}) (map[string]in // coalesceGlobals copies the globals out of src and merges them into dest. // // For convenience, returns dest. -func coalesceGlobals(dest, src map[string]interface{}) map[string]interface{} { +func coalesceGlobals(dest, src map[string]interface{}, chartName string) map[string]interface{} { var dg, sg map[string]interface{} if destglob, ok := dest[GlobalKey]; !ok { dg = map[string]interface{}{} } else if dg, ok = destglob.(map[string]interface{}); !ok { - log.Printf("warning: skipping globals because destination %s is not a table.", GlobalKey) + log.Printf("Warning: Skipping globals for chart '%s' because destination '%s' is not a table.", chartName, GlobalKey) return dg } if srcglob, ok := src[GlobalKey]; !ok { sg = map[string]interface{}{} } else if sg, ok = srcglob.(map[string]interface{}); !ok { - log.Printf("warning: skipping globals because source %s is not a table.", GlobalKey) + log.Printf("Warning: skipping globals for chart '%s' because source '%s' is not a table.", chartName, GlobalKey) return dg } @@ -247,11 +247,11 @@ func coalesceGlobals(dest, src map[string]interface{}) map[string]interface{} { if destvmap, ok := destv.(map[string]interface{}); ok { // Basically, we reverse order of coalesce here to merge // top-down. - coalesceTables(vv, destvmap) + coalesceTables(vv, destvmap, chartName) dg[key] = vv continue } else { - log.Printf("Conflict: cannot merge map onto non-map for %q. Skipping.", key) + log.Printf("Warning: For chart '%s', cannot merge map onto non-map for key '%q'. Skipping.", chartName, key) } } else { // Here there is no merge. We're just adding. @@ -259,7 +259,7 @@ func coalesceGlobals(dest, src map[string]interface{}) map[string]interface{} { } } else if dv, ok := dg[key]; ok && istable(dv) { // It's not clear if this condition can actually ever trigger. - log.Printf("key %s is table. Skipping", key) + log.Printf("Warning: For chart '%s', key '%s' is a table. Skipping.", chartName, key) continue } // TODO: Do we need to do any additional checking on the value? @@ -291,7 +291,7 @@ func coalesceValues(c *chart.Chart, v map[string]interface{}) (map[string]interf // On error, we return just the overridden values. // FIXME: We should log this error. It indicates that the YAML data // did not parse. - return v, fmt.Errorf("error reading default values (%s): %s", c.Values.Raw, err) + return v, fmt.Errorf("Error: Reading chart '%s' default values (%s): %s", c.Metadata.Name, c.Values.Raw, err) } for key, val := range nv { @@ -305,12 +305,12 @@ func coalesceValues(c *chart.Chart, v map[string]interface{}) (map[string]interf // if v[key] is a table, merge nv's val table into v[key]. src, ok := val.(map[string]interface{}) if !ok { - log.Printf("warning: skipped value for %s: Not a table.", key) + log.Printf("Warning: Building values map for chart '%s'. Skipped value (%+v) for '%s', as it is not a table.", c.Metadata.Name, src, key) continue } // Because v has higher precedence than nv, dest values override src // values. - coalesceTables(dest, src) + coalesceTables(dest, src, c.Metadata.Name) } } else { // If the key is not in v, copy it from nv. @@ -323,7 +323,7 @@ func coalesceValues(c *chart.Chart, v map[string]interface{}) (map[string]interf // coalesceTables merges a source map into a destination map. // // dest is considered authoritative. -func coalesceTables(dst, src map[string]interface{}) map[string]interface{} { +func coalesceTables(dst, src map[string]interface{}, chartName string) map[string]interface{} { // Because dest has higher precedence than src, dest values override src // values. for key, val := range src { @@ -331,13 +331,13 @@ func coalesceTables(dst, src map[string]interface{}) map[string]interface{} { if innerdst, ok := dst[key]; !ok { dst[key] = val } else if istable(innerdst) { - coalesceTables(innerdst.(map[string]interface{}), val.(map[string]interface{})) + coalesceTables(innerdst.(map[string]interface{}), val.(map[string]interface{}), chartName) } else { - log.Printf("warning: cannot overwrite table with non table for %s (%v)", key, val) + log.Printf("Warning: Merging destination map for chart '%s'. Cannot overwrite table item '%s', with non table value: %v", chartName, key, val) } continue } else if dv, ok := dst[key]; ok && istable(dv) { - log.Printf("warning: destination for %s is a table. Ignoring non-table value %v", key, val) + log.Printf("Warning: Merging destination map for chart '%s'. The destination item '%s' is a table and ignoring the source '%s' as it has a non-table value of: %v", chartName, key, key, val) continue } else if !ok { // <- ok is still in scope from preceding conditional. dst[key] = val diff --git a/pkg/chartutil/values_test.go b/pkg/chartutil/values_test.go index f38afaf95..3fea14c3a 100644 --- a/pkg/chartutil/values_test.go +++ b/pkg/chartutil/values_test.go @@ -386,7 +386,7 @@ func TestCoalesceTables(t *testing.T) { // What we expect is that anything in dst overrides anything in src, but that // otherwise the values are coalesced. - coalesceTables(dst, src) + coalesceTables(dst, src, "") if dst["name"] != "Ishmael" { t.Errorf("Unexpected name: %s", dst["name"]) From 99199c975236430fdf7599c69a956c6eb73b44e9 Mon Sep 17 00:00:00 2001 From: Tariq Ibrahim Date: Tue, 4 Dec 2018 08:25:38 -0800 Subject: [PATCH 024/146] add unit tests for portforwarder (#4979) Signed-off-by: tariqibrahim --- pkg/helm/portforwarder/portforwarder_test.go | 51 ++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/pkg/helm/portforwarder/portforwarder_test.go b/pkg/helm/portforwarder/portforwarder_test.go index f5efe3443..2809bcbff 100644 --- a/pkg/helm/portforwarder/portforwarder_test.go +++ b/pkg/helm/portforwarder/portforwarder_test.go @@ -85,3 +85,54 @@ func TestGetFirstPod(t *testing.T) { } } } + +func TestGetTillerPodImage(t *testing.T) { + tests := []struct { + name string + podSpec v1.PodSpec + expected string + err bool + }{ + { + name: "pod with tiller container image", + podSpec: v1.PodSpec{ + Containers: []v1.Container{ + { + Name: "tiller", + Image: "gcr.io/kubernetes-helm/tiller:v2.0.0", + }, + }, + }, + expected: "gcr.io/kubernetes-helm/tiller:v2.0.0", + err: false, + }, + { + name: "pod without tiller container image", + podSpec: v1.PodSpec{ + Containers: []v1.Container{ + { + Name: "not_tiller", + Image: "gcr.io/kubernetes-helm/not_tiller:v1.0.0", + }, + }, + }, + expected: "", + err: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mockPod := mockTillerPod() + mockPod.Spec = tt.podSpec + client := fake.NewSimpleClientset(&v1.PodList{Items: []v1.Pod{mockPod}}) + imageName, err := GetTillerPodImage(client.CoreV1(), v1.NamespaceDefault) + if (err != nil) != tt.err { + t.Errorf("%q. expected error: %v, got %v", tt.name, tt.err, err) + } + if imageName != tt.expected { + t.Errorf("%q. expected %q, got %q", tt.name, tt.expected, imageName) + } + }) + } +} From 73e985286f567bc5aa34399ca0e215840bee6c5e Mon Sep 17 00:00:00 2001 From: Florent Monbillard Date: Tue, 4 Dec 2018 13:48:12 -0500 Subject: [PATCH 025/146] Charts docs clean-up - Address #4998, #5000, #5001 and #5002 - Fix Markdown syntax for code blocks Signed-off-by: Florent Monbillard --- docs/charts.md | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/docs/charts.md b/docs/charts.md index 5a895fd49..7bc4f0020 100644 --- a/docs/charts.md +++ b/docs/charts.md @@ -116,10 +116,10 @@ be deprecated. The chart name can later be reused by publishing a newer version that is not marked as deprecated. The workflow for deprecating charts, as followed by the [helm/charts](https://github.com/helm/charts) project is: - - Update chart's `Chart.yaml` to mark the chart as deprecated, bumping the - version - - Release the new chart version in the Chart Repository - - Remove the chart from the source repository (e.g. git) + +- Update chart's `Chart.yaml` to mark the chart as deprecated, bumping the version +- Release the new chart version in the Chart Repository +- Remove the chart from the source repository (e.g. git) ## Chart LICENSE, README and NOTES @@ -160,7 +160,6 @@ the preferred method of declaring dependencies is by using a **Note:** The `dependencies:` section of the `Chart.yaml` from Helm Classic has been completely removed. - ### Managing Dependencies with `requirements.yaml` A `requirements.yaml` file is a simple file for listing your @@ -240,6 +239,7 @@ dependencies: ``` In the above example we will get 3 dependencies in all for `parentchart` + ``` subchart new-subchart-1 @@ -283,9 +283,10 @@ dependencies: condition: subchart2.enabled,global.subchart2.enabled tags: - back-end - - subchart2 + - subchart2 ``` + ```yaml # parentchart/values.yaml @@ -294,7 +295,7 @@ subchart1: tags: front-end: false back-end: true -```` +``` In the above example all charts with the tag `front-end` would be disabled but since the `subchart1.enabled` path evaluates to 'true' in the parent's values, the condition will override the @@ -314,12 +315,11 @@ helm install --set tags.front-end=true --set subchart2.enabled=false ##### Tags and Condition Resolution - - * **Conditions (when set in values) always override tags.** The first condition - path that exists wins and subsequent ones for that chart are ignored. - * Tags are evaluated as 'if any of the chart's tags are true then enable the chart'. - * Tags and conditions values must be set in the top parent's values. - * The `tags:` key in values must be a top level key. Globals and nested `tags:` tables +- **Conditions (when set in values) always override tags.** +- The first condition path that exists wins and subsequent ones for that chart are ignored. +- Tags are evaluated as 'if any of the chart's tags are true then enable the chart'. +- Tags and conditions values must be set in the top parent's values. +- The `tags:` key in values must be a top level key. Globals and nested `tags:` tables are not currently supported. #### Importing Child Values via requirements.yaml @@ -345,6 +345,7 @@ directly into the parent's values by specifying the keys to import as in the exa import-values: - data ``` + ```yaml # child's values.yaml file ... @@ -388,6 +389,7 @@ dependencies: - child: default.data parent: myimports ``` + In the above example, values found at `default.data` in the subchart1's values will be imported to the `myimports` key in the parent chart's values as detailed below: @@ -400,6 +402,7 @@ myimports: mystring: "helm rocks!" ``` + ```yaml # subchart1's values.yaml file @@ -409,6 +412,7 @@ default: mybool: true ``` + The parent chart's resulting values would be: ```yaml @@ -511,10 +515,10 @@ through the template engine. Values for the templates are supplied two ways: - - Chart developers may supply a file called `values.yaml` inside of a - chart. This file can contain default values. - - Chart users may supply a YAML file that contains values. This can be - provided on the command line with `helm install`. +- Chart developers may supply a file called `values.yaml` inside of a + chart. This file can contain default values. +- Chart users may supply a YAML file that contains values. This can be + provided on the command line with `helm install`. When a user supplies custom values, these values will override the values in the chart's `values.yaml` file. From 03718ee93d3dd290471554d6f4703c2e1539e1a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=AFo=D0=BD=D0=B8=D0=B8=CE=B3=20=C4=AFo=D0=BD=D0=B8?= =?UTF-8?q?=D0=B8=CE=B3?= Date: Wed, 5 Dec 2018 10:08:06 -0800 Subject: [PATCH 026/146] Added extra padding to resources template (#4981) This is probably a silly PR. However, each time I create a new chart via `helm create`, the instructions to uncomment the resource limits require adding a couple extra spaces back to the YAML. This PR simply brings the spacing in-line with the rest of the generated template. Signed-off-by: John Dewey --- pkg/chartutil/create.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/chartutil/create.go b/pkg/chartutil/create.go index 9063ed12a..82d307ded 100644 --- a/pkg/chartutil/create.go +++ b/pkg/chartutil/create.go @@ -89,11 +89,11 @@ resources: {} # resources, such as Minikube. If you do want to specify resources, uncomment the following # lines, adjust them as necessary, and remove the curly braces after 'resources:'. # limits: - # cpu: 100m - # memory: 128Mi + # cpu: 100m + # memory: 128Mi # requests: - # cpu: 100m - # memory: 128Mi + # cpu: 100m + # memory: 128Mi nodeSelector: {} From 6d3809a416e722bd6212d637ad9da25d0d954f7f Mon Sep 17 00:00:00 2001 From: Taylor Thomas Date: Wed, 5 Dec 2018 10:45:49 -0800 Subject: [PATCH 027/146] ref(kube): Gets rid of superfluous Sprintf call Signed-off-by: Taylor Thomas --- pkg/kube/client.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/kube/client.go b/pkg/kube/client.go index b60b0cfc2..4a387d524 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -220,8 +220,7 @@ func (c *Client) Get(namespace string, reader io.Reader) (string, error) { buf := new(bytes.Buffer) printFlags := get.NewHumanPrintFlags() for t, ot := range objs { - kindHeader := fmt.Sprintf("==> %s\n", t) - if _, err = buf.WriteString(kindHeader); err != nil { + if _, err = fmt.Fprintf(buf, "==> %s\n", t); err != nil { return "", err } typePrinter, _ := printFlags.ToPrinter("") From c80f7ddaebdb5789f3fb75012b07ad64a098af92 Mon Sep 17 00:00:00 2001 From: Henry Nash Date: Wed, 5 Dec 2018 19:41:52 +0000 Subject: [PATCH 028/146] docs(helm): Mention commit signing in the Developer Guide (#5018) This change adds a mention to the reqruiement for commit signing to the Git Convention outline in the Developer Guide, while leaving the existing detail on signing in the Contributing doc. Closes #5016 Signed-off-by: Henry Nash --- docs/developers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/developers.md b/docs/developers.md index 4f1da2d96..4edc4bea1 100644 --- a/docs/developers.md +++ b/docs/developers.md @@ -167,7 +167,7 @@ workflow for doing this is as follows: 3. Add your repository as a remote for `$GOPATH/src/k8s.io/helm` 4. Create a new working branch (`git checkout -b feat/my-feature`) and do your work on that branch. -5. When you are ready for us to review, push your branch to GitHub, and +5. When you are ready for us to review, sign your commit, push your branch to GitHub, and then open a new pull request with us. For Git commit messages, we follow the [Semantic Commit Messages](http://karma-runner.github.io/0.13/dev/git-commit-msg.html): From dc186e12c3bd7f0c6442d8501d2439071197836e Mon Sep 17 00:00:00 2001 From: tariqibrahim Date: Tue, 4 Dec 2018 23:57:41 -0800 Subject: [PATCH 029/146] remove for k8s.io/kubernetes deps for simple pod and svc util methods Signed-off-by: tariqibrahim --- pkg/kube/wait.go | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/pkg/kube/wait.go b/pkg/kube/wait.go index 960409df9..105d79b93 100644 --- a/pkg/kube/wait.go +++ b/pkg/kube/wait.go @@ -29,8 +29,6 @@ import ( "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/kubernetes" - podutil "k8s.io/kubernetes/pkg/api/v1/pod" - "k8s.io/kubernetes/pkg/apis/core/v1/helper" deploymentutil "k8s.io/kubernetes/pkg/controller/deployment/util" ) @@ -203,7 +201,7 @@ func (c *Client) waitForResources(timeout time.Duration, created Result) error { func (c *Client) podsReady(pods []v1.Pod) bool { for _, pod := range pods { - if !podutil.IsPodReady(&pod) { + if !isPodReady(&pod) { c.Log("Pod is not ready: %s/%s", pod.GetNamespace(), pod.GetName()) return false } @@ -219,7 +217,7 @@ func (c *Client) servicesReady(svc []v1.Service) bool { } // 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 && s.Spec.ClusterIP == "" { c.Log("Service is not ready: %s/%s", s.GetNamespace(), s.GetName()) return false } @@ -259,3 +257,15 @@ func getPods(client kubernetes.Interface, namespace string, selector map[string] }) return list.Items, err } + +func isPodReady(pod *v1.Pod) bool { + if &pod.Status != nil && len(pod.Status.Conditions) > 0 { + for _, condition := range pod.Status.Conditions { + if condition.Type == v1.PodReady && + condition.Status == v1.ConditionTrue { + return true + } + } + } + return false +} From adce632c830b28ca5bf56e5a9df583a06cacef82 Mon Sep 17 00:00:00 2001 From: Henry Nash Date: Wed, 5 Dec 2018 21:06:46 +0000 Subject: [PATCH 030/146] fix(helm): get rid of lint warning in pkg/storage (#5021) Provide comment for constant to avoid golint warning. Closes #5020 Signed-off-by: Henry Nash --- pkg/storage/storage.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/storage/storage.go b/pkg/storage/storage.go index e0e39ac0c..9520db08b 100644 --- a/pkg/storage/storage.go +++ b/pkg/storage/storage.go @@ -25,6 +25,7 @@ import ( "k8s.io/helm/pkg/storage/driver" ) +// NoReleasesErr indicates that a given release cannot be found const NoReleasesErr = "has no deployed releases" // Storage represents a storage engine for a Release. From 146c61af3765417c4b0d95bbb1a4ad73d3c228c9 Mon Sep 17 00:00:00 2001 From: Henry Nash Date: Wed, 5 Dec 2018 21:08:51 +0000 Subject: [PATCH 031/146] fix(helm): Correct and improve resilence of template check in unit test (#5010) Make the current check for the number of templates on create more resilient by using a varible to store the expected number of templates. In addition, fix the error message so that it displays the correct number expected of templates. Closes #5009 Signed-off-by: Henry Nash --- cmd/helm/create_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd/helm/create_test.go b/cmd/helm/create_test.go index 3cdf5ebf8..c9459b477 100644 --- a/cmd/helm/create_test.go +++ b/cmd/helm/create_test.go @@ -143,8 +143,9 @@ func TestCreateStarterCmd(t *testing.T) { t.Errorf("Wrong API version: %q", c.Metadata.ApiVersion) } - if l := len(c.Templates); l != 7 { - t.Errorf("Expected 6 templates, got %d", l) + expectedTemplateCount := 7 + if l := len(c.Templates); l != expectedTemplateCount { + t.Errorf("Expected %d templates, got %d", expectedTemplateCount, l) } found := false From 15703cb19942bba7b2f5f8355dee2947e542fdda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helgi=20=C3=9Eormar=20=C3=9Eorbj=C3=B6rnsson?= <70530+helgi@users.noreply.github.com> Date: Wed, 5 Dec 2018 13:30:42 -0800 Subject: [PATCH 032/146] Return empty string instead of nil when linting on required (#4748) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Return empty string instead of nil when linting on required This allows lint to work in scenarios when required is used in secrets or it's output is passed to another function. Due to lint mode no longer failing on missing value in required it is passing nil through which not all functions can accept. Fixes #4747 Signed-off-by: Helgi Þorbjörnsson * Apply suggestions from code review Co-Authored-By: helgi <70530+helgi@users.noreply.github.com> Signed-off-by: Helgi Þorbjörnsson * Add tests Signed-off-by: Helgi Þorbjörnsson --- pkg/engine/engine.go | 5 +++-- pkg/engine/engine_test.go | 27 ++++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index 9f212ba09..f3dd869c9 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -159,9 +159,10 @@ func (e *Engine) alterFuncMap(t *template.Template, referenceTpls map[string]ren if e.LintMode { // Don't fail on missing required values when linting log.Printf("[INFO] Missing required value: %s", warn) - return val, nil + return "", nil } - return val, fmt.Errorf(warn) + // Convert nil to "" in case required is piped into other functions + return "", fmt.Errorf(warn) } else if _, ok := val.(string); ok { if val == "" { if e.LintMode { diff --git a/pkg/engine/engine_test.go b/pkg/engine/engine_test.go index 91a3fd795..712b3b3df 100644 --- a/pkg/engine/engine_test.go +++ b/pkg/engine/engine_test.go @@ -466,7 +466,6 @@ func TestAlterFuncMap(t *testing.T) { if err != nil { t.Fatal(err) } - expectStr := "All your base are belong to us" if gotStr := outReq["conan/templates/quote"]; gotStr != expectStr { t.Errorf("Expected %q, got %q (%v)", expectStr, gotStr, outReq) @@ -476,6 +475,32 @@ func TestAlterFuncMap(t *testing.T) { t.Errorf("Expected %q, got %q (%v)", expectNum, gotNum, outReq) } + // test required without passing in needed values with lint mode on + // verifies lint replaces required with an empty string (should not fail) + lintValues := chartutil.Values{ + "Values": chartutil.Values{ + "who": "us", + }, + "Chart": reqChart.Metadata, + "Release": chartutil.Values{ + "Name": "That 90s meme", + }, + } + e := New() + e.LintMode = true + outReq, err = e.Render(reqChart, lintValues) + if err != nil { + t.Fatal(err) + } + expectStr = "All your base are belong to us" + if gotStr := outReq["conan/templates/quote"]; gotStr != expectStr { + t.Errorf("Expected %q, got %q (%v)", expectStr, gotStr, outReq) + } + expectNum = "All of them!" + if gotNum := outReq["conan/templates/bases"]; gotNum != expectNum { + t.Errorf("Expected %q, got %q (%v)", expectNum, gotNum, outReq) + } + tplChart := &chart.Chart{ Metadata: &chart.Metadata{Name: "TplFunction"}, Templates: []*chart.Template{ From 158d6dbb746f525bad9a0aacb698af7d370ac3f5 Mon Sep 17 00:00:00 2001 From: Frank Hamand Date: Wed, 5 Dec 2018 22:04:48 +0000 Subject: [PATCH 033/146] Add --parallel flag to helm test (#4144) * Refactor test run to separate method This will allow us to parallelise it more easily Signed-off-by: Frank Hamand * Add --parallel flag to helm test (No functionality in this commit) Signed-off-by: Frank Hamand * Run helm tests in parallel with --parallel flag Signed-off-by: Frank Hamand * Add a mutex to helm test message streams This is to protect against data races when running tests in parallel. Signed-off-by: Frank Hamand * Add tests for --parallel flag Signed-off-by: Frank Hamand * Add concurrency limit for parallel helm tests Signed-off-by: Frank Hamand * Add test for concurrency limit Signed-off-by: Frank Hamand * Fix rebase introduced errors Signed-off-by: Frank Hamand --- _proto/hapi/services/tiller.proto | 2 + cmd/helm/release_testing.go | 13 +- docs/helm/helm_test.md | 3 +- glide.lock | 8 +- glide.yaml | 4 +- pkg/helm/option.go | 7 + pkg/proto/hapi/services/tiller.pb.go | 172 +++++++++++++------------ pkg/releasetesting/environment.go | 14 +- pkg/releasetesting/environment_test.go | 9 +- pkg/releasetesting/test_suite.go | 92 +++++++++---- pkg/releasetesting/test_suite_test.go | 121 +++++++++++++++++ pkg/tiller/release_testing.go | 12 +- 12 files changed, 329 insertions(+), 128 deletions(-) diff --git a/_proto/hapi/services/tiller.proto b/_proto/hapi/services/tiller.proto index 6c44ce6e0..8eba963e4 100644 --- a/_proto/hapi/services/tiller.proto +++ b/_proto/hapi/services/tiller.proto @@ -339,6 +339,8 @@ message TestReleaseRequest { int64 timeout = 2; // cleanup specifies whether or not to attempt pod deletion after test completes bool cleanup = 3; + // parallel specifies whether or not to run test pods in parallel + bool parallel = 4; } // TestReleaseResponse represents a message from executing a test diff --git a/cmd/helm/release_testing.go b/cmd/helm/release_testing.go index f39d9b81f..91c0d7189 100644 --- a/cmd/helm/release_testing.go +++ b/cmd/helm/release_testing.go @@ -34,11 +34,12 @@ The tests to be run are defined in the chart that was installed. ` type releaseTestCmd struct { - name string - out io.Writer - client helm.Interface - timeout int64 - cleanup bool + name string + out io.Writer + client helm.Interface + timeout int64 + cleanup bool + parallel bool } func newReleaseTestCmd(c helm.Interface, out io.Writer) *cobra.Command { @@ -67,6 +68,7 @@ func newReleaseTestCmd(c helm.Interface, out io.Writer) *cobra.Command { settings.AddFlagsTLS(f) f.Int64Var(&rlsTest.timeout, "timeout", 300, "time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks)") f.BoolVar(&rlsTest.cleanup, "cleanup", false, "delete test pods upon completion") + f.BoolVar(&rlsTest.parallel, "parallel", false, "run test pods in parallel") // set defaults from environment settings.InitTLS(f) @@ -79,6 +81,7 @@ func (t *releaseTestCmd) run() (err error) { t.name, helm.ReleaseTestTimeout(t.timeout), helm.ReleaseTestCleanup(t.cleanup), + helm.ReleaseTestParallel(t.parallel), ) testErr := &testErr{} diff --git a/docs/helm/helm_test.md b/docs/helm/helm_test.md index e55c5df68..e8ddfbc9b 100644 --- a/docs/helm/helm_test.md +++ b/docs/helm/helm_test.md @@ -20,6 +20,7 @@ helm test [RELEASE] [flags] ``` --cleanup delete test pods upon completion -h, --help help for test + --parallel run test pods in parallel --timeout int time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks) (default 300) --tls enable TLS for request --tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem") @@ -45,4 +46,4 @@ helm test [RELEASE] [flags] * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 10-Aug-2018 +###### Auto generated by spf13/cobra on 9-Nov-2018 diff --git a/glide.lock b/glide.lock index 16ea64ff5..c6bec006d 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: fcbba2207c6511df365dfe355dfe601a862d340bbf15db47938a404fd0ec58d0 -updated: 2018-11-11T19:26:29.631232-05:00 +hash: 813d803db5fc2cb46f8050190d2a307f247da5b7b3a4b00eb4d3e766882ad4f9 +updated: 2018-11-30T10:55:17.417707Z imports: - name: cloud.google.com/go version: 3b1ae45394a234c385be014e9a488f2bb6eef821 @@ -290,6 +290,10 @@ imports: - internal - jws - jwt +- name: golang.org/x/sync + version: 1d60e4601c6fd243af51cc01ddf169918a5407ca + subpackages: + - semaphore - name: golang.org/x/sys version: 95c6576299259db960f6c5b9b69ea52422860fce subpackages: diff --git a/glide.yaml b/glide.yaml index f0028b579..52cee8142 100644 --- a/glide.yaml +++ b/glide.yaml @@ -3,6 +3,9 @@ import: - package: golang.org/x/net subpackages: - context + - package: golang.org/x/sync + subpackages: + - semaphore - package: github.com/spf13/cobra version: fe5e611709b0c57fa4a89136deaa8e1d4004d053 - package: github.com/spf13/pflag @@ -41,7 +44,6 @@ import: - package: github.com/prometheus/client_golang version: 0.8.0 - package: github.com/grpc-ecosystem/go-grpc-prometheus - - package: k8s.io/kubernetes version: release-1.12 - package: k8s.io/client-go diff --git a/pkg/helm/option.go b/pkg/helm/option.go index 5579ae76d..f41d9c6ae 100644 --- a/pkg/helm/option.go +++ b/pkg/helm/option.go @@ -227,6 +227,13 @@ func ReleaseTestCleanup(cleanup bool) ReleaseTestOption { } } +// ReleaseTestParallel is a boolean value representing whether to run test pods in parallel +func ReleaseTestParallel(parallel bool) ReleaseTestOption { + return func(opts *options) { + opts.testReq.Parallel = parallel + } +} + // RollbackTimeout specifies the number of seconds before kubernetes calls timeout func RollbackTimeout(timeout int64) RollbackOption { return func(opts *options) { diff --git a/pkg/proto/hapi/services/tiller.pb.go b/pkg/proto/hapi/services/tiller.pb.go index 044d54e91..f57ad8582 100644 --- a/pkg/proto/hapi/services/tiller.pb.go +++ b/pkg/proto/hapi/services/tiller.pb.go @@ -883,6 +883,8 @@ type TestReleaseRequest struct { Timeout int64 `protobuf:"varint,2,opt,name=timeout" json:"timeout,omitempty"` // cleanup specifies whether or not to attempt pod deletion after test completes Cleanup bool `protobuf:"varint,3,opt,name=cleanup" json:"cleanup,omitempty"` + // parallel specifies whether or not to run test pods in parallel + Parallel bool `protobuf:"varint,4,opt,name=parallel" json:"parallel,omitempty"` } func (m *TestReleaseRequest) Reset() { *m = TestReleaseRequest{} } @@ -911,6 +913,13 @@ func (m *TestReleaseRequest) GetCleanup() bool { return false } +func (m *TestReleaseRequest) GetParallel() bool { + if m != nil { + return m.Parallel + } + return false +} + // TestReleaseResponse represents a message from executing a test type TestReleaseResponse struct { Msg string `protobuf:"bytes,1,opt,name=msg" json:"msg,omitempty"` @@ -1415,85 +1424,86 @@ var _ReleaseService_serviceDesc = grpc.ServiceDesc{ func init() { proto.RegisterFile("hapi/services/tiller.proto", fileDescriptor0) } var fileDescriptor0 = []byte{ - // 1276 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x57, 0xdd, 0x6e, 0xe3, 0x44, - 0x14, 0x6e, 0xe2, 0xfc, 0x9e, 0x74, 0x43, 0x76, 0x36, 0xdb, 0x7a, 0xcd, 0x82, 0x82, 0x11, 0x6c, - 0x76, 0x61, 0x53, 0x08, 0xdc, 0x20, 0x21, 0xa4, 0x6e, 0x36, 0x6a, 0x0b, 0xa5, 0x2b, 0x39, 0xed, - 0x22, 0x21, 0x50, 0xe4, 0x26, 0x93, 0xd6, 0xac, 0x63, 0x07, 0xcf, 0xb8, 0x6c, 0x1f, 0x00, 0x24, - 0xde, 0x83, 0x07, 0xe1, 0x3d, 0x78, 0x0e, 0xee, 0x91, 0xe7, 0xc7, 0xf5, 0x38, 0x76, 0x6a, 0x7a, - 0xd3, 0x78, 0xe6, 0x9c, 0x39, 0x3f, 0xdf, 0x37, 0xe7, 0xcc, 0x29, 0x18, 0x97, 0xf6, 0xca, 0xd9, - 0x23, 0x38, 0xb8, 0x72, 0x66, 0x98, 0xec, 0x51, 0xc7, 0x75, 0x71, 0x30, 0x58, 0x05, 0x3e, 0xf5, - 0x51, 0x37, 0x92, 0x0d, 0xa4, 0x6c, 0xc0, 0x65, 0xc6, 0x0e, 0x3b, 0x31, 0xbb, 0xb4, 0x03, 0xca, - 0xff, 0x72, 0x6d, 0x63, 0x37, 0xb9, 0xef, 0x7b, 0x0b, 0xe7, 0x42, 0x08, 0xb8, 0x8b, 0x00, 0xbb, - 0xd8, 0x26, 0x58, 0xfe, 0x2a, 0x87, 0xa4, 0xcc, 0xf1, 0x16, 0xbe, 0x10, 0xbc, 0xab, 0x08, 0x28, - 0x26, 0x74, 0x1a, 0x84, 0x9e, 0x10, 0x3e, 0x52, 0x84, 0x84, 0xda, 0x34, 0x24, 0x8a, 0xb3, 0x2b, - 0x1c, 0x10, 0xc7, 0xf7, 0xe4, 0x2f, 0x97, 0x99, 0x7f, 0x97, 0xe1, 0xc1, 0xb1, 0x43, 0xa8, 0xc5, - 0x0f, 0x12, 0x0b, 0xff, 0x1a, 0x62, 0x42, 0x51, 0x17, 0xaa, 0xae, 0xb3, 0x74, 0xa8, 0x5e, 0xea, - 0x95, 0xfa, 0x9a, 0xc5, 0x17, 0x68, 0x07, 0x6a, 0xfe, 0x62, 0x41, 0x30, 0xd5, 0xcb, 0xbd, 0x52, - 0xbf, 0x69, 0x89, 0x15, 0xfa, 0x06, 0xea, 0xc4, 0x0f, 0xe8, 0xf4, 0xfc, 0x5a, 0xd7, 0x7a, 0xa5, - 0x7e, 0x7b, 0xf8, 0xd1, 0x20, 0x0b, 0xa7, 0x41, 0xe4, 0x69, 0xe2, 0x07, 0x74, 0x10, 0xfd, 0x79, - 0x71, 0x6d, 0xd5, 0x08, 0xfb, 0x8d, 0xec, 0x2e, 0x1c, 0x97, 0xe2, 0x40, 0xaf, 0x70, 0xbb, 0x7c, - 0x85, 0x0e, 0x00, 0x98, 0x5d, 0x3f, 0x98, 0xe3, 0x40, 0xaf, 0x32, 0xd3, 0xfd, 0x02, 0xa6, 0x5f, - 0x45, 0xfa, 0x56, 0x93, 0xc8, 0x4f, 0xf4, 0x35, 0x6c, 0x73, 0x48, 0xa6, 0x33, 0x7f, 0x8e, 0x89, - 0x5e, 0xeb, 0x69, 0xfd, 0xf6, 0xf0, 0x11, 0x37, 0x25, 0xe1, 0x9f, 0x70, 0xd0, 0x46, 0xfe, 0x1c, - 0x5b, 0x2d, 0xae, 0x1e, 0x7d, 0x13, 0xf4, 0x18, 0x9a, 0x9e, 0xbd, 0xc4, 0x64, 0x65, 0xcf, 0xb0, - 0x5e, 0x67, 0x11, 0xde, 0x6c, 0x98, 0x1e, 0x34, 0xa4, 0x73, 0xf3, 0x05, 0xd4, 0x78, 0x6a, 0xa8, - 0x05, 0xf5, 0xb3, 0x93, 0xef, 0x4e, 0x5e, 0xfd, 0x70, 0xd2, 0xd9, 0x42, 0x0d, 0xa8, 0x9c, 0xec, - 0x7f, 0x3f, 0xee, 0x94, 0xd0, 0x7d, 0xb8, 0x77, 0xbc, 0x3f, 0x39, 0x9d, 0x5a, 0xe3, 0xe3, 0xf1, - 0xfe, 0x64, 0xfc, 0xb2, 0x53, 0x46, 0x6d, 0x80, 0xd1, 0xe1, 0xbe, 0x75, 0x3a, 0x65, 0x2a, 0x9a, - 0xf9, 0x3e, 0x34, 0xe3, 0x1c, 0x50, 0x1d, 0xb4, 0xfd, 0xc9, 0x88, 0x9b, 0x78, 0x39, 0x9e, 0x8c, - 0x3a, 0x25, 0xf3, 0xcf, 0x12, 0x74, 0x55, 0xca, 0xc8, 0xca, 0xf7, 0x08, 0x8e, 0x38, 0x9b, 0xf9, - 0xa1, 0x17, 0x73, 0xc6, 0x16, 0x08, 0x41, 0xc5, 0xc3, 0x6f, 0x25, 0x63, 0xec, 0x3b, 0xd2, 0xa4, - 0x3e, 0xb5, 0x5d, 0xc6, 0x96, 0x66, 0xf1, 0x05, 0xfa, 0x1c, 0x1a, 0x02, 0x0a, 0xa2, 0x57, 0x7a, - 0x5a, 0xbf, 0x35, 0x7c, 0xa8, 0x02, 0x24, 0x3c, 0x5a, 0xb1, 0x9a, 0x79, 0x00, 0xbb, 0x07, 0x58, - 0x46, 0xc2, 0xf1, 0x93, 0x37, 0x28, 0xf2, 0x6b, 0x2f, 0x31, 0x0b, 0x26, 0xf2, 0x6b, 0x2f, 0x31, - 0xd2, 0xa1, 0x2e, 0xae, 0x1f, 0x0b, 0xa7, 0x6a, 0xc9, 0xa5, 0x49, 0x41, 0x5f, 0x37, 0x24, 0xf2, - 0xca, 0xb2, 0xf4, 0x31, 0x54, 0xa2, 0xca, 0x60, 0x66, 0x5a, 0x43, 0xa4, 0xc6, 0x79, 0xe4, 0x2d, - 0x7c, 0x8b, 0xc9, 0x55, 0xea, 0xb4, 0x34, 0x75, 0x87, 0x49, 0xaf, 0x23, 0xdf, 0xa3, 0xd8, 0xa3, - 0x77, 0x8b, 0xff, 0x18, 0x1e, 0x65, 0x58, 0x12, 0x09, 0xec, 0x41, 0x5d, 0x84, 0xc6, 0xac, 0xe5, - 0xe2, 0x2a, 0xb5, 0xcc, 0xdf, 0x35, 0xe8, 0x9e, 0xad, 0xe6, 0x36, 0xc5, 0x52, 0xb4, 0x21, 0xa8, - 0x27, 0x50, 0x65, 0x1d, 0x46, 0x60, 0x71, 0x9f, 0xdb, 0xe6, 0x6d, 0x68, 0x14, 0xfd, 0xb5, 0xb8, - 0x1c, 0x3d, 0x83, 0xda, 0x95, 0xed, 0x86, 0x98, 0x30, 0x20, 0x62, 0xd4, 0x84, 0x26, 0x6b, 0x4f, - 0x96, 0xd0, 0x40, 0xbb, 0x50, 0x9f, 0x07, 0xd7, 0x51, 0x7f, 0x61, 0x25, 0xd9, 0xb0, 0x6a, 0xf3, - 0xe0, 0xda, 0x0a, 0x3d, 0xf4, 0x21, 0xdc, 0x9b, 0x3b, 0xc4, 0x3e, 0x77, 0xf1, 0xf4, 0xd2, 0xf7, - 0xdf, 0x10, 0x56, 0x95, 0x0d, 0x6b, 0x5b, 0x6c, 0x1e, 0x46, 0x7b, 0xc8, 0x88, 0x6e, 0xd2, 0x2c, - 0xc0, 0x36, 0xc5, 0x7a, 0x8d, 0xc9, 0xe3, 0x75, 0x84, 0x21, 0x75, 0x96, 0xd8, 0x0f, 0x29, 0x2b, - 0x25, 0xcd, 0x92, 0x4b, 0xf4, 0x01, 0x6c, 0x07, 0x98, 0x60, 0x3a, 0x15, 0x51, 0x36, 0xd8, 0xc9, - 0x16, 0xdb, 0x7b, 0xcd, 0xc3, 0x42, 0x50, 0xf9, 0xcd, 0x76, 0xa8, 0xde, 0x64, 0x22, 0xf6, 0xcd, - 0x8f, 0x85, 0x04, 0xcb, 0x63, 0x20, 0x8f, 0x85, 0x04, 0x8b, 0x63, 0x5d, 0xa8, 0x2e, 0xfc, 0x60, - 0x86, 0xf5, 0x16, 0x93, 0xf1, 0x05, 0xea, 0x41, 0x6b, 0x8e, 0xc9, 0x2c, 0x70, 0x56, 0x34, 0x62, - 0x74, 0x9b, 0x61, 0x9a, 0xdc, 0x32, 0x0f, 0xe1, 0x61, 0x8a, 0x86, 0xbb, 0x32, 0xfa, 0x47, 0x19, - 0x76, 0x2c, 0xdf, 0x75, 0xcf, 0xed, 0xd9, 0x9b, 0x02, 0x9c, 0x26, 0xe0, 0x2f, 0x6f, 0x86, 0x5f, - 0xcb, 0x80, 0x3f, 0x71, 0x4d, 0x2b, 0xca, 0x35, 0x55, 0x88, 0xa9, 0xe6, 0x13, 0x53, 0x53, 0x89, - 0x91, 0xa8, 0xd7, 0x13, 0xa8, 0xc7, 0x90, 0x36, 0x36, 0x40, 0xda, 0x5c, 0x87, 0xf4, 0x5b, 0xd8, - 0x5d, 0xc3, 0xe1, 0xae, 0xa0, 0xfe, 0x5b, 0x86, 0x87, 0x47, 0x1e, 0xa1, 0xb6, 0xeb, 0xa6, 0x30, - 0x8d, 0x6b, 0xa2, 0x54, 0xb8, 0x26, 0xca, 0xff, 0xa7, 0x26, 0x34, 0x85, 0x14, 0xc9, 0x60, 0x25, - 0xc1, 0x60, 0xa1, 0x3a, 0x51, 0xba, 0x53, 0x2d, 0xd5, 0x9d, 0xd0, 0x7b, 0x00, 0xfc, 0x62, 0x33, - 0xe3, 0x1c, 0xfc, 0x26, 0xdb, 0x39, 0x11, 0xcd, 0x48, 0xf2, 0xd5, 0xc8, 0xe6, 0x2b, 0x59, 0x25, - 0x7d, 0xe8, 0xc8, 0x78, 0x66, 0xc1, 0x9c, 0xc5, 0x24, 0x2a, 0xa5, 0x2d, 0xf6, 0x47, 0xc1, 0x3c, - 0x8a, 0x2a, 0xcd, 0x61, 0x6b, 0x9d, 0xc3, 0x23, 0xd8, 0x49, 0xc3, 0x7e, 0x57, 0x0a, 0xff, 0x2a, - 0xc1, 0xee, 0x99, 0xe7, 0x64, 0x92, 0x98, 0x55, 0x18, 0x6b, 0xb0, 0x96, 0x33, 0x60, 0xed, 0x42, - 0x75, 0x15, 0x06, 0x17, 0x58, 0xd0, 0xc4, 0x17, 0x49, 0xbc, 0x2a, 0x2a, 0x5e, 0xa9, 0x8c, 0xab, - 0xeb, 0x19, 0x4f, 0x41, 0x5f, 0x8f, 0xf2, 0x8e, 0x39, 0x47, 0x79, 0xc5, 0x6f, 0x57, 0x93, 0xbf, - 0x53, 0xe6, 0x03, 0xb8, 0x7f, 0x80, 0xe9, 0x6b, 0x5e, 0xa6, 0x02, 0x00, 0x73, 0x0c, 0x28, 0xb9, - 0x79, 0xe3, 0x4f, 0x6c, 0xa9, 0xfe, 0xe4, 0x60, 0x27, 0xf5, 0xa5, 0x96, 0xf9, 0x15, 0xb3, 0x7d, - 0xe8, 0x10, 0xea, 0x07, 0xd7, 0x9b, 0xc0, 0xed, 0x80, 0xb6, 0xb4, 0xdf, 0x8a, 0xa7, 0x2d, 0xfa, - 0x34, 0x0f, 0x58, 0x04, 0xf1, 0x51, 0x11, 0x41, 0x72, 0x50, 0x28, 0x15, 0x1b, 0x14, 0x7e, 0x02, - 0x74, 0x8a, 0xe3, 0x99, 0xe5, 0x96, 0x37, 0x56, 0xd2, 0x54, 0x56, 0x69, 0xd2, 0xa1, 0x3e, 0x73, - 0xb1, 0xed, 0x85, 0x2b, 0x41, 0xac, 0x5c, 0x9a, 0x3f, 0xc3, 0x03, 0xc5, 0xba, 0x88, 0x33, 0xca, - 0x87, 0x5c, 0x08, 0xeb, 0xd1, 0x27, 0xfa, 0x12, 0x6a, 0x7c, 0xb0, 0x63, 0xb6, 0xdb, 0xc3, 0xc7, - 0x6a, 0xdc, 0xcc, 0x48, 0xe8, 0x89, 0x49, 0xd0, 0x12, 0xba, 0xc3, 0x7f, 0x1a, 0xd0, 0x96, 0xa3, - 0x09, 0x1f, 0x3b, 0x91, 0x03, 0xdb, 0xc9, 0x19, 0x0c, 0x3d, 0xcd, 0x9f, 0x4a, 0x53, 0xa3, 0xb5, - 0xf1, 0xac, 0x88, 0x2a, 0xcf, 0xc0, 0xdc, 0xfa, 0xac, 0x84, 0x08, 0x74, 0xd2, 0xa3, 0x11, 0x7a, - 0x9e, 0x6d, 0x23, 0x67, 0x16, 0x33, 0x06, 0x45, 0xd5, 0xa5, 0x5b, 0x74, 0xc5, 0xee, 0x8c, 0x3a, - 0xcf, 0xa0, 0x5b, 0xcd, 0xa8, 0x23, 0x94, 0xb1, 0x57, 0x58, 0x3f, 0xf6, 0xfb, 0x0b, 0xdc, 0x53, - 0x5e, 0x5c, 0x94, 0x83, 0x56, 0xd6, 0x74, 0x64, 0x7c, 0x52, 0x48, 0x37, 0xf6, 0xb5, 0x84, 0xb6, - 0xda, 0xc6, 0x50, 0x8e, 0x81, 0xcc, 0x37, 0xc6, 0xf8, 0xb4, 0x98, 0x72, 0xec, 0x8e, 0x40, 0x27, - 0xdd, 0x43, 0xf2, 0x78, 0xcc, 0xe9, 0x88, 0x79, 0x3c, 0xe6, 0xb5, 0x26, 0x73, 0x0b, 0xd9, 0x00, - 0x37, 0x2d, 0x04, 0x3d, 0xc9, 0x25, 0x44, 0xed, 0x3c, 0x46, 0xff, 0x76, 0xc5, 0xd8, 0xc5, 0x0a, - 0xde, 0x49, 0xbd, 0xe8, 0x28, 0x07, 0x9a, 0xec, 0x01, 0xc8, 0x78, 0x5e, 0x50, 0x3b, 0x95, 0x94, - 0xe8, 0x4a, 0x1b, 0x92, 0x52, 0x5b, 0xde, 0x86, 0xa4, 0x52, 0x0d, 0xce, 0xdc, 0x42, 0x0e, 0xb4, - 0xad, 0xd0, 0x13, 0xae, 0xa3, 0xb6, 0x80, 0x72, 0x4e, 0xaf, 0x77, 0x35, 0xe3, 0x69, 0x01, 0xcd, - 0x9b, 0xfa, 0x7e, 0x01, 0x3f, 0x36, 0xa4, 0xea, 0x79, 0x8d, 0xfd, 0x57, 0xfe, 0xc5, 0x7f, 0x01, - 0x00, 0x00, 0xff, 0xff, 0x38, 0x07, 0x4c, 0x12, 0x83, 0x10, 0x00, 0x00, + // 1289 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x57, 0xed, 0x72, 0xdb, 0x44, + 0x17, 0x8e, 0x2d, 0x7f, 0x1e, 0xa7, 0x7e, 0xdd, 0x6d, 0x9a, 0xa8, 0x7a, 0x0b, 0x63, 0xc4, 0x40, + 0xdd, 0x42, 0x1d, 0x30, 0xfc, 0x61, 0x86, 0x61, 0x26, 0x75, 0x3d, 0x49, 0x21, 0xa4, 0x33, 0x72, + 0x5b, 0x66, 0x98, 0x61, 0x3c, 0x8a, 0xbd, 0x6e, 0x45, 0x65, 0xc9, 0x68, 0x57, 0xa1, 0xb9, 0x00, + 0x98, 0xe1, 0x3e, 0xb8, 0x10, 0xee, 0x83, 0xeb, 0xe0, 0x3f, 0xb3, 0x5f, 0x8a, 0x56, 0x96, 0x1c, + 0x91, 0x3f, 0xb1, 0x76, 0xcf, 0xd9, 0xf3, 0xf1, 0x3c, 0x7b, 0xce, 0x9e, 0x80, 0xf5, 0xc6, 0x5d, + 0x7b, 0x87, 0x04, 0x47, 0x17, 0xde, 0x1c, 0x93, 0x43, 0xea, 0xf9, 0x3e, 0x8e, 0x86, 0xeb, 0x28, + 0xa4, 0x21, 0xda, 0x63, 0xb2, 0xa1, 0x92, 0x0d, 0x85, 0xcc, 0xda, 0xe7, 0x27, 0xe6, 0x6f, 0xdc, + 0x88, 0x8a, 0xbf, 0x42, 0xdb, 0x3a, 0x48, 0xef, 0x87, 0xc1, 0xd2, 0x7b, 0x2d, 0x05, 0xc2, 0x45, + 0x84, 0x7d, 0xec, 0x12, 0xac, 0x7e, 0xb5, 0x43, 0x4a, 0xe6, 0x05, 0xcb, 0x50, 0x0a, 0xfe, 0xaf, + 0x09, 0x28, 0x26, 0x74, 0x16, 0xc5, 0x81, 0x14, 0xde, 0xd3, 0x84, 0x84, 0xba, 0x34, 0x26, 0x9a, + 0xb3, 0x0b, 0x1c, 0x11, 0x2f, 0x0c, 0xd4, 0xaf, 0x90, 0xd9, 0x7f, 0x55, 0xe1, 0xce, 0xa9, 0x47, + 0xa8, 0x23, 0x0e, 0x12, 0x07, 0xff, 0x12, 0x63, 0x42, 0xd1, 0x1e, 0xd4, 0x7d, 0x6f, 0xe5, 0x51, + 0xb3, 0xd2, 0xaf, 0x0c, 0x0c, 0x47, 0x2c, 0xd0, 0x3e, 0x34, 0xc2, 0xe5, 0x92, 0x60, 0x6a, 0x56, + 0xfb, 0x95, 0x41, 0xdb, 0x91, 0x2b, 0xf4, 0x0d, 0x34, 0x49, 0x18, 0xd1, 0xd9, 0xf9, 0xa5, 0x69, + 0xf4, 0x2b, 0x83, 0xee, 0xe8, 0xa3, 0x61, 0x1e, 0x4e, 0x43, 0xe6, 0x69, 0x1a, 0x46, 0x74, 0xc8, + 0xfe, 0x3c, 0xb9, 0x74, 0x1a, 0x84, 0xff, 0x32, 0xbb, 0x4b, 0xcf, 0xa7, 0x38, 0x32, 0x6b, 0xc2, + 0xae, 0x58, 0xa1, 0x63, 0x00, 0x6e, 0x37, 0x8c, 0x16, 0x38, 0x32, 0xeb, 0xdc, 0xf4, 0xa0, 0x84, + 0xe9, 0xe7, 0x4c, 0xdf, 0x69, 0x13, 0xf5, 0x89, 0xbe, 0x86, 0x5d, 0x01, 0xc9, 0x6c, 0x1e, 0x2e, + 0x30, 0x31, 0x1b, 0x7d, 0x63, 0xd0, 0x1d, 0xdd, 0x13, 0xa6, 0x14, 0xfc, 0x53, 0x01, 0xda, 0x38, + 0x5c, 0x60, 0xa7, 0x23, 0xd4, 0xd9, 0x37, 0x41, 0xf7, 0xa1, 0x1d, 0xb8, 0x2b, 0x4c, 0xd6, 0xee, + 0x1c, 0x9b, 0x4d, 0x1e, 0xe1, 0xd5, 0x86, 0x1d, 0x40, 0x4b, 0x39, 0xb7, 0x9f, 0x40, 0x43, 0xa4, + 0x86, 0x3a, 0xd0, 0x7c, 0x79, 0xf6, 0xdd, 0xd9, 0xf3, 0x1f, 0xce, 0x7a, 0x3b, 0xa8, 0x05, 0xb5, + 0xb3, 0xa3, 0xef, 0x27, 0xbd, 0x0a, 0xba, 0x0d, 0xb7, 0x4e, 0x8f, 0xa6, 0x2f, 0x66, 0xce, 0xe4, + 0x74, 0x72, 0x34, 0x9d, 0x3c, 0xed, 0x55, 0x51, 0x17, 0x60, 0x7c, 0x72, 0xe4, 0xbc, 0x98, 0x71, + 0x15, 0xc3, 0x7e, 0x1f, 0xda, 0x49, 0x0e, 0xa8, 0x09, 0xc6, 0xd1, 0x74, 0x2c, 0x4c, 0x3c, 0x9d, + 0x4c, 0xc7, 0xbd, 0x8a, 0xfd, 0x47, 0x05, 0xf6, 0x74, 0xca, 0xc8, 0x3a, 0x0c, 0x08, 0x66, 0x9c, + 0xcd, 0xc3, 0x38, 0x48, 0x38, 0xe3, 0x0b, 0x84, 0xa0, 0x16, 0xe0, 0x77, 0x8a, 0x31, 0xfe, 0xcd, + 0x34, 0x69, 0x48, 0x5d, 0x9f, 0xb3, 0x65, 0x38, 0x62, 0x81, 0x3e, 0x87, 0x96, 0x84, 0x82, 0x98, + 0xb5, 0xbe, 0x31, 0xe8, 0x8c, 0xee, 0xea, 0x00, 0x49, 0x8f, 0x4e, 0xa2, 0x66, 0x1f, 0xc3, 0xc1, + 0x31, 0x56, 0x91, 0x08, 0xfc, 0xd4, 0x0d, 0x62, 0x7e, 0xdd, 0x15, 0xe6, 0xc1, 0x30, 0xbf, 0xee, + 0x0a, 0x23, 0x13, 0x9a, 0xf2, 0xfa, 0xf1, 0x70, 0xea, 0x8e, 0x5a, 0xda, 0x14, 0xcc, 0x4d, 0x43, + 0x32, 0xaf, 0x3c, 0x4b, 0x1f, 0x43, 0x8d, 0x55, 0x06, 0x37, 0xd3, 0x19, 0x21, 0x3d, 0xce, 0x67, + 0xc1, 0x32, 0x74, 0xb8, 0x5c, 0xa7, 0xce, 0xc8, 0x52, 0x77, 0x92, 0xf6, 0x3a, 0x0e, 0x03, 0x8a, + 0x03, 0x7a, 0xb3, 0xf8, 0x4f, 0xe1, 0x5e, 0x8e, 0x25, 0x99, 0xc0, 0x21, 0x34, 0x65, 0x68, 0xdc, + 0x5a, 0x21, 0xae, 0x4a, 0xcb, 0xfe, 0xcd, 0x80, 0xbd, 0x97, 0xeb, 0x85, 0x4b, 0xb1, 0x12, 0x6d, + 0x09, 0xea, 0x01, 0xd4, 0x79, 0x87, 0x91, 0x58, 0xdc, 0x16, 0xb6, 0x45, 0x1b, 0x1a, 0xb3, 0xbf, + 0x8e, 0x90, 0xa3, 0x47, 0xd0, 0xb8, 0x70, 0xfd, 0x18, 0x13, 0x0e, 0x44, 0x82, 0x9a, 0xd4, 0xe4, + 0xed, 0xc9, 0x91, 0x1a, 0xe8, 0x00, 0x9a, 0x8b, 0xe8, 0x92, 0xf5, 0x17, 0x5e, 0x92, 0x2d, 0xa7, + 0xb1, 0x88, 0x2e, 0x9d, 0x38, 0x40, 0x1f, 0xc2, 0xad, 0x85, 0x47, 0xdc, 0x73, 0x1f, 0xcf, 0xde, + 0x84, 0xe1, 0x5b, 0xc2, 0xab, 0xb2, 0xe5, 0xec, 0xca, 0xcd, 0x13, 0xb6, 0x87, 0x2c, 0x76, 0x93, + 0xe6, 0x11, 0x76, 0x29, 0x36, 0x1b, 0x5c, 0x9e, 0xac, 0x19, 0x86, 0xd4, 0x5b, 0xe1, 0x30, 0xa6, + 0xbc, 0x94, 0x0c, 0x47, 0x2d, 0xd1, 0x07, 0xb0, 0x1b, 0x61, 0x82, 0xe9, 0x4c, 0x46, 0xd9, 0xe2, + 0x27, 0x3b, 0x7c, 0xef, 0x95, 0x08, 0x0b, 0x41, 0xed, 0x57, 0xd7, 0xa3, 0x66, 0x9b, 0x8b, 0xf8, + 0xb7, 0x38, 0x16, 0x13, 0xac, 0x8e, 0x81, 0x3a, 0x16, 0x13, 0x2c, 0x8f, 0xed, 0x41, 0x7d, 0x19, + 0x46, 0x73, 0x6c, 0x76, 0xb8, 0x4c, 0x2c, 0x50, 0x1f, 0x3a, 0x0b, 0x4c, 0xe6, 0x91, 0xb7, 0xa6, + 0x8c, 0xd1, 0x5d, 0x8e, 0x69, 0x7a, 0xcb, 0x3e, 0x81, 0xbb, 0x19, 0x1a, 0x6e, 0xca, 0xe8, 0xef, + 0x55, 0xd8, 0x77, 0x42, 0xdf, 0x3f, 0x77, 0xe7, 0x6f, 0x4b, 0x70, 0x9a, 0x82, 0xbf, 0xba, 0x1d, + 0x7e, 0x23, 0x07, 0xfe, 0xd4, 0x35, 0xad, 0x69, 0xd7, 0x54, 0x23, 0xa6, 0x5e, 0x4c, 0x4c, 0x43, + 0x27, 0x46, 0xa1, 0xde, 0x4c, 0xa1, 0x9e, 0x40, 0xda, 0xda, 0x02, 0x69, 0x7b, 0x13, 0xd2, 0x6f, + 0xe1, 0x60, 0x03, 0x87, 0x9b, 0x82, 0xfa, 0x4f, 0x15, 0xee, 0x3e, 0x0b, 0x08, 0x75, 0x7d, 0x3f, + 0x83, 0x69, 0x52, 0x13, 0x95, 0xd2, 0x35, 0x51, 0xfd, 0x2f, 0x35, 0x61, 0x68, 0xa4, 0x28, 0x06, + 0x6b, 0x29, 0x06, 0x4b, 0xd5, 0x89, 0xd6, 0x9d, 0x1a, 0x99, 0xee, 0x84, 0xde, 0x03, 0x10, 0x17, + 0x9b, 0x1b, 0x17, 0xe0, 0xb7, 0xf9, 0xce, 0x99, 0x6c, 0x46, 0x8a, 0xaf, 0x56, 0x3e, 0x5f, 0xe9, + 0x2a, 0x19, 0x40, 0x4f, 0xc5, 0x33, 0x8f, 0x16, 0x3c, 0x26, 0x59, 0x29, 0x5d, 0xb9, 0x3f, 0x8e, + 0x16, 0x2c, 0xaa, 0x2c, 0x87, 0x9d, 0x4d, 0x0e, 0x9f, 0xc1, 0x7e, 0x16, 0xf6, 0x9b, 0x52, 0xf8, + 0x67, 0x05, 0x0e, 0x5e, 0x06, 0x5e, 0x2e, 0x89, 0x79, 0x85, 0xb1, 0x01, 0x6b, 0x35, 0x07, 0xd6, + 0x3d, 0xa8, 0xaf, 0xe3, 0xe8, 0x35, 0x96, 0x34, 0x89, 0x45, 0x1a, 0xaf, 0x9a, 0x8e, 0x57, 0x26, + 0xe3, 0xfa, 0x66, 0xc6, 0x33, 0x30, 0x37, 0xa3, 0xbc, 0x61, 0xce, 0x2c, 0xaf, 0xe4, 0xed, 0x6a, + 0x8b, 0x77, 0xca, 0xbe, 0x03, 0xb7, 0x8f, 0x31, 0x7d, 0x25, 0xca, 0x54, 0x02, 0x60, 0x4f, 0x00, + 0xa5, 0x37, 0xaf, 0xfc, 0xc9, 0x2d, 0xdd, 0x9f, 0x1a, 0xec, 0x94, 0xbe, 0xd2, 0xb2, 0xbf, 0xe2, + 0xb6, 0x4f, 0x3c, 0x42, 0xc3, 0xe8, 0x72, 0x1b, 0xb8, 0x3d, 0x30, 0x56, 0xee, 0x3b, 0xf9, 0xb4, + 0xb1, 0x4f, 0xfb, 0x98, 0x47, 0x90, 0x1c, 0x95, 0x11, 0xa4, 0x07, 0x85, 0x4a, 0xb9, 0x41, 0xe1, + 0x1d, 0xa0, 0x17, 0x38, 0x99, 0x59, 0xae, 0x79, 0x63, 0x15, 0x4d, 0x55, 0x9d, 0x26, 0x13, 0x9a, + 0x73, 0x1f, 0xbb, 0x41, 0xbc, 0x96, 0xc4, 0xaa, 0x25, 0x6b, 0x6b, 0x6b, 0x37, 0x72, 0x7d, 0x1f, + 0xfb, 0xf2, 0xb9, 0x4a, 0xd6, 0xf6, 0x4f, 0x70, 0x47, 0xf3, 0x2c, 0x73, 0x60, 0xb9, 0x92, 0xd7, + 0xd2, 0x33, 0xfb, 0x44, 0x5f, 0x42, 0x43, 0x0c, 0x7d, 0xdc, 0x6f, 0x77, 0x74, 0x5f, 0xcf, 0x89, + 0x1b, 0x89, 0x03, 0x39, 0x25, 0x3a, 0x52, 0x77, 0xf4, 0x77, 0x0b, 0xba, 0x6a, 0x6c, 0x11, 0x23, + 0x29, 0xf2, 0x60, 0x37, 0x3d, 0x9f, 0xa1, 0x87, 0xc5, 0x13, 0x6b, 0x66, 0xec, 0xb6, 0x1e, 0x95, + 0x51, 0x15, 0x19, 0xd8, 0x3b, 0x9f, 0x55, 0x10, 0x81, 0x5e, 0x76, 0x6c, 0x42, 0x8f, 0xf3, 0x6d, + 0x14, 0xcc, 0x69, 0xd6, 0xb0, 0xac, 0xba, 0x72, 0x8b, 0x2e, 0xf8, 0x7d, 0xd2, 0x67, 0x1d, 0x74, + 0xad, 0x19, 0x7d, 0xbc, 0xb2, 0x0e, 0x4b, 0xeb, 0x27, 0x7e, 0x7f, 0x86, 0x5b, 0xda, 0x6b, 0x8c, + 0x0a, 0xd0, 0xca, 0x9b, 0x9c, 0xac, 0x4f, 0x4a, 0xe9, 0x26, 0xbe, 0x56, 0xd0, 0xd5, 0x5b, 0x1c, + 0x2a, 0x30, 0x90, 0xfb, 0xfe, 0x58, 0x9f, 0x96, 0x53, 0x4e, 0xdc, 0x11, 0xe8, 0x65, 0xfb, 0x4b, + 0x11, 0x8f, 0x05, 0xdd, 0xb2, 0x88, 0xc7, 0xa2, 0xb6, 0x65, 0xef, 0x20, 0x17, 0xe0, 0xaa, 0xbd, + 0xa0, 0x07, 0x85, 0x84, 0xe8, 0x5d, 0xc9, 0x1a, 0x5c, 0xaf, 0x98, 0xb8, 0x58, 0xc3, 0xff, 0x32, + 0xaf, 0x3d, 0x2a, 0x80, 0x26, 0x7f, 0x38, 0xb2, 0x1e, 0x97, 0xd4, 0xce, 0x24, 0x25, 0x3b, 0xd6, + 0x96, 0xa4, 0xf4, 0x76, 0xb8, 0x25, 0xa9, 0x4c, 0xf3, 0xb3, 0x77, 0x90, 0x07, 0x5d, 0x27, 0x0e, + 0xa4, 0x6b, 0xd6, 0x16, 0x50, 0xc1, 0xe9, 0xcd, 0x8e, 0x67, 0x3d, 0x2c, 0xa1, 0x79, 0x55, 0xdf, + 0x4f, 0xe0, 0xc7, 0x96, 0x52, 0x3d, 0x6f, 0xf0, 0xff, 0xd8, 0xbf, 0xf8, 0x37, 0x00, 0x00, 0xff, + 0xff, 0xb6, 0x48, 0x98, 0x76, 0x9f, 0x10, 0x00, 0x00, } diff --git a/pkg/releasetesting/environment.go b/pkg/releasetesting/environment.go index ee078e182..e4184b5f4 100644 --- a/pkg/releasetesting/environment.go +++ b/pkg/releasetesting/environment.go @@ -20,6 +20,7 @@ import ( "bytes" "fmt" "log" + "sync" "time" "k8s.io/api/core/v1" @@ -31,10 +32,13 @@ import ( // Environment encapsulates information about where test suite executes and returns results type Environment struct { - Namespace string - KubeClient environment.KubeClient - Stream services.ReleaseService_RunReleaseTestServer - Timeout int64 + Namespace string + KubeClient environment.KubeClient + Stream services.ReleaseService_RunReleaseTestServer + Timeout int64 + Parallel bool + Parallelism uint32 + streamLock sync.Mutex } func (env *Environment) createTestPod(test *test) error { @@ -108,6 +112,8 @@ func (env *Environment) streamUnknown(name, info string) error { func (env *Environment) streamMessage(msg string, status release.TestRun_Status) error { resp := &services.TestReleaseResponse{Msg: msg, Status: status} + env.streamLock.Lock() + defer env.streamLock.Unlock() return env.Stream.Send(resp) } diff --git a/pkg/releasetesting/environment_test.go b/pkg/releasetesting/environment_test.go index 4403ab6a9..d9377b0f3 100644 --- a/pkg/releasetesting/environment_test.go +++ b/pkg/releasetesting/environment_test.go @@ -121,10 +121,11 @@ func newMockTestingEnvironment() *MockTestingEnvironment { return &MockTestingEnvironment{ Environment: &Environment{ - Namespace: "default", - KubeClient: tEnv.KubeClient, - Timeout: 5, - Stream: &mockStream{}, + Namespace: "default", + KubeClient: tEnv.KubeClient, + Timeout: 5, + Stream: &mockStream{}, + Parallelism: 20, }, } } diff --git a/pkg/releasetesting/test_suite.go b/pkg/releasetesting/test_suite.go index 8ba83fdb2..4fa5de526 100644 --- a/pkg/releasetesting/test_suite.go +++ b/pkg/releasetesting/test_suite.go @@ -17,7 +17,9 @@ limitations under the License. package releasetesting import ( + "context" "fmt" + "golang.org/x/sync/semaphore" "strings" "github.com/ghodss/yaml" @@ -69,53 +71,91 @@ func (ts *TestSuite) Run(env *Environment) error { env.streamMessage("No Tests Found", release.TestRun_UNKNOWN) } + var tests []*test + for _, testManifest := range ts.TestManifests { test, err := newTest(testManifest) if err != nil { return err } - test.result.StartedAt = timeconv.Now() - if err := env.streamRunning(test.result.Name); err != nil { - return err + tests = append(tests, test) + } + + if env.Parallel { + c := make(chan error, len(tests)) + // Use a semaphore to restrict the number of tests running in parallel. + sem := semaphore.NewWeighted(int64(env.Parallelism)) + ctx := context.Background() + for _, t := range tests { + sem.Acquire(ctx, 1) + go func(t *test, sem *semaphore.Weighted) { + defer sem.Release(1) + c <- t.run(env) + }(t, sem) } - test.result.Status = release.TestRun_RUNNING - resourceCreated := true - if err := env.createTestPod(test); err != nil { - resourceCreated = false - if streamErr := env.streamError(test.result.Info); streamErr != nil { + for range tests { + if err := <-c; err != nil { return err } } - resourceCleanExit := true - status := v1.PodUnknown - if resourceCreated { - status, err = env.getTestPodStatus(test) - if err != nil { - resourceCleanExit = false - if streamErr := env.streamError(test.result.Info); streamErr != nil { - return streamErr - } + } else { + for _, t := range tests { + if err := t.run(env); err != nil { + return err } } + } - if resourceCreated && resourceCleanExit { - if err := test.assignTestResult(status); err != nil { - return err - } + for _, t := range tests { + ts.Results = append(ts.Results, t.result) + } - if err := env.streamResult(test.result); err != nil { - return err + ts.CompletedAt = timeconv.Now() + return nil +} + +func (t *test) run(env *Environment) error { + t.result.StartedAt = timeconv.Now() + if err := env.streamRunning(t.result.Name); err != nil { + return err + } + t.result.Status = release.TestRun_RUNNING + + resourceCreated := true + if err := env.createTestPod(t); err != nil { + resourceCreated = false + if streamErr := env.streamError(t.result.Info); streamErr != nil { + return err + } + } + + resourceCleanExit := true + status := v1.PodUnknown + if resourceCreated { + var err error + status, err = env.getTestPodStatus(t) + if err != nil { + resourceCleanExit = false + if streamErr := env.streamError(t.result.Info); streamErr != nil { + return streamErr } } + } + + if resourceCreated && resourceCleanExit { + if err := t.assignTestResult(status); err != nil { + return err + } - test.result.CompletedAt = timeconv.Now() - ts.Results = append(ts.Results, test.result) + if err := env.streamResult(t.result); err != nil { + return err + } } - ts.CompletedAt = timeconv.Now() + t.result.CompletedAt = timeconv.Now() return nil } diff --git a/pkg/releasetesting/test_suite_test.go b/pkg/releasetesting/test_suite_test.go index bf85e4207..59f122953 100644 --- a/pkg/releasetesting/test_suite_test.go +++ b/pkg/releasetesting/test_suite_test.go @@ -220,6 +220,107 @@ func TestExtractTestManifestsFromHooks(t *testing.T) { } } +func TestParallelTestRun(t *testing.T) { + ts := testSuiteFixture([]string{manifestWithTestSuccessHook, manifestWithTestSuccessHook}) + env := testEnvFixture() + env.Parallel = true + env.KubeClient = newSleepOnWaitKubeClient() + if err := ts.Run(env); err != nil { + t.Errorf("%s", err) + } + + if len(ts.Results) != 2 { + t.Errorf("Expected 2 test result. Got %v", len(ts.Results)) + } + + stream := env.Stream.(*mockStream) + if len(stream.messages) != 4 { + t.Errorf("Expected four messages, Got: %v", len(stream.messages)) + } + + if stream.messages[0].Status != release.TestRun_RUNNING { + t.Errorf("Expected first message status to be RUNNING, Got: %v", stream.messages[0].Status) + } + if stream.messages[1].Status != release.TestRun_RUNNING { + t.Errorf("Expected second message status to be RUNNING, Got: %v", stream.messages[1].Status) + } + if stream.messages[2].Status != release.TestRun_SUCCESS { + t.Errorf("Expected third message status to be SUCCESS, Got: %v", stream.messages[2].Status) + } + if stream.messages[3].Status != release.TestRun_SUCCESS { + t.Errorf("Expected fourth message status to be SUCCESS, Got: %v", stream.messages[3].Status) + } +} + +func TestParallelTestRunFailure(t *testing.T) { + ts := testSuiteFixture([]string{manifestWithTestSuccessHook, manifestWithTestFailureHook}) + env := testEnvFixture() + env.Parallel = true + env.KubeClient = newSleepOnWaitKubeClient() + if err := ts.Run(env); err != nil { + t.Errorf("%s", err) + } + + if len(ts.Results) != 2 { + t.Errorf("Expected 2 test result. Got %v", len(ts.Results)) + } + + stream := env.Stream.(*mockStream) + if len(stream.messages) != 4 { + t.Errorf("Expected four messages, Got: %v", len(stream.messages)) + } + + if stream.messages[0].Status != release.TestRun_RUNNING { + t.Errorf("Expected first message status to be RUNNING, Got: %v", stream.messages[0].Status) + } + if stream.messages[1].Status != release.TestRun_RUNNING { + t.Errorf("Expected second message status to be RUNNING, Got: %v", stream.messages[1].Status) + } + + if ts.Results[0].Status != release.TestRun_SUCCESS { + t.Errorf("Expected first test result to be successful, got: %v", ts.Results[0].Status) + } + + if ts.Results[1].Status != release.TestRun_FAILURE { + t.Errorf("Expected second test result to be failure, got: %v", ts.Results[1].Status) + } +} + +func TestParallelism(t *testing.T) { + ts := testSuiteFixture([]string{manifestWithTestSuccessHook, manifestWithTestSuccessHook, manifestWithTestFailureHook}) + env := testEnvFixture() + env.Parallel = true + env.Parallelism = 2 + env.KubeClient = newSleepOnWaitKubeClient() + if err := ts.Run(env); err != nil { + t.Errorf("%s", err) + } + + stream := env.Stream.(*mockStream) + + if stream.messages[0].Status != release.TestRun_RUNNING { + t.Errorf("Expected first message status to be RUNNING, Got: %v", stream.messages[0].Status) + } + if stream.messages[1].Status != release.TestRun_RUNNING { + t.Errorf("Expected second message status to be RUNNING, Got: %v", stream.messages[1].Status) + } + if stream.messages[2].Status == release.TestRun_RUNNING { + t.Errorf("Expected third message status to be not be RUNNING") + } + + if ts.Results[0].Status != release.TestRun_SUCCESS { + t.Errorf("Expected first test result to be successful, got: %v", ts.Results[0].Status) + } + + if ts.Results[1].Status != release.TestRun_SUCCESS { + t.Errorf("Expected second test result to be successful, got: %v", ts.Results[1].Status) + } + + if ts.Results[2].Status != release.TestRun_FAILURE { + t.Errorf("Expected third test result to be failure, got: %v", ts.Results[2].Status) + } +} + func chartStub() *chart.Chart { return &chart.Chart{ Metadata: &chart.Metadata{ @@ -328,6 +429,26 @@ func (p *podSucceededKubeClient) WaitAndGetCompletedPodPhase(ns string, r io.Rea return v1.PodSucceeded, nil } +// For testing parallelism, this kube client +// will sleep for 1ms before returning completed pod +// phase. +type sleepOnWaitKubeClient struct { + tillerEnv.PrintingKubeClient + firstWait bool +} + +func newSleepOnWaitKubeClient() *sleepOnWaitKubeClient { + return &sleepOnWaitKubeClient{ + PrintingKubeClient: tillerEnv.PrintingKubeClient{Out: ioutil.Discard}, + } +} + +func (p *sleepOnWaitKubeClient) WaitAndGetCompletedPodPhase(ns string, r io.Reader, timeout time.Duration) (v1.PodPhase, error) { + time.Sleep(1 * time.Millisecond) + + return v1.PodSucceeded, nil +} + type podFailedKubeClient struct { tillerEnv.PrintingKubeClient } diff --git a/pkg/tiller/release_testing.go b/pkg/tiller/release_testing.go index 06d41e323..e6b6a7f6f 100644 --- a/pkg/tiller/release_testing.go +++ b/pkg/tiller/release_testing.go @@ -22,6 +22,8 @@ import ( reltesting "k8s.io/helm/pkg/releasetesting" ) +const maxParallelism = 20 + // RunReleaseTest runs pre-defined tests stored as hooks on a given release func (s *ReleaseServer) RunReleaseTest(req *services.TestReleaseRequest, stream services.ReleaseService_RunReleaseTestServer) error { @@ -37,10 +39,12 @@ func (s *ReleaseServer) RunReleaseTest(req *services.TestReleaseRequest, stream } testEnv := &reltesting.Environment{ - Namespace: rel.Namespace, - KubeClient: s.env.KubeClient, - Timeout: req.Timeout, - Stream: stream, + Namespace: rel.Namespace, + KubeClient: s.env.KubeClient, + Timeout: req.Timeout, + Stream: stream, + Parallel: req.Parallel, + Parallelism: maxParallelism, } s.Log("running tests for release %s", rel.Name) tSuite, err := reltesting.NewTestSuite(rel) From ff35ab8626ffa5caf0a0a92477476d070e822131 Mon Sep 17 00:00:00 2001 From: tariqibrahim Date: Wed, 5 Dec 2018 14:21:02 -0800 Subject: [PATCH 034/146] Renaming Issue Templates correctly and adding a pull request template Signed-off-by: tariqibrahim --- .github/{issue_template.md => ISSUE_TEMPLATE.md} | 0 .github/PULL_REQUEST_TEMPLATE.md | 12 ++++++++++++ 2 files changed, 12 insertions(+) rename .github/{issue_template.md => ISSUE_TEMPLATE.md} (100%) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/issue_template.md b/.github/ISSUE_TEMPLATE.md similarity index 100% rename from .github/issue_template.md rename to .github/ISSUE_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..595b50218 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,12 @@ + + +**What this PR does / why we need it**: + +**Special notes for your reviewer**: + +**If applicable**: +- [ ] this PR contains documentation +- [ ] this PR contains unit tests +- [ ] this PR has been tested for backwards compatibility From 129ed826791a13f5b9135e482abdeaf108ef66da Mon Sep 17 00:00:00 2001 From: Adam Reese Date: Fri, 7 Dec 2018 17:26:10 -0800 Subject: [PATCH 035/146] ref(*): kubernetes v1.13 support Signed-off-by: Adam Reese --- glide.lock | 125 ++++++++++++++++++----------------------------------- glide.yaml | 14 +++--- 2 files changed, 49 insertions(+), 90 deletions(-) diff --git a/glide.lock b/glide.lock index c6bec006d..8e63136e7 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: 813d803db5fc2cb46f8050190d2a307f247da5b7b3a4b00eb4d3e766882ad4f9 -updated: 2018-11-30T10:55:17.417707Z +hash: c54977baef0c54fe52cd8b2df120454018de82a1c8967a34b804e9a1fa0ae9cc +updated: 2018-12-08T01:25:26.033266Z imports: - name: cloud.google.com/go version: 3b1ae45394a234c385be014e9a488f2bb6eef821 @@ -15,12 +15,13 @@ imports: subpackages: - winterm - name: github.com/Azure/go-autorest - version: bca49d5b51a50dc5bb17bbf6204c711c6dbded06 + version: ea233b6412b0421a65dc6160e16c893364664a95 subpackages: - autorest - autorest/adal - autorest/azure - autorest/date + - logger - version - name: github.com/beorn7/perks version: 3ac7bf7a47d159a033b107610db8a1b6575507a4 @@ -81,14 +82,6 @@ imports: - pkg/sysinfo - pkg/term - pkg/term/windows -- name: github.com/docker/go-connections - version: 3ede32e2033de7505e6500d6c868c2b9ed9f169d - subpackages: - - nat - - sockets - - tlsconfig -- name: github.com/docker/go-units - version: 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1 - name: github.com/docker/spdystream version: 449fdfce4d962303d702fec724ef0ad181c92528 subpackages: @@ -102,13 +95,13 @@ imports: - name: github.com/ghodss/yaml version: 73d445a93680fa1a78ae23a5839bad48f32ba1ee - name: github.com/go-openapi/jsonpointer - version: 46af16f9f7b149af66e5d1bd010e3574dc06de98 + version: ef5f0afec364d3b9396b7b77b43dbe26bf1f8004 - name: github.com/go-openapi/jsonreference - version: 13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272 + version: 8483a886a90412cd6858df4ea3483dce9c8e35a3 - name: github.com/go-openapi/spec - version: 1de3e0542de65ad8d75452a595886fdd0befb363 + version: 5bae59e25b21498baea7f9d46e9c147ec106a42e - name: github.com/go-openapi/swag - version: f3f9494671f93fcff853e3c6e9e948b3eb71e590 + version: 5899d5c5e619fda5fa86e14795a835f473ca284c - name: github.com/gobwas/glob version: 5ccd90ef52e1e632236f7326478d4faa74f99438 subpackages: @@ -120,12 +113,10 @@ imports: - util/runes - util/strings - name: github.com/gogo/protobuf - version: c0656edd0d9eab7c66d1eb0c568f9039345796f7 + version: 342cbe0a04158f6dcb03ca0079991a51a4248c02 subpackages: - proto - sortkeys -- name: github.com/golang/glog - version: 44145f04b68cf362d9c4df2182967c2275eaefed - name: github.com/golang/groupcache version: 02826c3e79038b59d737d3b1c0a1d937f71a4433 subpackages: @@ -181,7 +172,7 @@ imports: - name: github.com/inconshreveable/mousetrap version: 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 - name: github.com/json-iterator/go - version: f2b4162afba35581b6d4a50d3b8f34e33c144682 + version: ab8a2e0c74be9d3be70b3184d9acc634935ded82 - name: github.com/mailru/easyjson version: 2f5df55504ebc322e4d52d34df6a1f5b503bf26d subpackages: @@ -207,14 +198,9 @@ imports: - name: github.com/modern-go/concurrent version: bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94 - name: github.com/modern-go/reflect2 - version: 05fbef0ca5da472bbf96c9322b84a53edc03c9fd + version: 94122c33edd36123c84d5368cfb2b69df93a0ec8 - 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/peterbourgon/diskv version: 5f041e8faa004a95c88a202771f4cc3e991971e6 - name: github.com/pkg/errors @@ -273,7 +259,7 @@ imports: - scrypt - ssh/terminal - name: golang.org/x/net - version: 1c05540f6879653db88113bc4a2b70aec4bd491f + version: 0ed95abb35c445290478a5348a7b38bb154135fd subpackages: - context - context/ctxhttp @@ -370,7 +356,7 @@ imports: - name: gopkg.in/yaml.v2 version: 670d4cfef0544295bc27a114dbac37980d83185a - name: k8s.io/api - version: fd83cbc87e7632ccd8bbab63d2b673d4e0c631cc + version: 89a74a8d264df0e993299876a8cde88379b940ee subpackages: - admission/v1beta1 - admissionregistration/v1alpha1 @@ -378,6 +364,7 @@ imports: - apps/v1 - apps/v1beta1 - apps/v1beta2 + - auditregistration/v1alpha1 - authentication/v1 - authentication/v1beta1 - authorization/v1 @@ -406,11 +393,11 @@ imports: - storage/v1alpha1 - storage/v1beta1 - name: k8s.io/apiextensions-apiserver - version: 05e89e265cc594459a3d33a63e779d94e6614c63 + version: 20c909e7c8c3fec1a0e345b1d4e57f1c1623c368 subpackages: - pkg/features - name: k8s.io/apimachinery - version: 6dd46049f39503a1fc8d65de4bd566829e95faff + version: 2b1284ed4c93a43499e781493253e2ac5959c4fd subpackages: - pkg/api/equality - pkg/api/errors @@ -418,7 +405,6 @@ imports: - pkg/api/meta/testrestmapper - pkg/api/resource - pkg/api/validation - - pkg/api/validation/path - pkg/apis/meta/internalversion - pkg/apis/meta/v1 - pkg/apis/meta/v1/unstructured @@ -467,23 +453,21 @@ imports: - third_party/forked/golang/netutil - third_party/forked/golang/reflect - name: k8s.io/apiserver - version: e85ad7b666fef0476185731329f4cff1536efff8 + version: 9caa0299108fbdf51d3d9b8e8956834ae84dac75 subpackages: - - pkg/apis/audit - pkg/authentication/authenticator - pkg/authentication/serviceaccount - pkg/authentication/user - - pkg/endpoints/request - pkg/features - pkg/util/feature - name: k8s.io/cli-runtime - version: 79bf4e0b64544d8c490247abae089bea572ddae6 + version: a04da5c88c0796c1dc5ff976a9c91999779ac0e4 subpackages: - pkg/genericclioptions - pkg/genericclioptions/printers - pkg/genericclioptions/resource - name: k8s.io/client-go - version: 1638f8970cefaa404ff3a62950f88b08292b2696 + version: e64494209f554a6723674bd494d69445fb76a1d4 subpackages: - discovery - discovery/fake @@ -502,6 +486,8 @@ imports: - kubernetes/typed/apps/v1beta1/fake - kubernetes/typed/apps/v1beta2 - kubernetes/typed/apps/v1beta2/fake + - kubernetes/typed/auditregistration/v1alpha1 + - kubernetes/typed/auditregistration/v1alpha1/fake - kubernetes/typed/authentication/v1 - kubernetes/typed/authentication/v1/fake - kubernetes/typed/authentication/v1beta1 @@ -602,30 +588,20 @@ imports: - util/integer - util/jsonpath - util/retry +- name: k8s.io/klog + version: 8139d8cb77af419532b33dfa7dd09fbc5f1d344f - name: k8s.io/kube-openapi - version: 0cf8f7e6ed1d2e3d47d02e3b6e559369af24d803 + version: c59034cc13d587f5ef4e85ca0ade0c1866ae8e1d subpackages: - pkg/util/proto - pkg/util/proto/testing - pkg/util/proto/validation - name: k8s.io/kubernetes - version: 54a352dda957bce0f88e49b65a6ee8bba8c0ba74 + version: f2c8f1cadf1808ec28476682e49a3cce2b09efbf subpackages: - - pkg/api/events - pkg/api/legacyscheme - - pkg/api/pod - - pkg/api/ref - - pkg/api/resource - pkg/api/service - - pkg/api/testapi - pkg/api/v1/pod - - pkg/apis/admission - - pkg/apis/admission/install - - pkg/apis/admission/v1beta1 - - pkg/apis/admissionregistration - - pkg/apis/admissionregistration/install - - pkg/apis/admissionregistration/v1alpha1 - - pkg/apis/admissionregistration/v1beta1 - pkg/apis/apps - pkg/apis/apps/install - pkg/apis/apps/v1 @@ -657,7 +633,6 @@ imports: - pkg/apis/coordination/v1beta1 - pkg/apis/core - pkg/apis/core/helper - - pkg/apis/core/helper/qos - pkg/apis/core/install - pkg/apis/core/pods - pkg/apis/core/v1 @@ -669,12 +644,7 @@ imports: - pkg/apis/extensions - pkg/apis/extensions/install - pkg/apis/extensions/v1beta1 - - pkg/apis/imagepolicy - - pkg/apis/imagepolicy/install - - pkg/apis/imagepolicy/v1alpha1 - pkg/apis/networking - - pkg/apis/networking/install - - pkg/apis/networking/v1 - pkg/apis/policy - pkg/apis/policy/install - pkg/apis/policy/v1beta1 @@ -697,45 +667,36 @@ imports: - pkg/apis/storage/v1alpha1 - pkg/apis/storage/v1beta1 - pkg/capabilities - - pkg/client/clientset_generated/internalclientset - - pkg/client/clientset_generated/internalclientset/scheme - - pkg/client/clientset_generated/internalclientset/typed/admissionregistration/internalversion - - pkg/client/clientset_generated/internalclientset/typed/apps/internalversion - - pkg/client/clientset_generated/internalclientset/typed/authentication/internalversion - - pkg/client/clientset_generated/internalclientset/typed/authorization/internalversion - - pkg/client/clientset_generated/internalclientset/typed/autoscaling/internalversion - - pkg/client/clientset_generated/internalclientset/typed/batch/internalversion - - pkg/client/clientset_generated/internalclientset/typed/certificates/internalversion - - pkg/client/clientset_generated/internalclientset/typed/coordination/internalversion - - pkg/client/clientset_generated/internalclientset/typed/core/internalversion - - pkg/client/clientset_generated/internalclientset/typed/events/internalversion - - pkg/client/clientset_generated/internalclientset/typed/extensions/internalversion - - pkg/client/clientset_generated/internalclientset/typed/networking/internalversion - - pkg/client/clientset_generated/internalclientset/typed/policy/internalversion - - pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion - - pkg/client/clientset_generated/internalclientset/typed/scheduling/internalversion - - pkg/client/clientset_generated/internalclientset/typed/settings/internalversion - - pkg/client/clientset_generated/internalclientset/typed/storage/internalversion - pkg/controller - pkg/controller/deployment/util - - pkg/credentialprovider - pkg/features - pkg/fieldpath - - pkg/generated - pkg/kubectl - pkg/kubectl/apps - pkg/kubectl/cmd/get - - pkg/kubectl/cmd/templates - pkg/kubectl/cmd/testing - pkg/kubectl/cmd/util - pkg/kubectl/cmd/util/openapi - pkg/kubectl/cmd/util/openapi/testing - pkg/kubectl/cmd/util/openapi/validation + - pkg/kubectl/describe + - pkg/kubectl/describe/versioned + - pkg/kubectl/generated - pkg/kubectl/scheme - pkg/kubectl/util - - pkg/kubectl/util/hash + - pkg/kubectl/util/certificate + - pkg/kubectl/util/deployment + - pkg/kubectl/util/event + - pkg/kubectl/util/fieldpath - pkg/kubectl/util/i18n + - pkg/kubectl/util/podutils + - pkg/kubectl/util/printers + - pkg/kubectl/util/qos + - pkg/kubectl/util/rbac + - pkg/kubectl/util/resource - pkg/kubectl/util/slice + - pkg/kubectl/util/storage + - pkg/kubectl/util/templates - pkg/kubectl/util/term - pkg/kubectl/validation - pkg/kubelet/apis @@ -743,12 +704,7 @@ imports: - pkg/master/ports - pkg/printers - pkg/printers/internalversion - - pkg/registry/rbac/validation - - pkg/scheduler/algorithm - - pkg/scheduler/algorithm/priorities/util - pkg/scheduler/api - - pkg/scheduler/cache - - pkg/scheduler/util - pkg/security/apparmor - pkg/serviceaccount - pkg/util/file @@ -758,7 +714,6 @@ imports: - pkg/util/net/sets - pkg/util/node - pkg/util/parsers - - pkg/util/slice - pkg/util/taints - pkg/version - name: k8s.io/utils @@ -768,6 +723,8 @@ imports: - exec - exec/testing - pointer +- name: sigs.k8s.io/yaml + version: fd68e9863619f6ec2fdd8625fe1f02e7c877e480 - name: vbom.ml/util version: db5cfe13f5cc80a4990d98e2e1b0707a4d1a5394 subpackages: diff --git a/glide.yaml b/glide.yaml index 52cee8142..1abfacc0e 100644 --- a/glide.yaml +++ b/glide.yaml @@ -45,17 +45,19 @@ import: version: 0.8.0 - package: github.com/grpc-ecosystem/go-grpc-prometheus - package: k8s.io/kubernetes - version: release-1.12 + version: release-1.13 - package: k8s.io/client-go - version: kubernetes-1.12.0 + version: kubernetes-1.13.0 - package: k8s.io/api - version: kubernetes-1.12.0 + version: kubernetes-1.13.0 - package: k8s.io/apimachinery - version: kubernetes-1.12.0 + version: kubernetes-1.13.0 - package: k8s.io/apiserver - version: kubernetes-1.12.0 + version: kubernetes-1.13.0 - package: k8s.io/cli-runtime - version: kubernetes-1.12.0 + version: kubernetes-1.13.0 + - package: k8s.io/apiextensions-apiserver + version: kubernetes-1.13.0 - package: github.com/cyphar/filepath-securejoin version: ^0.2.1 From c7009a155c5c591018cf25e85cf94f6148513780 Mon Sep 17 00:00:00 2001 From: Ben Tyler Date: Wed, 12 Dec 2018 12:53:59 -0800 Subject: [PATCH 036/146] docs: add Shipper to the list of additional tools (#5051) Signed-off-by: Ben Tyler --- docs/related.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/related.md b/docs/related.md index 520616e55..c6735e0ea 100644 --- a/docs/related.md +++ b/docs/related.md @@ -81,6 +81,7 @@ Tools layered on top of Helm or Tiller. - [Quay App Registry](https://coreos.com/blog/quay-application-registry-for-kubernetes.html) - Open Kubernetes application registry, including a Helm access client - [Rudder](https://github.com/AcalephStorage/rudder) - RESTful (JSON) proxy for Tiller's API - [Schelm](https://github.com/databus23/schelm) - Render a Helm manifest to a directory +- [Shipper](https://github.com/bookingcom/shipper) - Multi-cluster canary or blue-green rollouts using Helm - [VIM-Kubernetes](https://github.com/andrewstuart/vim-kubernetes) - VIM plugin for Kubernetes and Helm ## Helm Included From 9aa773042d56f3f4efeed41e281381c94682d86a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Fri, 14 Dec 2018 18:14:14 +0100 Subject: [PATCH 037/146] create: include the namespace in NOTES.txt for LoadBalancer status (#5055) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Dunglas --- pkg/chartutil/create.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/chartutil/create.go b/pkg/chartutil/create.go index 82d307ded..36b07adb5 100644 --- a/pkg/chartutil/create.go +++ b/pkg/chartutil/create.go @@ -255,7 +255,7 @@ const defaultNotes = `1. Get the application URL by running these commands: 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 {{ include ".fullname" . }}' + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include ".fullname" . }}' export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include ".fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') echo http://$SERVICE_IP:{{ .Values.service.port }} {{- else if contains "ClusterIP" .Values.service.type }} From e9a5465c661a7543d5a968f0020fc4729f95874f Mon Sep 17 00:00:00 2001 From: JoeWrightss <42261994+JoeWrightss@users.noreply.github.com> Date: Sat, 15 Dec 2018 01:19:23 +0800 Subject: [PATCH 038/146] Fix some spelling error (#5032) Signed-off-by: JoeWrightss --- _proto/README.md | 2 +- pkg/chartutil/doc.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/_proto/README.md b/_proto/README.md index fcc2c52f1..0ebd6b6a4 100644 --- a/_proto/README.md +++ b/_proto/README.md @@ -6,5 +6,5 @@ Packages - `hapi.chart` Complete serialization of Heml charts - `hapi.release` Information about installed charts (Releases) such as metadata about when they were installed, their status, and how they were configured. - `hapi.services.rudder` Definition for the ReleaseModuleService used by Tiller to manipulate releases on a given node - - `hapi.services.tiller` Definition of the ReleaseService provoded by Tiller and used by Helm clients to manipulate releases cluster wide. + - `hapi.services.tiller` Definition of the ReleaseService provided by Tiller and used by Helm clients to manipulate releases cluster wide. - `hapi.version` Version meta-data used by tiller to express it's version diff --git a/pkg/chartutil/doc.go b/pkg/chartutil/doc.go index cb3f5d1f1..a4f6d4515 100644 --- a/pkg/chartutil/doc.go +++ b/pkg/chartutil/doc.go @@ -25,7 +25,7 @@ A chart can be represented on the file system in one of two ways: - As a tarred gzipped file containing a directory that then contains a Chart.yaml file. -This package provides utilitites for working with those file formats. +This package provides utilities for working with those file formats. The preferred way of loading a chart is using 'chartutil.Load`: From 9174f5b9e5f8e9ab9fa2bce95247e4e8a9d21aa7 Mon Sep 17 00:00:00 2001 From: Adam Reese Date: Fri, 14 Dec 2018 13:48:54 -0800 Subject: [PATCH 039/146] chore(deps): bump kubernetes to v1.13.1 Signed-off-by: Adam Reese --- glide.lock | 14 +++++++------- glide.yaml | 12 ++++++------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/glide.lock b/glide.lock index 8e63136e7..105dada1f 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: c54977baef0c54fe52cd8b2df120454018de82a1c8967a34b804e9a1fa0ae9cc -updated: 2018-12-08T01:25:26.033266Z +hash: 2af9a5c4f891a0f44109a929a494b5aeaaffa3a87cd1f3881f25f79845703d5b +updated: 2018-12-14T21:39:31.112097Z imports: - name: cloud.google.com/go version: 3b1ae45394a234c385be014e9a488f2bb6eef821 @@ -356,7 +356,7 @@ imports: - name: gopkg.in/yaml.v2 version: 670d4cfef0544295bc27a114dbac37980d83185a - name: k8s.io/api - version: 89a74a8d264df0e993299876a8cde88379b940ee + version: 05914d821849570fba9eacfb29466f2d8d3cd229 subpackages: - admission/v1beta1 - admissionregistration/v1alpha1 @@ -393,7 +393,7 @@ imports: - storage/v1alpha1 - storage/v1beta1 - name: k8s.io/apiextensions-apiserver - version: 20c909e7c8c3fec1a0e345b1d4e57f1c1623c368 + version: 0fe22c71c47604641d9aa352c785b7912c200562 subpackages: - pkg/features - name: k8s.io/apimachinery @@ -453,7 +453,7 @@ imports: - third_party/forked/golang/netutil - third_party/forked/golang/reflect - name: k8s.io/apiserver - version: 9caa0299108fbdf51d3d9b8e8956834ae84dac75 + version: 3ccfe8365421eb08e334b195786a2973460741d8 subpackages: - pkg/authentication/authenticator - pkg/authentication/serviceaccount @@ -461,13 +461,13 @@ imports: - pkg/features - pkg/util/feature - name: k8s.io/cli-runtime - version: a04da5c88c0796c1dc5ff976a9c91999779ac0e4 + version: 835b10687cb6556f6b113099ef925146a56d5981 subpackages: - pkg/genericclioptions - pkg/genericclioptions/printers - pkg/genericclioptions/resource - name: k8s.io/client-go - version: e64494209f554a6723674bd494d69445fb76a1d4 + version: 8d9ed539ba3134352c586810e749e58df4e94e4f subpackages: - discovery - discovery/fake diff --git a/glide.yaml b/glide.yaml index 1abfacc0e..bf81b22ee 100644 --- a/glide.yaml +++ b/glide.yaml @@ -47,17 +47,17 @@ import: - package: k8s.io/kubernetes version: release-1.13 - package: k8s.io/client-go - version: kubernetes-1.13.0 + version: kubernetes-1.13.1 - package: k8s.io/api - version: kubernetes-1.13.0 + version: kubernetes-1.13.1 - package: k8s.io/apimachinery - version: kubernetes-1.13.0 + version: kubernetes-1.13.1 - package: k8s.io/apiserver - version: kubernetes-1.13.0 + version: kubernetes-1.13.1 - package: k8s.io/cli-runtime - version: kubernetes-1.13.0 + version: kubernetes-1.13.1 - package: k8s.io/apiextensions-apiserver - version: kubernetes-1.13.0 + version: kubernetes-1.13.1 - package: github.com/cyphar/filepath-securejoin version: ^0.2.1 From 89467a8bf154aa19ad41c6775dc4a4f7ce6dfc04 Mon Sep 17 00:00:00 2001 From: Alex Humphreys Date: Tue, 18 Dec 2018 15:24:33 +0100 Subject: [PATCH 040/146] Fix(helm): Use spaces in ingress template The rest of the ingress template was using spaces, just these two lines were tabs. Signed-off-by: Alex Humphreys --- pkg/chartutil/create.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/chartutil/create.go b/pkg/chartutil/create.go index 36b07adb5..8f713fcd1 100644 --- a/pkg/chartutil/create.go +++ b/pkg/chartutil/create.go @@ -158,12 +158,12 @@ spec: - host: {{ . | quote }} http: paths: - {{- range $ingressPaths }} + {{- range $ingressPaths }} - path: {{ . }} backend: serviceName: {{ $fullName }} servicePort: http - {{- end }} + {{- end }} {{- end }} {{- end }} ` From 29ab7a0a775ec7182be88a1b6daa9e65a472b46b Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Wed, 19 Dec 2018 12:24:00 -0800 Subject: [PATCH 041/146] Revert "Fix for existing CRDs are deleted when crd-install hook is introduced (#4709)" (#5067) This reverts commit e2a0e7fa545585a29c1e9602e6320479788eb9a6. Signed-off-by: Matthew Fisher --- pkg/tiller/hooks.go | 7 ------- pkg/tiller/hooks_test.go | 33 +++++++++------------------------ 2 files changed, 9 insertions(+), 31 deletions(-) diff --git a/pkg/tiller/hooks.go b/pkg/tiller/hooks.go index 472301022..0fb7c92f8 100644 --- a/pkg/tiller/hooks.go +++ b/pkg/tiller/hooks.go @@ -174,13 +174,6 @@ func (file *manifestFile) sort(result *result) error { isUnknownHook = true break } - if e == release.Hook_CRD_INSTALL { - result.generic = append(result.generic, Manifest{ - Name: file.path, - Content: m, - Head: &entry, - }) - } h.Events = append(h.Events, e) } diff --git a/pkg/tiller/hooks_test.go b/pkg/tiller/hooks_test.go index 86c89b8f3..8bd928500 100644 --- a/pkg/tiller/hooks_test.go +++ b/pkg/tiller/hooks_test.go @@ -131,21 +131,6 @@ metadata: name: example-test annotations: "helm.sh/hook": test-success -`, - }, - { - name: []string{"ninth"}, - path: "nine", - kind: []string{"CustomResourceDefinition"}, - hooks: map[string][]release.Hook_Event{"ninth": {release.Hook_CRD_INSTALL}}, - manifest: `apiVersion: apiextensions.k8s.io/v1beta1 -kind: CustomResourceDefinition -metadata: - name: ninth - labels: - doesnot: matter - annotations: - "helm.sh/hook": crd-install `, }, } @@ -161,22 +146,22 @@ metadata: } // This test will fail if 'six' or 'seven' was added. - // changed to account for CustomResourceDefinition with crd-install hook being added to generic list of manifests - if len(generic) != 3 { - t.Errorf("Expected 3 generic manifests, got %d", len(generic)) + if len(generic) != 2 { + t.Errorf("Expected 2 generic manifests, got %d", len(generic)) } - // changed to account for 5 hooks now that there is a crd-install hook added as member 9 of the data list. It was 4 before. - if len(hs) != 5 { - t.Errorf("Expected 5 hooks, got %d", len(hs)) + if len(hs) != 4 { + t.Errorf("Expected 4 hooks, got %d", len(hs)) } for _, out := range hs { - t.Logf("Checking name %s path %s and kind %s", out.Name, out.Path, out.Kind) found := false for _, expect := range data { if out.Path == expect.path { found = true + if out.Path != expect.path { + t.Errorf("Expected path %s, got %s", expect.path, out.Path) + } nameFound := false for _, expectedName := range expect.name { if out.Name == expectedName { @@ -224,8 +209,8 @@ metadata: name := sh.Metadata.Name - //only keep track of non-hook manifests, that are not CustomResourceDefinitions with crd-install - if err == nil && (s.hooks[name] == nil || s.hooks[name][0] == release.Hook_CRD_INSTALL) { + //only keep track of non-hook manifests + if err == nil && s.hooks[name] == nil { another := Manifest{ Content: m, Name: name, From 266b3415f0a0dd9e70b1658d1fc2c17668b85960 Mon Sep 17 00:00:00 2001 From: ejether Date: Fri, 21 Dec 2018 15:16:21 -0800 Subject: [PATCH 042/146] Ejether/rename autohelm in docs (#5095) * autohelm we renamed to reckoner for copyright concerns. This commit renames autohelm in the documentation Signed-off-by: EJ Etherington * moving to be in alphabetical order Signed-off-by: EJ Etherington --- docs/related.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/related.md b/docs/related.md index c6735e0ea..6122101dc 100644 --- a/docs/related.md +++ b/docs/related.md @@ -65,7 +65,6 @@ Tools layered on top of Helm or Tiller. - [AppsCode Swift](https://github.com/appscode/swift) - Ajax friendly Helm Tiller Proxy using [grpc-gateway](https://github.com/grpc-ecosystem/grpc-gateway) - [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. -- [Autohelm](https://github.com/reactiveops/autohelm) - Autohelm is _another_ simple declarative spec for deploying helm charts. Written in python and supports git urls as a source for helm charts. - [ChartMuseum](https://github.com/chartmuseum/chartmuseum) - Helm Chart Repository with support for Amazon S3 and Google Cloud Storage - [Chartify](https://github.com/appscode/chartify) - Generate Helm charts from existing Kubernetes resources. - [Codefresh](https://codefresh.io) - Kubernetes native CI/CD and management platform with UI dashboards for managing Helm charts and releases @@ -79,6 +78,7 @@ Tools layered on top of Helm or Tiller. - [Monocular](https://github.com/helm/monocular) - Web UI for Helm Chart repositories - [Orca](https://github.com/maorfr/orca) - Advanced CI\CD tool for Kubernetes and Helm made simple. - [Quay App Registry](https://coreos.com/blog/quay-application-registry-for-kubernetes.html) - Open Kubernetes application registry, including a Helm access client +- [Reckoner](https://github.com/reactiveops/reckoner) - Reckoner (formerly Autohelm) is a tool for declarative management of helm releases. Written in python and supports git urls as a source for helm charts. - [Rudder](https://github.com/AcalephStorage/rudder) - RESTful (JSON) proxy for Tiller's API - [Schelm](https://github.com/databus23/schelm) - Render a Helm manifest to a directory - [Shipper](https://github.com/bookingcom/shipper) - Multi-cluster canary or blue-green rollouts using Helm From c82c0b6046b852f449dcaae768ba57331116dc87 Mon Sep 17 00:00:00 2001 From: Maor Friedman Date: Sun, 23 Dec 2018 15:45:43 +0200 Subject: [PATCH 043/146] [docs/related] update orca link to official repo (#5097) Signed-off-by: Maor --- docs/related.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/related.md b/docs/related.md index 6122101dc..5c027cc36 100644 --- a/docs/related.md +++ b/docs/related.md @@ -76,7 +76,7 @@ Tools layered on top of Helm or Tiller. - [Helmsman](https://github.com/Praqma/helmsman) - Helmsman is a helm-charts-as-code tool which enables installing/upgrading/protecting/moving/deleting releases from version controlled desired state files (described in a simple TOML format). - [Landscaper](https://github.com/Eneco/landscaper/) - "Landscaper takes a set of Helm Chart references with values (a desired state), and realizes this in a Kubernetes cluster." - [Monocular](https://github.com/helm/monocular) - Web UI for Helm Chart repositories -- [Orca](https://github.com/maorfr/orca) - Advanced CI\CD tool for Kubernetes and Helm made simple. +- [Orca](https://github.com/nuvo/orca) - Advanced CI\CD tool for Kubernetes and Helm made simple. - [Quay App Registry](https://coreos.com/blog/quay-application-registry-for-kubernetes.html) - Open Kubernetes application registry, including a Helm access client - [Reckoner](https://github.com/reactiveops/reckoner) - Reckoner (formerly Autohelm) is a tool for declarative management of helm releases. Written in python and supports git urls as a source for helm charts. - [Rudder](https://github.com/AcalephStorage/rudder) - RESTful (JSON) proxy for Tiller's API From e3c6385959bca1d632ee59d1fccbcb1c612a53c5 Mon Sep 17 00:00:00 2001 From: Taylor Thomas Date: Thu, 3 Jan 2019 10:16:53 -0800 Subject: [PATCH 044/146] doc(release_checklist): Adds steps for categorizing changelogs Closes #5119 Also includes some formatting fixes to wrap lines at 80 chars Signed-off-by: Taylor Thomas --- docs/release_checklist.md | 156 ++++++++++++++++++++++++++++---------- 1 file changed, 117 insertions(+), 39 deletions(-) diff --git a/docs/release_checklist.md b/docs/release_checklist.md index c69db9d21..4011b6675 100644 --- a/docs/release_checklist.md +++ b/docs/release_checklist.md @@ -3,8 +3,8 @@ **IMPORTANT**: If your experience deviates from this document, please document the changes to keep it up-to-date. ## Release Meetings -As part of the release process, two of the weekly developer calls will be co-opted -as "release meetings." +As part of the release process, two of the weekly developer calls will be +co-opted as "release meetings." ### Start of the Release Cycle The first developer call after a release will be used as the release meeting to @@ -17,17 +17,19 @@ identified: - Any other important details for the community All of this information should be added to the GitHub milestone for the given -release. This should give the community and maintainers a clear set of guidelines -to follow when choosing whether or not to add issues and PRs to a given release. +release. This should give the community and maintainers a clear set of +guidelines to follow when choosing whether or not to add issues and PRs to a +given release. ### End (almost) of the Release Cycle The developer call closest to two weeks before the scheduled release date will be used to review any remaining PRs that should be pulled into the release. This -is the place to debate whether or not we should wait before cutting a release and -any other concerns. At the end of this meeting, if the release date has not been -pushed out, the first RC should be cut. Subsequent developer calls in between this -meeting and the release date should have some time set aside to see if any bugs -were found. Once the release date is reached, the final release can be cut +is the place to debate whether or not we should wait before cutting a release +and any other concerns. At the end of this meeting, if the release date has not +been pushed out, the first RC should be cut. Subsequent developer calls in +between this meeting and the release date should have some time set aside to see +if any bugs were found. Once the release date is reached, the final release can +be cut ## A Maintainer's Guide to Releasing Helm @@ -37,17 +39,28 @@ So you're in charge of a new release for Helm? Cool. Here's what to do... Just kidding! :trollface: -All releases will be of the form vX.Y.Z where X is the major version number, Y is the minor version number and Z is the patch release number. This project strictly follows [semantic versioning](http://semver.org/) so following this step is critical. +All releases will be of the form vX.Y.Z where X is the major version number, Y +is the minor version number and Z is the patch release number. This project +strictly follows [semantic versioning](http://semver.org/) so following this +step is critical. -It is important to note that this document assumes that the git remote in your repository that corresponds to "https://github.com/helm/helm" is named "upstream". If yours is not (for example, if you've chosen to name it "origin" or something similar instead), be sure to adjust the listed snippets for your local environment accordingly. If you are not sure what your upstream remote is named, use a command like `git remote -v` to find out. +It is important to note that this document assumes that the git remote in your +repository that corresponds to "https://github.com/helm/helm" is named +"upstream". If yours is not (for example, if you've chosen to name it "origin" +or something similar instead), be sure to adjust the listed snippets for your +local environment accordingly. If you are not sure what your upstream remote is +named, use a command like `git remote -v` to find out. -If you don't have an upstream remote, you can add one easily using something like: +If you don't have an upstream remote, you can add one easily using something +like: ```shell git remote add upstream git@github.com:helm/helm.git ``` -In this doc, we are going to reference a few environment variables as well, which you may want to set for convenience. For major/minor releases, use the following: +In this doc, we are going to reference a few environment variables as well, +which you may want to set for convenience. For major/minor releases, use the +following: ```shell export RELEASE_NAME=vX.Y.0 @@ -68,7 +81,10 @@ export RELEASE_CANDIDATE_NAME="$RELEASE_NAME-rc.1" ### Major/Minor Releases -Major releases are for new feature additions and behavioral changes *that break backwards compatibility*. Minor releases are for new feature additions that do not break backwards compatibility. To create a major or minor release, start by creating a `release-vX.Y.0` branch from master. +Major releases are for new feature additions and behavioral changes *that break +backwards compatibility*. Minor releases are for new feature additions that do +not break backwards compatibility. To create a major or minor release, start by +creating a `release-vX.Y.0` branch from master. ```shell git fetch upstream @@ -76,11 +92,13 @@ git checkout upstream/master git checkout -b $RELEASE_BRANCH_NAME ``` -This new branch is going to be the base for the release, which we are going to iterate upon later. +This new branch is going to be the base for the release, which we are going to +iterate upon later. ### Patch releases -Patch releases are a few critical cherry-picked fixes to existing releases. Start by creating a `release-vX.Y.Z` branch from the latest patch release. +Patch releases are a few critical cherry-picked fixes to existing releases. +Start by creating a `release-vX.Y.Z` branch from the latest patch release. ```shell git fetch upstream --tags @@ -88,7 +106,8 @@ git checkout $PREVIOUS_PATCH_RELEASE git checkout -b $RELEASE_BRANCH_NAME ``` -From here, we can cherry-pick the commits we want to bring into the patch release: +From here, we can cherry-pick the commits we want to bring into the patch +release: ```shell # get the commits ids we want to cherry-pick @@ -98,11 +117,13 @@ git cherry-pick -x git cherry-pick -x ``` -This new branch is going to be the base for the release, which we are going to iterate upon later. +This new branch is going to be the base for the release, which we are going to +iterate upon later. ## 2. Change the Version Number in Git -When doing a minor release, make sure to update pkg/version/version.go with the new release version. +When doing a minor release, make sure to update pkg/version/version.go with the +new release version. ```shell $ git diff pkg/version/version.go @@ -128,28 +149,36 @@ git commit -m "bump version to $RELEASE_CANDIDATE_NAME" ## 3. Commit and Push the Release Branch -In order for others to start testing, we can now push the release branch upstream and start the test process. +In order for others to start testing, we can now push the release branch +upstream and start the test process. ```shell git push upstream $RELEASE_BRANCH_NAME ``` -Make sure to check [helm on CircleCI](https://circleci.com/gh/helm/helm) and make sure the release passed CI before proceeding. +Make sure to check [helm on CircleCI](https://circleci.com/gh/helm/helm) and +make sure the release passed CI before proceeding. -If anyone is available, let others peer-review the branch before continuing to ensure that all the proper changes have been made and all of the commits for the release are there. +If anyone is available, let others peer-review the branch before continuing to +ensure that all the proper changes have been made and all of the commits for the +release are there. ## 4. Create a Release Candidate -Now that the release branch is out and ready, it is time to start creating and iterating on release candidates. +Now that the release branch is out and ready, it is time to start creating and +iterating on release candidates. ```shell git tag --sign --annotate "${RELEASE_CANDIDATE_NAME}" --message "Helm release ${RELEASE_CANDIDATE_NAME}" git push upstream $RELEASE_CANDIDATE_NAME ``` -CircleCI will automatically create a tagged release image and client binary to test with. +CircleCI will automatically create a tagged release image and client binary to +test with. -For testers, the process to start testing after CircleCI finishes building the artifacts involves the following steps to grab the client from Google Cloud Storage: +For testers, the process to start testing after CircleCI finishes building the +artifacts involves the following steps to grab the client from Google Cloud +Storage: linux/amd64, using /bin/bash: @@ -169,21 +198,35 @@ windows/amd64, using PowerShell: PS C:\> Invoke-WebRequest -Uri "https://kubernetes-helm.storage.googleapis.com/helm-$RELEASE_CANDIDATE_NAME-windows-amd64.zip" -OutFile "helm-$ReleaseCandidateName-windows-amd64.zip" ``` -Then, unpack and move the binary to somewhere on your $PATH, or move it somewhere and add it to your $PATH (e.g. /usr/local/bin/helm for linux/macOS, C:\Program Files\helm\helm.exe for Windows). +Then, unpack and move the binary to somewhere on your $PATH, or move it +somewhere and add it to your $PATH (e.g. /usr/local/bin/helm for linux/macOS, +C:\Program Files\helm\helm.exe for Windows). ## 5. Iterate on Successive Release Candidates -Spend several days explicitly investing time and resources to try and break helm in every possible way, documenting any findings pertinent to the release. This time should be spent testing and finding ways in which the release might have caused various features or upgrade environments to have issues, not coding. During this time, the release is in code freeze, and any additional code changes will be pushed out to the next release. +Spend several days explicitly investing time and resources to try and break helm +in every possible way, documenting any findings pertinent to the release. This +time should be spent testing and finding ways in which the release might have +caused various features or upgrade environments to have issues, not coding. +During this time, the release is in code freeze, and any additional code changes +will be pushed out to the next release. -During this phase, the $RELEASE_BRANCH_NAME branch will keep evolving as you will produce new release candidates. The frequency of new candidates is up to the release manager: use your best judgement taking into account the severity of reported issues, testers' availability, and the release deadline date. Generally speaking, it is better to let a release roll over the deadline than to ship a broken release. +During this phase, the $RELEASE_BRANCH_NAME branch will keep evolving as you +will produce new release candidates. The frequency of new candidates is up to +the release manager: use your best judgement taking into account the severity of +reported issues, testers' availability, and the release deadline date. Generally +speaking, it is better to let a release roll over the deadline than to ship a +broken release. -Each time you'll want to produce a new release candidate, you will start by adding commits to the branch by cherry-picking from master: +Each time you'll want to produce a new release candidate, you will start by +adding commits to the branch by cherry-picking from master: ```shell git cherry-pick -x ``` -You will also want to update the release version number and the CHANGELOG as we did in steps 2 and 3 as separate commits. +You will also want to update the release version number and the CHANGELOG as we +did in steps 2 and 3 as separate commits. After that, tag it and notify users of the new release candidate: @@ -197,7 +240,9 @@ From here on just repeat this process, continuously testing until you're happy w ## 6. Finalize the Release -When you're finally happy with the quality of a release candidate, you can move on and create the real thing. Double-check one last time to make sure everything is in order, then finally push the release tag. +When you're finally happy with the quality of a release candidate, you can move +on and create the real thing. Double-check one last time to make sure everything +is in order, then finally push the release tag. ```shell git checkout $RELEASE_BRANCH_NAME @@ -207,9 +252,13 @@ git push upstream $RELEASE_NAME ## 7. Write the Release Notes -We will auto-generate a changelog based on the commits that occurred during a release cycle, but it is usually more beneficial to the end-user if the release notes are hand-written by a human being/marketing team/dog. +We will auto-generate a changelog based on the commits that occurred during a +release cycle, but it is usually more beneficial to the end-user if the release +notes are hand-written by a human being/marketing team/dog. -If you're releasing a major/minor release, listing notable user-facing features is usually sufficient. For patch releases, do the same, but make note of the symptoms and who is affected. +If you're releasing a major/minor release, listing notable user-facing features +is usually sufficient. For patch releases, do the same, but make note of the +symptoms and who is affected. An example release note for a minor release would look like this: @@ -226,6 +275,13 @@ The community keeps growing, and we'd love to see you there! - Hang out at the Public Developer Call: Thursday, 9:30 Pacific via [Zoom](https://zoom.us/j/696660622) - Test, debug, and contribute charts: [GitHub/helm/charts](https://github.com/helm/charts) +## Features and Changes + +- Major +- features +- list +- here + ## Installation and Upgrading Download Helm X.Y. The common platform binaries are here: @@ -250,23 +306,45 @@ The [Quickstart Guide](https://docs.helm.sh/using_helm/#quickstart-guide) will g ## Changelog -- chore(*): bump version to v2.7.0 08c1144f5eb3e3b636d9775617287cc26e53dba4 (Adam Reese) +### Features +- ref(*): kubernetes v1.11 support efadbd88035654b2951f3958167afed014c46bc6 (Adam Reese) +- feat(helm): add $HELM_KEY_PASSPHRASE environment variable for signing helm charts (#4778) 1e26b5300b5166fabb90002535aacd2f9cc7d787 + +### Bug fixes - fix circle not building tags f4f932fabd197f7e6d608c8672b33a483b4b76fa (Matthew Fisher) + +### Code cleanup +- ref(kube): Gets rid of superfluous Sprintf call 3071a16f5eb3a2b646d9795617287cc26e53dba4 (Taylor Thomas) +- chore(*): bump version to v2.7.0 08c1144f5eb3e3b636d9775617287cc26e53dba4 (Adam Reese) + +### Documentation Changes +- docs(release_checklist): fix changelog generation command (#4694) 8442851a5c566a01d9b4c69b368d64daa04f6a7f (Matthew Fisher) ``` -The changelog at the bottom of the release notes can be generated with this command: +The changelog at the bottom of the release notes can be generated with this +command: ```shell PREVIOUS_RELEASE=vX.Y.Z git log --no-merges --pretty=format:'- %s %H (%aN)' $PREVIOUS_RELEASE..$RELEASE_NAME ``` -Once finished, go into GitHub and edit the release notes for the tagged release with the notes written here. +After generating the changelog, you will need to categorize the changes as shown +in the example above. + +Once finished, go into GitHub and edit the release notes for the tagged release +with the notes written here. ## 8. Evangelize -Congratulations! You're done. Go grab yourself a $DRINK_OF_CHOICE. You've earned it. +Congratulations! You're done. Go grab yourself a $DRINK_OF_CHOICE. You've earned +it. -After enjoying a nice $DRINK_OF_CHOICE, go forth and announce the glad tidings of the new release in Slack and on Twitter. You should also notify any key partners in the helm community such as the homebrew formula maintainers, the owners of incubator projects (e.g. ChartMuseum) and any other interested parties. +After enjoying a nice $DRINK_OF_CHOICE, go forth and announce the glad tidings +of the new release in Slack and on Twitter. You should also notify any key +partners in the helm community such as the homebrew formula maintainers, the +owners of incubator projects (e.g. ChartMuseum) and any other interested +parties. -Optionally, write a blog post about the new release and showcase some of the new features on there! +Optionally, write a blog post about the new release and showcase some of the new +features on there! From 4634f5f2faa0caa7de390c95c7d27be22d56a156 Mon Sep 17 00:00:00 2001 From: Eric Thiebaut-George Date: Tue, 8 Jan 2019 16:14:43 +0000 Subject: [PATCH 045/146] Recommend using crd-install instead of pre-install (#5139) * 5138 Recommended using crd-install instead of pre-install Signed-off-by: Eric Thiebaut-George * 5138 Updated section title Signed-off-by: Eric Thiebaut-George --- docs/chart_best_practices/custom_resource_definitions.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/chart_best_practices/custom_resource_definitions.md b/docs/chart_best_practices/custom_resource_definitions.md index 96690dc9b..ee6fcf470 100644 --- a/docs/chart_best_practices/custom_resource_definitions.md +++ b/docs/chart_best_practices/custom_resource_definitions.md @@ -28,10 +28,10 @@ resources that use that CRD in _another_ chart. In this method, each chart must be installed separately. -### Method 2: Pre-install Hooks +### Method 2: Crd-install Hooks -To package the two together, add a `pre-install` hook to the CRD definition so +To package the two together, add a `crd-install` hook to the CRD definition so that it is fully installed before the rest of the chart is executed. -Note that if you create the CRD with a `pre-install` hook, that CRD definition +Note that if you create the CRD with a `crd-install` hook, that CRD definition will not be deleted when `helm delete` is run. From 7c55fdcf024e83d78b47102dd27315728400c860 Mon Sep 17 00:00:00 2001 From: Elad Iwanir Date: Tue, 8 Jan 2019 20:00:49 +0200 Subject: [PATCH 046/146] Sort resources output by 'helm status' Signed-off-by: Elad Iwanir --- pkg/kube/client.go | 81 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 62 insertions(+), 19 deletions(-) diff --git a/pkg/kube/client.go b/pkg/kube/client.go index 4a387d524..513f7400d 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -24,6 +24,7 @@ import ( "fmt" "io" "log" + "sort" "strings" "time" @@ -151,13 +152,41 @@ func (c *Client) Build(namespace string, reader io.Reader) (Result, error) { return result, scrubValidationError(err) } +// Return the resource info as internal +func resourceInfoToObject(info *resource.Info) runtime.Object { + internalObj, err := asInternal(info) + if err != nil { + // If the problem is just that the resource is not registered, don't print any + // error. This is normal for custom resources. + if !runtime.IsNotRegisteredError(err) { + c.Log("Warning: conversion to internal type failed: %v", err) + } + // Add the unstructured object in this situation. It will still get listed, just + // with less information. + return info.Object + } + + return internalObj +} + +func sortByKey(objs map[string](map[string]runtime.Object)) []string { + var keys []string + // Create a simple slice, so we can sort it + for key := range objs { + keys = append(keys, key) + } + // Sort alphabetically by version/kind keys + sort.Strings(keys) + return keys +} + // Get gets Kubernetes resources as pretty-printed string. // // Namespace will set the namespace. func (c *Client) Get(namespace string, reader io.Reader) (string, error) { - // Since we don't know what order the objects come in, let's group them by the types, so + // Since we don't know what order the objects come in, let's group them by the types and then sort them, so // that when we print them, they come out looking good (headers apply to subgroups, etc.). - objs := make(map[string][]runtime.Object) + objs := make(map[string](map[string]runtime.Object)) infos, err := c.BuildUnstructured(namespace, reader) if err != nil { return "", err @@ -178,19 +207,15 @@ func (c *Client) Get(namespace string, reader io.Reader) (string, error) { // versions per cluster, but this certainly won't hurt anything, so let's be safe. gvk := info.ResourceMapping().GroupVersionKind vk := gvk.Version + "/" + gvk.Kind - internalObj, err := asInternal(info) - if err != nil { - // If the problem is just that the resource is not registered, don't print any - // error. This is normal for custom resources. - if !runtime.IsNotRegisteredError(err) { - c.Log("Warning: conversion to internal type failed: %v", err) - } - // Add the unstructured object in this situation. It will still get listed, just - // with less information. - objs[vk] = append(objs[vk], info.Object) - } else { - objs[vk] = append(objs[vk], internalObj) + + // Initialize map. The main map groups resources based on version/kind + // The second level is a simple 'Name' to 'Object', that will help sort + // the individual resource later + if objs[vk] == nil { + objs[vk] = make(map[string]runtime.Object) } + // Map between the resource name to the underlying info object + objs[vk][info.Name] = resourceInfoToObject(info) //Get the relation pods objPods, err = c.getSelectRelationPod(info, objPods) @@ -208,8 +233,12 @@ func (c *Client) Get(namespace string, reader io.Reader) (string, error) { for key, podItems := range objPods { for i := range podItems { pod := &core.Pod{} + legacyscheme.Scheme.Convert(&podItems[i], pod, nil) - objs[key+"(related)"] = append(objs[key+"(related)"], pod) + if objs[key+"(related)"] == nil { + objs[key+"(related)"] = make(map[string]runtime.Object) + } + objs[key+"(related)"][pod.ObjectMeta.Name] = runtime.Object(pod) } } @@ -219,14 +248,28 @@ func (c *Client) Get(namespace string, reader io.Reader) (string, error) { // track of tab widths. buf := new(bytes.Buffer) printFlags := get.NewHumanPrintFlags() - for t, ot := range objs { + + // Sort alphabetically by version/kind keys + vkKeys := sortByKey(objs) + // Iterate on sorted version/kind types + for _, t := range vkKeys { if _, err = fmt.Fprintf(buf, "==> %s\n", t); err != nil { return "", err } typePrinter, _ := printFlags.ToPrinter("") - for _, o := range ot { - if err := typePrinter.PrintObj(o, buf); err != nil { - c.Log("failed to print object type %s, object: %q :\n %v", t, o, err) + + var sortedResources []string + for resource := range objs[t] { + sortedResources = append(sortedResources, resource) + } + sort.Strings(sortedResources) + + // Now that each individual resource within the specific version/kind + // is sorted, we print each resource using the k8s printer + for _, resourceName := range sortedResources { + vk := objs[t] + if err := typePrinter.PrintObj(vk[resourceName], buf); err != nil { + c.Log("failed to print object type %s, object: %q :\n %v", t, resourceName, err) return "", err } } From cbf9ad11be1153d72cade3212d708112af97eefe Mon Sep 17 00:00:00 2001 From: Elad Iwanir Date: Tue, 8 Jan 2019 20:14:39 +0200 Subject: [PATCH 047/146] fix minor build issue Signed-off-by: Elad Iwanir --- pkg/kube/client.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/kube/client.go b/pkg/kube/client.go index 513f7400d..9aa821b5a 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -153,7 +153,7 @@ func (c *Client) Build(namespace string, reader io.Reader) (Result, error) { } // Return the resource info as internal -func resourceInfoToObject(info *resource.Info) runtime.Object { +func resourceInfoToObject(info *resource.Info, c *Client) runtime.Object { internalObj, err := asInternal(info) if err != nil { // If the problem is just that the resource is not registered, don't print any @@ -215,7 +215,7 @@ func (c *Client) Get(namespace string, reader io.Reader) (string, error) { objs[vk] = make(map[string]runtime.Object) } // Map between the resource name to the underlying info object - objs[vk][info.Name] = resourceInfoToObject(info) + objs[vk][info.Name] = resourceInfoToObject(info, c) //Get the relation pods objPods, err = c.getSelectRelationPod(info, objPods) From e70bea6adb6825e4f0cce1917121e6e000bf9049 Mon Sep 17 00:00:00 2001 From: JoeWrightss <42261994+JoeWrightss@users.noreply.github.com> Date: Thu, 10 Jan 2019 05:09:50 +0800 Subject: [PATCH 048/146] Fix some spelling errors (#5114) Signed-off-by: JoeWrightss --- _proto/hapi/services/tiller.proto | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_proto/hapi/services/tiller.proto b/_proto/hapi/services/tiller.proto index 8eba963e4..e00c50caf 100644 --- a/_proto/hapi/services/tiller.proto +++ b/_proto/hapi/services/tiller.proto @@ -76,7 +76,7 @@ service ReleaseService { rpc RollbackRelease(RollbackReleaseRequest) returns (RollbackReleaseResponse) { } - // ReleaseHistory retrieves a releasse's history. + // ReleaseHistory retrieves a release's history. rpc GetHistory(GetHistoryRequest) returns (GetHistoryResponse) { } @@ -298,7 +298,7 @@ message UninstallReleaseRequest { bool purge = 3; // timeout specifies the max amount of time any kubernetes client command can run. int64 timeout = 4; - // Description, if set, will set the description for the uninnstalled release + // Description, if set, will set the description for the uninstalled release string description = 5; } From 8015fc35707050ae4578000cfe89fcba66112f07 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Thu, 10 Jan 2019 08:09:55 -0800 Subject: [PATCH 049/146] bump version to v2.12 (#4991) (cherry picked from commit 657557947c62efca6c9b8f81a62540e27901717b) Signed-off-by: Matthew Fisher --- pkg/version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/version/version.go b/pkg/version/version.go index dae739500..692167b83 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.11" + Version = "v2.12" // BuildMetadata is extra build time data BuildMetadata = "unreleased" From 893c3b61f6594232a57f232034afc418d2466878 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20K=C3=B6hler?= <9337156+axdotl@users.noreply.github.com> Date: Thu, 10 Jan 2019 18:05:44 +0100 Subject: [PATCH 050/146] Add chart name check to lint (#3773) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Axel Köhler --- .gitignore | 1 + pkg/lint/rules/chartfile.go | 12 ++++++++++-- pkg/lint/rules/chartfile_test.go | 16 +++++++++++++--- pkg/lint/rules/testdata/badnamechart/Chart.yaml | 4 ++++ pkg/lint/rules/testdata/badnamechart/values.yaml | 1 + 5 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 pkg/lint/rules/testdata/badnamechart/Chart.yaml create mode 100644 pkg/lint/rules/testdata/badnamechart/values.yaml diff --git a/.gitignore b/.gitignore index 7fdfdcf2a..2414f7f2b 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ rootfs/rudder vendor/ *.exe .idea/ +*.iml \ No newline at end of file diff --git a/pkg/lint/rules/chartfile.go b/pkg/lint/rules/chartfile.go index 12f028af1..95ee38f0b 100644 --- a/pkg/lint/rules/chartfile.go +++ b/pkg/lint/rules/chartfile.go @@ -46,7 +46,8 @@ func Chartfile(linter *support.Linter) { return } - linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartName(chartFile)) + linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartNamePresence(chartFile)) + linter.RunLinterRule(support.WarningSev, chartFileName, validateChartNameFormat(chartFile)) linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartNameDirMatch(linter.ChartDir, chartFile)) // Chart metadata @@ -74,13 +75,20 @@ func validateChartYamlFormat(chartFileError error) error { return nil } -func validateChartName(cf *chart.Metadata) error { +func validateChartNamePresence(cf *chart.Metadata) error { if cf.Name == "" { return errors.New("name is required") } return nil } +func validateChartNameFormat(cf *chart.Metadata) error { + if strings.Contains(cf.Name, ".") { + return errors.New("name should be lower case letters and numbers. Words may be separated with dashes") + } + return nil +} + func validateChartNameDirMatch(chartDir string, cf *chart.Metadata) error { if cf.Name != filepath.Base(chartDir) { return fmt.Errorf("directory name (%s) and chart name (%s) must be the same", filepath.Base(chartDir), cf.Name) diff --git a/pkg/lint/rules/chartfile_test.go b/pkg/lint/rules/chartfile_test.go index 235e5fc4c..2422a2d10 100644 --- a/pkg/lint/rules/chartfile_test.go +++ b/pkg/lint/rules/chartfile_test.go @@ -29,17 +29,20 @@ import ( ) const ( - badChartDir = "testdata/badchartfile" - goodChartDir = "testdata/goodone" + badChartDir = "testdata/badchartfile" + badNameChartDir = "testdata/badnamechart" + goodChartDir = "testdata/goodone" ) var ( badChartFilePath = filepath.Join(badChartDir, "Chart.yaml") + badNameChartFilePath = filepath.Join(badNameChartDir, "Chart.yaml") goodChartFilePath = filepath.Join(goodChartDir, "Chart.yaml") nonExistingChartFilePath = filepath.Join(os.TempDir(), "Chart.yaml") ) var badChart, chatLoadRrr = chartutil.LoadChartfile(badChartFilePath) +var badNameChart, _ = chartutil.LoadChartfile(badNameChartFilePath) var goodChart, _ = chartutil.LoadChartfile(goodChartFilePath) // Validation functions Test @@ -66,12 +69,19 @@ func TestValidateChartYamlFormat(t *testing.T) { } func TestValidateChartName(t *testing.T) { - err := validateChartName(badChart) + err := validateChartNamePresence(badChart) if err == nil { t.Errorf("validateChartName to return a linter error, got no error") } } +func TestValidateChartNameFormat(t *testing.T) { + err := validateChartNameFormat(badNameChart) + if err == nil { + t.Errorf("validateChartNameFormat to return a linter error, got no error") + } +} + func TestValidateChartNameDirMatch(t *testing.T) { err := validateChartNameDirMatch(goodChartDir, goodChart) if err != nil { diff --git a/pkg/lint/rules/testdata/badnamechart/Chart.yaml b/pkg/lint/rules/testdata/badnamechart/Chart.yaml new file mode 100644 index 000000000..6ac6cfa42 --- /dev/null +++ b/pkg/lint/rules/testdata/badnamechart/Chart.yaml @@ -0,0 +1,4 @@ +name: bad.chart.name +description: A Helm chart for Kubernetes +version: 0.1.0 +icon: http://riverrun.io diff --git a/pkg/lint/rules/testdata/badnamechart/values.yaml b/pkg/lint/rules/testdata/badnamechart/values.yaml new file mode 100644 index 000000000..54deecf74 --- /dev/null +++ b/pkg/lint/rules/testdata/badnamechart/values.yaml @@ -0,0 +1 @@ +# Default values for badchartname. From 5603fe8d3e6ca9347ea0c2a94b2b33a55f5134cd Mon Sep 17 00:00:00 2001 From: Matt Butcher Date: Mon, 14 Jan 2019 10:03:35 -0700 Subject: [PATCH 051/146] fix: perform extra validation on paths in tar archives (#5165) * fix: perform extra validation on paths in tar archives Signed-off-by: Matt Butcher * fix: Cover a few Windows cases and also remove a duplicate tar reader Signed-off-by: Matt Butcher * fix: removed debug output Signed-off-by: Matt Butcher * fix: Expand again preserves the files verbatim Also added tests for Expand Signed-off-by: Matt Butcher * fix: add license block and remove println Signed-off-by: Matt Butcher --- pkg/chartutil/expand.go | 64 +++++++++--------- pkg/chartutil/expand_test.go | 121 +++++++++++++++++++++++++++++++++++ pkg/chartutil/load.go | 43 +++++++++++-- pkg/chartutil/load_test.go | 97 ++++++++++++++++++++++++++++ 4 files changed, 289 insertions(+), 36 deletions(-) create mode 100644 pkg/chartutil/expand_test.go diff --git a/pkg/chartutil/expand.go b/pkg/chartutil/expand.go index 1d49b159f..9ed021d9c 100644 --- a/pkg/chartutil/expand.go +++ b/pkg/chartutil/expand.go @@ -17,58 +17,60 @@ limitations under the License. package chartutil import ( - "archive/tar" - "compress/gzip" + "errors" "io" + "io/ioutil" "os" "path/filepath" + + securejoin "github.com/cyphar/filepath-securejoin" ) // Expand uncompresses and extracts a chart into the specified directory. func Expand(dir string, r io.Reader) error { - gr, err := gzip.NewReader(r) + files, err := loadArchiveFiles(r) if err != nil { return err } - defer gr.Close() - tr := tar.NewReader(gr) - for { - header, err := tr.Next() - if err == io.EOF { - break - } else if err != nil { - return err - } - //split header name and create missing directories - d, _ := filepath.Split(header.Name) - fullDir := filepath.Join(dir, d) - _, err = os.Stat(fullDir) - if err != nil && d != "" { - if err := os.MkdirAll(fullDir, 0700); err != nil { + // Get the name of the chart + var chartName string + for _, file := range files { + if file.Name == "Chart.yaml" { + ch, err := UnmarshalChartfile(file.Data) + if err != nil { return err } + chartName = ch.GetName() } + } + if chartName == "" { + return errors.New("chart name not specified") + } - path := filepath.Clean(filepath.Join(dir, header.Name)) - info := header.FileInfo() - if info.IsDir() { - if err = os.MkdirAll(path, info.Mode()); err != nil { - return err - } - continue - } + // Find the base directory + chartdir, err := securejoin.SecureJoin(dir, chartName) + if err != nil { + return err + } - file, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, info.Mode()) + // Copy all files verbatim. We don't parse these files because parsing can remove + // comments. + for _, file := range files { + outpath, err := securejoin.SecureJoin(chartdir, file.Name) if err != nil { return err } - _, err = io.Copy(file, tr) - if err != nil { - file.Close() + + // Make sure the necessary subdirs get created. + basedir := filepath.Dir(outpath) + if err := os.MkdirAll(basedir, 0755); err != nil { + return err + } + + if err := ioutil.WriteFile(outpath, file.Data, 0644); err != nil { return err } - file.Close() } return nil } diff --git a/pkg/chartutil/expand_test.go b/pkg/chartutil/expand_test.go new file mode 100644 index 000000000..80fd4416b --- /dev/null +++ b/pkg/chartutil/expand_test.go @@ -0,0 +1,121 @@ +/* +Copyright The Helm Authors. + +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 chartutil + +import ( + "io/ioutil" + "os" + "path/filepath" + "testing" +) + +func TestExpand(t *testing.T) { + dest, err := ioutil.TempDir("", "helm-testing-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dest) + + reader, err := os.Open("testdata/frobnitz-1.2.3.tgz") + if err != nil { + t.Fatal(err) + } + + if err := Expand(dest, reader); err != nil { + t.Fatal(err) + } + + expectedChartPath := filepath.Join(dest, "frobnitz") + fi, err := os.Stat(expectedChartPath) + if err != nil { + t.Fatal(err) + } + if !fi.IsDir() { + t.Fatalf("expected a chart directory at %s", expectedChartPath) + } + + dir, err := os.Open(expectedChartPath) + if err != nil { + t.Fatal(err) + } + + fis, err := dir.Readdir(0) + if err != nil { + t.Fatal(err) + } + + expectLen := 12 + if len(fis) != expectLen { + t.Errorf("Expected %d files, but got %d", expectLen, len(fis)) + } + + for _, fi := range fis { + expect, err := os.Stat(filepath.Join("testdata", "frobnitz", fi.Name())) + if err != nil { + t.Fatal(err) + } + if fi.Size() != expect.Size() { + t.Errorf("Expected %s to have size %d, got %d", fi.Name(), expect.Size(), fi.Size()) + } + } +} + +func TestExpandFile(t *testing.T) { + dest, err := ioutil.TempDir("", "helm-testing-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dest) + + if err := ExpandFile(dest, "testdata/frobnitz-1.2.3.tgz"); err != nil { + t.Fatal(err) + } + + expectedChartPath := filepath.Join(dest, "frobnitz") + fi, err := os.Stat(expectedChartPath) + if err != nil { + t.Fatal(err) + } + if !fi.IsDir() { + t.Fatalf("expected a chart directory at %s", expectedChartPath) + } + + dir, err := os.Open(expectedChartPath) + if err != nil { + t.Fatal(err) + } + + fis, err := dir.Readdir(0) + if err != nil { + t.Fatal(err) + } + + expectLen := 12 + if len(fis) != expectLen { + t.Errorf("Expected %d files, but got %d", expectLen, len(fis)) + } + + for _, fi := range fis { + expect, err := os.Stat(filepath.Join("testdata", "frobnitz", fi.Name())) + if err != nil { + t.Fatal(err) + } + if fi.Size() != expect.Size() { + t.Errorf("Expected %s to have size %d, got %d", fi.Name(), expect.Size(), fi.Size()) + } + } +} diff --git a/pkg/chartutil/load.go b/pkg/chartutil/load.go index 9f1c80c85..f4741516e 100644 --- a/pkg/chartutil/load.go +++ b/pkg/chartutil/load.go @@ -25,7 +25,9 @@ import ( "io" "io/ioutil" "os" + "path" "path/filepath" + "regexp" "strings" "github.com/golang/protobuf/ptypes/any" @@ -63,11 +65,13 @@ type BufferedFile struct { Data []byte } -// LoadArchive loads from a reader containing a compressed tar archive. -func LoadArchive(in io.Reader) (*chart.Chart, error) { +var drivePathPattern = regexp.MustCompile(`^[a-zA-Z]:/`) + +// loadArchiveFiles loads files out of an archive +func loadArchiveFiles(in io.Reader) ([]*BufferedFile, error) { unzipped, err := gzip.NewReader(in) if err != nil { - return &chart.Chart{}, err + return nil, err } defer unzipped.Close() @@ -80,7 +84,7 @@ func LoadArchive(in io.Reader) (*chart.Chart, error) { break } if err != nil { - return &chart.Chart{}, err + return nil, err } if hd.FileInfo().IsDir() { @@ -101,12 +105,33 @@ func LoadArchive(in io.Reader) (*chart.Chart, error) { // Normalize the path to the / delimiter n = strings.Replace(n, delimiter, "/", -1) + if path.IsAbs(n) { + return nil, errors.New("chart illegally contains absolute paths") + } + + n = path.Clean(n) + if n == "." { + // In this case, the original path was relative when it should have been absolute. + return nil, errors.New("chart illegally contains empty path") + } + if strings.HasPrefix(n, "..") { + return nil, errors.New("chart illegally references parent directory") + } + + // In some particularly arcane acts of path creativity, it is possible to intermix + // UNIX and Windows style paths in such a way that you produce a result of the form + // c:/foo even after all the built-in absolute path checks. So we explicitly check + // for this condition. + if drivePathPattern.MatchString(n) { + return nil, errors.New("chart contains illegally named files") + } + if parts[0] == "Chart.yaml" { return nil, errors.New("chart yaml not in base directory") } if _, err := io.Copy(b, tr); err != nil { - return &chart.Chart{}, err + return files, err } files = append(files, &BufferedFile{Name: n, Data: b.Bytes()}) @@ -116,7 +141,15 @@ func LoadArchive(in io.Reader) (*chart.Chart, error) { if len(files) == 0 { return nil, errors.New("no files in chart archive") } + return files, nil +} +// LoadArchive loads from a reader containing a compressed tar archive. +func LoadArchive(in io.Reader) (*chart.Chart, error) { + files, err := loadArchiveFiles(in) + if err != nil { + return nil, err + } return LoadFiles(files) } diff --git a/pkg/chartutil/load_test.go b/pkg/chartutil/load_test.go index 5cb15fbdc..c031a6a96 100644 --- a/pkg/chartutil/load_test.go +++ b/pkg/chartutil/load_test.go @@ -17,8 +17,14 @@ limitations under the License. package chartutil import ( + "archive/tar" + "compress/gzip" + "io/ioutil" + "os" "path" + "path/filepath" "testing" + "time" "k8s.io/helm/pkg/proto/hapi/chart" ) @@ -43,6 +49,97 @@ func TestLoadFile(t *testing.T) { verifyRequirements(t, c) } +func TestLoadArchive_InvalidArchive(t *testing.T) { + tmpdir, err := ioutil.TempDir("", "helm-test-") + if err != nil { + t.Fatal(err) + } + defer os.Remove(tmpdir) + + writeTar := func(filename, internalPath string, body []byte) { + dest, err := os.Create(filename) + if err != nil { + t.Fatal(err) + } + zipper := gzip.NewWriter(dest) + tw := tar.NewWriter(zipper) + + h := &tar.Header{ + Name: internalPath, + Mode: 0755, + Size: int64(len(body)), + ModTime: time.Now(), + } + if err := tw.WriteHeader(h); err != nil { + t.Fatal(err) + } + if _, err := tw.Write(body); err != nil { + t.Fatal(err) + } + tw.Close() + zipper.Close() + dest.Close() + } + + for _, tt := range []struct { + chartname string + internal string + expectError string + }{ + {"illegal-dots.tgz", "../../malformed-helm-test", "chart illegally references parent directory"}, + {"illegal-dots2.tgz", "/foo/../../malformed-helm-test", "chart illegally references parent directory"}, + {"illegal-dots3.tgz", "/../../malformed-helm-test", "chart illegally references parent directory"}, + {"illegal-dots4.tgz", "./../../malformed-helm-test", "chart illegally references parent directory"}, + {"illegal-name.tgz", "./.", "chart illegally contains empty path"}, + {"illegal-name2.tgz", "/./.", "chart illegally contains empty path"}, + {"illegal-name3.tgz", "missing-leading-slash", "chart illegally contains empty path"}, + {"illegal-name4.tgz", "/missing-leading-slash", "chart metadata (Chart.yaml) missing"}, + {"illegal-abspath.tgz", "//foo", "chart illegally contains absolute paths"}, + {"illegal-abspath2.tgz", "///foo", "chart illegally contains absolute paths"}, + {"illegal-abspath3.tgz", "\\\\foo", "chart illegally contains absolute paths"}, + {"illegal-abspath3.tgz", "\\..\\..\\foo", "chart illegally references parent directory"}, + + // Under special circumstances, this can get normalized to things that look like absolute Windows paths + {"illegal-abspath4.tgz", "\\.\\c:\\\\foo", "chart contains illegally named files"}, + {"illegal-abspath5.tgz", "/./c://foo", "chart contains illegally named files"}, + {"illegal-abspath6.tgz", "\\\\?\\Some\\windows\\magic", "chart illegally contains absolute paths"}, + } { + illegalChart := filepath.Join(tmpdir, tt.chartname) + writeTar(illegalChart, tt.internal, []byte("hello: world")) + _, err = Load(illegalChart) + if err == nil { + t.Fatal("expected error when unpacking illegal files") + } + if err.Error() != tt.expectError { + t.Errorf("Expected %q, got %q for %s", tt.expectError, err.Error(), tt.chartname) + } + } + + // Make sure that absolute path gets interpreted as relative + illegalChart := filepath.Join(tmpdir, "abs-path.tgz") + writeTar(illegalChart, "/Chart.yaml", []byte("hello: world")) + _, err = Load(illegalChart) + if err.Error() != "invalid chart (Chart.yaml): name must not be empty" { + t.Error(err) + } + + // And just to validate that the above was not spurious + illegalChart = filepath.Join(tmpdir, "abs-path2.tgz") + writeTar(illegalChart, "files/whatever.yaml", []byte("hello: world")) + _, err = Load(illegalChart) + if err.Error() != "chart metadata (Chart.yaml) missing" { + t.Error(err) + } + + // Finally, test that drive letter gets stripped off on Windows + illegalChart = filepath.Join(tmpdir, "abs-winpath.tgz") + writeTar(illegalChart, "c:\\Chart.yaml", []byte("hello: world")) + _, err = Load(illegalChart) + if err.Error() != "invalid chart (Chart.yaml): name must not be empty" { + t.Error(err) + } +} + func TestLoadFiles(t *testing.T) { goodFiles := []*BufferedFile{ { From 315ed81116235882967f4021b739eafa44ebec5e Mon Sep 17 00:00:00 2001 From: Jon Leonard Date: Wed, 16 Jan 2019 11:32:54 -0500 Subject: [PATCH 052/146] Restore comment text Signed-off-by: Jon Leonard --- pkg/helm/option.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/helm/option.go b/pkg/helm/option.go index a34c4b8ae..391913094 100644 --- a/pkg/helm/option.go +++ b/pkg/helm/option.go @@ -53,7 +53,7 @@ type options struct { disableHooks bool // if set, skip CRD hook only disableCRDHook bool - // if set, render SubChart Notes + // name of release releaseName string // tls.Config to use for rpc if tls enabled tlsConfig *tls.Config From a4bc9fd7330fc3886caba52d1a33f0c8a907e4d4 Mon Sep 17 00:00:00 2001 From: Deepak Sattiraju Date: Thu, 17 Jan 2019 22:04:32 +0530 Subject: [PATCH 053/146] Fixing helm search display format #5148 (#5162) Signed-off-by: ds-ms --- cmd/helm/search.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/helm/search.go b/cmd/helm/search.go index 84f328d41..2e7611609 100644 --- a/cmd/helm/search.go +++ b/cmd/helm/search.go @@ -154,7 +154,7 @@ func (s *searchCmd) buildIndex() (*search.Index, error) { f := s.helmhome.CacheIndex(n) ind, err := repo.LoadIndexFile(f) if err != nil { - fmt.Fprintf(s.out, "WARNING: Repo %q is corrupt or missing. Try 'helm repo update'.", n) + fmt.Fprintf(s.out, "WARNING: Repo %q is corrupt or missing. Try 'helm repo update'.\n", n) continue } From 6453dbe575eeea92c5d40a9898a24a22b517b780 Mon Sep 17 00:00:00 2001 From: Martin Hickey Date: Mon, 21 Jan 2019 11:49:43 +0000 Subject: [PATCH 054/146] Add content on how community members can help review PRs Updated text to better elaborate on he process and also some small other nits/updates. Signed-off-by: Martin Hickey --- CONTRIBUTING.md | 47 +++++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index aba3388a6..7736cbd6b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -84,12 +84,12 @@ your PR will be rejected by the automated DCO check. Whether you are a user or contributor, official support channels include: -- GitHub [issues](https://github.com/helm/helm/issues/new) -- Slack [Kubernetes Slack](http://slack.kubernetes.io/): - - User: #helm-users - - Contributor: #helm-dev +- [Issues](https://github.com/helm/helm/issues) +- Slack: + - User: [#helm-users](https://kubernetes.slack.com/messages/C0NH30761/details/) + - Contributor: [#helm-dev](https://kubernetes.slack.com/messages/C51E88VDG/) -Before opening a new issue or submitting a new pull request, it's helpful to search the project - it's likely that another user has already reported the issue you're facing, or it's a known issue that we're already aware of. +Before opening a new issue or submitting a new pull request, it's helpful to search the project - it's likely that another user has already reported the issue you're facing, or it's a known issue that we're already aware of. It is also worth asking on the Slack channels. ## Milestones @@ -180,33 +180,33 @@ contributing to Helm. All issue types follow the same general lifecycle. Differe Coding conventions and standards are explained in the official developer docs: [Developers Guide](docs/developers.md) -The next section contains more information on the workflow followed for PRs +The next section contains more information on the workflow followed for Pull Requests. ## Pull Requests -Like any good open source project, we use Pull Requests to track code changes +Like any good open source project, we use Pull Requests (PRs) to track code changes. ### PR Lifecycle 1. PR creation + - PRs are usually created to fix or else be a subset of other PRs that fix a particular issue. - We more than welcome PRs that are currently in progress. They are a great way to keep track of important work that is in-flight, but useful for others to see. If a PR is a work in progress, it **must** be prefaced with "WIP: [title]". Once the PR is ready for review, remove "WIP" from the title. - - It is preferred, but not required, to have a PR tied to a specific issue. + - It is preferred, but not required, to have a PR tied to a specific issue. There can be + circumstances where if it is a quick fix then an issue might be overkill. The details provided + in the PR description would suffice in this case. 2. Triage - The maintainer in charge of triaging will apply the proper labels for the issue. This should include at least a size label, `bug` or `feature`, and `awaiting review` once all labels are applied. - See the [Labels section](#labels) for full details on the definitions of labels + See the [Labels section](#labels) for full details on the definitions of labels. - Add the PR to the correct milestone. This should be the same as the issue the PR closes. 3. Assigning reviews - Once a review has the `awaiting review` label, maintainers will review them as schedule permits. The maintainer who takes the issue should self-request a review. - - Reviews from others in the community, especially those who have encountered a bug or have - requested a feature, are highly encouraged, but not required. Maintainer reviews **are** required - before any merge - Any PR with the `size/large` label requires 2 review approvals from maintainers before it can be - merged. Those with `size/medium` are per the judgement of the maintainers + merged. Those with `size/medium` or `size/small` are per the judgement of the maintainers. 4. Reviewing/Discussion - Once a maintainer begins reviewing a PR, they will remove the `awaiting review` label and add the `in progress` label so the person submitting knows that it is being worked on. This is @@ -214,17 +214,24 @@ Like any good open source project, we use Pull Requests to track code changes - All reviews will be completed using Github review tool. - A "Comment" review should be used when there are questions about the code that should be answered, but that don't involve code changes. This type of review does not count as approval. - - A "Changes Requested" review indicates that changes to the code need to be made before they will be merged. - - Reviewers should update labels as needed (such as `needs rebase`) -5. Address comments by answering questions or changing code + - A "Changes Requested" review indicates that changes to the code need to be made before they will be + merged. + - Reviewers (maintainers) should update labels as needed (such as `needs rebase`). + - Reviews are also welcome from others in the community, especially those who have encountered a bug or + have requested a feature. In the code review, a message can be added, as well as `LGTM` if the PR is + good to merge. It’s also possible to add comments to specific lines in a file, for giving context + to the comment. +5. PR owner should try to be responsive to comments by answering questions or changing code. If the + owner is unsure of any comment, reach out to the person who added the comment in + [#helm-dev](https://kubernetes.slack.com/messages/C51E88VDG/). Once all comments have been addressed, + the PR is ready to be merged. 6. Merge or close - PRs should stay open until merged or if they have not been active for more than 30 days. This will help keep the PR queue to a manageable size and reduce noise. Should the PR need to stay open (like in the case of a WIP), the `keep open` label can be added. - - If the owner of the PR is listed in `OWNERS`, that user **must** merge their own PRs - or explicitly request another OWNER do that for them. - - If the owner of a PR is _not_ listed in `OWNERS`, any core committer may - merge the PR once it is approved. + - If the owner of the PR is listed in `OWNERS`, that user **must** merge their own PRs or explicitly + request another OWNER do that for them. + - If the owner of a PR is _not_ listed in `OWNERS`, any maintainer may merge the PR once it is approved. #### Documentation PRs From 812b74aca5f14ea67b531a41687abfee8a6399a6 Mon Sep 17 00:00:00 2001 From: Koichi Shiraishi Date: Tue, 22 Jan 2019 08:58:07 +0900 Subject: [PATCH 055/146] Fix delete.go file permission (#5194) The 'cmd/helm/delete.go' file permission is 755, change to same as another file. Signed-off-by: Koichi Shiraishi --- cmd/helm/delete.go | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 cmd/helm/delete.go diff --git a/cmd/helm/delete.go b/cmd/helm/delete.go old mode 100755 new mode 100644 From 581e6cdbb8e42753556ae48ccba8cef84c40f736 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Mon, 21 Jan 2019 15:58:57 -0800 Subject: [PATCH 056/146] fix: use RFC 1123 subdomains for name verification (#5132) As noted in Slack by a community member, release names with periods are considered usable. Switching to RFC 1123 subdomain verification continues to block bad release names like BAD_NAME, but allows names like good.name to continue working. Signed-off-by: Matthew Fisher --- cmd/helm/install.go | 4 ++-- cmd/helm/install_test.go | 1 - cmd/helm/template.go | 4 ++-- cmd/helm/template_test.go | 8 ++++---- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/cmd/helm/install.go b/cmd/helm/install.go index f33747ac4..5ddb31054 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -251,8 +251,8 @@ func (i *installCmd) run() error { fmt.Printf("FINAL NAME: %s\n", i.name) } - if msgs := validation.IsDNS1123Label(i.name); i.name != "" && len(msgs) > 0 { - return fmt.Errorf("release name %s is not a valid DNS label: %s", i.name, strings.Join(msgs, ";")) + if msgs := validation.IsDNS1123Subdomain(i.name); i.name != "" && len(msgs) > 0 { + return fmt.Errorf("release name %s is invalid: %s", i.name, strings.Join(msgs, ";")) } // Check chart requirements to make sure all dependencies are present in /charts diff --git a/cmd/helm/install_test.go b/cmd/helm/install_test.go index 4a2055640..5f7ffdb50 100644 --- a/cmd/helm/install_test.go +++ b/cmd/helm/install_test.go @@ -169,7 +169,6 @@ func TestInstall(t *testing.T) { name: "install chart with release name using periods", args: []string{"testdata/testcharts/alpine"}, flags: []string{"--name", "foo.bar"}, - err: true, }, { name: "install chart with release name using underscores", diff --git a/cmd/helm/template.go b/cmd/helm/template.go index d776f2989..1838bb758 100644 --- a/cmd/helm/template.go +++ b/cmd/helm/template.go @@ -147,8 +147,8 @@ func (t *templateCmd) run(cmd *cobra.Command, args []string) error { } } - if msgs := validation.IsDNS1123Label(t.releaseName); t.releaseName != "" && len(msgs) > 0 { - return fmt.Errorf("release name %s is not a valid DNS label: %s", t.releaseName, strings.Join(msgs, ";")) + if msgs := validation.IsDNS1123Subdomain(t.releaseName); t.releaseName != "" && len(msgs) > 0 { + return fmt.Errorf("release name %s is invalid: %s", t.releaseName, strings.Join(msgs, ";")) } // Check chart requirements to make sure all dependencies are present in /charts diff --git a/cmd/helm/template_test.go b/cmd/helm/template_test.go index 98044eff0..3c5026b08 100644 --- a/cmd/helm/template_test.go +++ b/cmd/helm/template_test.go @@ -112,21 +112,21 @@ func TestTemplateCmd(t *testing.T) { desc: "verify the release name using capitals is invalid", args: []string{subchart1ChartPath, "--name", "FOO"}, expectKey: "subchart1/templates/service.yaml", - expectError: "is not a valid DNS label", + expectError: "is invalid", }, { name: "check_invalid_name_uppercase", desc: "verify the release name using periods is invalid", args: []string{subchart1ChartPath, "--name", "foo.bar"}, expectKey: "subchart1/templates/service.yaml", - expectError: "is not a valid DNS label", + expectValue: "release-name: \"foo.bar\"", }, { name: "check_invalid_name_uppercase", desc: "verify the release name using underscores is invalid", args: []string{subchart1ChartPath, "--name", "foo_bar"}, expectKey: "subchart1/templates/service.yaml", - expectError: "is not a valid DNS label", + expectError: "is invalid", }, { name: "check_release_is_install", @@ -160,7 +160,7 @@ func TestTemplateCmd(t *testing.T) { name: "check_invalid_name_template", desc: "verify the relase name generate by template is invalid", args: []string{subchart1ChartPath, "--name-template", "foobar-{{ b64enc \"abc\" }}-baz"}, - expectError: "is not a valid DNS label", + expectError: "is invalid", }, { name: "check_name_template", From af4c14b593f03190b08863da65e04ff5aa593020 Mon Sep 17 00:00:00 2001 From: Patrick Lang Date: Mon, 21 Jan 2019 21:33:57 -0800 Subject: [PATCH 057/146] Update docs/examples to use multi-arch tagged images (#5099) * update nginx example to work multi-arch Signed-off-by: Patrick Lang * Fix alpine to use a multiarch tag Signed-off-by: Patrick Lang --- docs/examples/alpine/values.yaml | 2 +- docs/examples/nginx/templates/post-install-job.yaml | 2 +- docs/examples/nginx/values.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/examples/alpine/values.yaml b/docs/examples/alpine/values.yaml index afe8cc6c0..225e0472a 100644 --- a/docs/examples/alpine/values.yaml +++ b/docs/examples/alpine/values.yaml @@ -1,6 +1,6 @@ image: repository: alpine - tag: 3.3 + tag: latest pullPolicy: IfNotPresent restartPolicy: Never diff --git a/docs/examples/nginx/templates/post-install-job.yaml b/docs/examples/nginx/templates/post-install-job.yaml index 6e32086ab..3562e6cf5 100644 --- a/docs/examples/nginx/templates/post-install-job.yaml +++ b/docs/examples/nginx/templates/post-install-job.yaml @@ -32,6 +32,6 @@ spec: restartPolicy: {{ .Values.restartPolicy }} containers: - name: post-install-job - image: "alpine:3.3" + image: "alpine:latest" # All we're going to do is sleep for a while, then exit. command: ["/bin/sleep", "{{ .Values.sleepyTime }}"] diff --git a/docs/examples/nginx/values.yaml b/docs/examples/nginx/values.yaml index b40208cce..36f2505af 100644 --- a/docs/examples/nginx/values.yaml +++ b/docs/examples/nginx/values.yaml @@ -14,7 +14,7 @@ index: >- image: repository: nginx - tag: 1.11.0 + tag: alpine pullPolicy: IfNotPresent service: From 05a365358f43a452e523d3f76b1107b6f4ff2aa7 Mon Sep 17 00:00:00 2001 From: Geoff Baskwill Date: Tue, 22 Jan 2019 10:03:01 -0500 Subject: [PATCH 058/146] fix: ignore pax header "file"s in chart validation Signed-off-by: Geoff Baskwill --- pkg/chartutil/load.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkg/chartutil/load.go b/pkg/chartutil/load.go index f4741516e..b0927a5cf 100644 --- a/pkg/chartutil/load.go +++ b/pkg/chartutil/load.go @@ -93,6 +93,12 @@ func loadArchiveFiles(in io.Reader) ([]*BufferedFile, error) { continue } + switch hd.Typeflag { + // We don't want to process these extension header files. + case tar.TypeXGlobalHeader, tar.TypeXHeader: + continue + } + // Archive could contain \ if generated on Windows delimiter := "/" if strings.ContainsRune(hd.Name, '\\') { From 197e68ec1f5cde7a78fc5053a798f939378f4158 Mon Sep 17 00:00:00 2001 From: JoeWrightss <42261994+JoeWrightss@users.noreply.github.com> Date: Sat, 26 Jan 2019 02:46:24 +0800 Subject: [PATCH 059/146] Fix some typos in comment (#5215) Signed-off-by: zhoulin xie --- pkg/helm/client.go | 2 +- pkg/helm/fake.go | 2 +- pkg/helm/option.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/helm/client.go b/pkg/helm/client.go index 771c7f3d1..0d4d16039 100644 --- a/pkg/helm/client.go +++ b/pkg/helm/client.go @@ -302,7 +302,7 @@ func (h *Client) RunReleaseTest(rlsName string, opts ...ReleaseTestOption) (<-ch return h.test(ctx, req) } -// PingTiller pings the Tiller pod and ensure's that it is up and running +// PingTiller pings the Tiller pod and ensures that it is up and running func (h *Client) PingTiller() error { ctx := NewContext() return h.ping(ctx) diff --git a/pkg/helm/fake.go b/pkg/helm/fake.go index 46be7d398..c8ce91f44 100644 --- a/pkg/helm/fake.go +++ b/pkg/helm/fake.go @@ -257,7 +257,7 @@ func (c *FakeClient) RunReleaseTest(rlsName string, opts ...ReleaseTestOption) ( return results, errc } -// PingTiller pings the Tiller pod and ensure's that it is up and running +// PingTiller pings the Tiller pod and ensures that it is up and running func (c *FakeClient) PingTiller() error { return nil } diff --git a/pkg/helm/option.go b/pkg/helm/option.go index 121f71c83..1f5cf6904 100644 --- a/pkg/helm/option.go +++ b/pkg/helm/option.go @@ -474,7 +474,7 @@ type VersionOption func(*options) // the defaults used when running the `helm upgrade` command. type UpdateOption func(*options) -// RollbackOption allows specififying various settings configurable +// RollbackOption allows specifying various settings configurable // by the helm client user for overriding the defaults used when // running the `helm rollback` command. type RollbackOption func(*options) From 0dfe2b865a9b4900ef41fc141fc88c11bd728c57 Mon Sep 17 00:00:00 2001 From: shibataka000 Date: Sun, 27 Jan 2019 02:54:12 +0900 Subject: [PATCH 060/146] Itemize text in docs/securing_installation.md (#5217) Signed-off-by: Takao Shibata --- docs/securing_installation.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/securing_installation.md b/docs/securing_installation.md index d47a98bcc..56ebad62c 100644 --- a/docs/securing_installation.md +++ b/docs/securing_installation.md @@ -69,9 +69,10 @@ When Helm clients are connecting from outside of the cluster, the security betwe Contrary to the previous [Enabling TLS](#enabling-tls) section, this section does not involve running a tiller server pod in your cluster (for what it's worth, that lines up with the current [helm v3 proposal](https://github.com/helm/community/blob/master/helm-v3/000-helm-v3.md)), thus there is no gRPC endpoint (and thus there's no need to create & manage TLS certificates to secure each gRPC endpoint). Steps: - * Fetch the latest helm release tarball from the [GitHub release page](https://github.com/helm/helm/releases), and extract and move `helm` and `tiller` somewhere on your `$PATH`. - * "Server": Run `tiller --storage=secret`. (Note that `tiller` has a default value of ":44134" for the `--listen` argument.) - * Client: In another terminal (and on the same host that the aforementioned `tiller` command was run for the previous bullet): Run `export HELM_HOST=:44134`, and then run `helm` commands as usual. + +- Fetch the latest helm release tarball from the [GitHub release page](https://github.com/helm/helm/releases), and extract and move `helm` and `tiller` somewhere on your `$PATH`. +- "Server": Run `tiller --storage=secret`. (Note that `tiller` has a default value of ":44134" for the `--listen` argument.) +- Client: In another terminal (and on the same host that the aforementioned `tiller` command was run for the previous bullet): Run `export HELM_HOST=:44134`, and then run `helm` commands as usual. ### Tiller's Release Information From 8a5c7f157106d9ba0fe1e0ab01498d454c47bb0e Mon Sep 17 00:00:00 2001 From: Alexander Nesterenko Date: Wed, 9 Jan 2019 12:33:37 +0200 Subject: [PATCH 061/146] Implement "atomic" upgrade/install Add possibility to put "--safe" argument to install and upgrade command that restores the state of cluster in case of failed install/upgrade attempt Signed-off-by: Alexander Nesterenko --- cmd/helm/install.go | 18 ++++++++++++++++++ cmd/helm/upgrade.go | 26 ++++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/cmd/helm/install.go b/cmd/helm/install.go index 5ddb31054..9e0b19487 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -131,6 +131,7 @@ type installCmd struct { version string timeout int64 wait bool + safe bool repoURL string username string password string @@ -190,6 +191,8 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command { } inst.chartPath = cp inst.client = ensureHelmClient(inst.client) + inst.wait = inst.wait || inst.safe + return inst.run() }, } @@ -212,6 +215,7 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command { f.StringVar(&inst.version, "version", "", "specify the exact chart version to install. If this is not specified, the latest version is installed") f.Int64Var(&inst.timeout, "timeout", 300, "time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks)") f.BoolVar(&inst.wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment are in a ready state before marking the release as successful. It will wait for as long as --timeout") + f.BoolVar(&inst.safe, "safe", false, "if set, upgrade process rolls back changes made in case of failed upgrade") f.StringVar(&inst.repoURL, "repo", "", "chart repository url where to locate the requested chart") f.StringVar(&inst.username, "username", "", "chart repository username where to locate the requested chart") f.StringVar(&inst.password, "password", "", "chart repository password where to locate the requested chart") @@ -307,6 +311,20 @@ func (i *installCmd) run() error { helm.InstallWait(i.wait), helm.InstallDescription(i.description)) if err != nil { + if i.safe { + fmt.Fprintf(os.Stdout, "INSTALL FAILED\nPURGING CHART\nError: %v", prettyError(err)) + deleteSideEffects := &deleteCmd{ + name: i.name, + disableHooks: i.disableHooks, + purge: true, + timeout: i.timeout, + description: "", + dryRun: i.dryRun, + out: i.out, + client: i.client, + } + if err := deleteSideEffects.run(); err != nil { return err } + } return prettyError(err) } diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go index d6c915c3a..a20a1003a 100644 --- a/cmd/helm/upgrade.go +++ b/cmd/helm/upgrade.go @@ -105,6 +105,7 @@ type upgradeCmd struct { resetValues bool reuseValues bool wait bool + safe bool repoURL string username string password string @@ -142,6 +143,7 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command { upgrade.release = args[0] upgrade.chart = args[1] upgrade.client = ensureHelmClient(upgrade.client) + upgrade.wait = upgrade.wait || upgrade.safe return upgrade.run() }, @@ -167,6 +169,7 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command { f.BoolVar(&upgrade.resetValues, "reset-values", false, "when upgrading, reset the values to the ones built into the chart") f.BoolVar(&upgrade.reuseValues, "reuse-values", false, "when upgrading, reuse the last release's values and merge in any overrides from the command line via --set and -f. If '--reset-values' is specified, this is ignored.") f.BoolVar(&upgrade.wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment are in a ready state before marking the release as successful. It will wait for as long as --timeout") + f.BoolVar(&upgrade.safe, "safe", false, "if set, upgrade process rolls back changes made in case of failed upgrade") f.StringVar(&upgrade.repoURL, "repo", "", "chart repository url where to locate the requested chart") f.StringVar(&upgrade.username, "username", "", "chart repository username where to locate the requested chart") f.StringVar(&upgrade.password, "password", "", "chart repository password where to locate the requested chart") @@ -191,6 +194,8 @@ func (u *upgradeCmd) run() error { return err } + releaseHistory, err := u.client.ReleaseHistory(u.release, helm.WithMaxHistory(1)) + if u.install { // If a release does not exist, install it. If another error occurs during // the check, ignore the error and continue with the upgrade. @@ -198,7 +203,6 @@ 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. - releaseHistory, err := u.client.ReleaseHistory(u.release, helm.WithMaxHistory(1)) if err == nil { if u.namespace == "" { @@ -232,6 +236,7 @@ func (u *upgradeCmd) run() error { timeout: u.timeout, wait: u.wait, description: u.description, + safe: u.safe, } return ic.run() } @@ -270,7 +275,24 @@ func (u *upgradeCmd) run() error { helm.UpgradeWait(u.wait), helm.UpgradeDescription(u.description)) if err != nil { - return fmt.Errorf("UPGRADE FAILED: %v", prettyError(err)) + fmt.Fprintf(u.out, "UPGRADE FAILED\nROLLING BACK\nError: %v", prettyError(err)) + if u.safe { + rollback := &rollbackCmd { + out: u.out, + client: u.client, + name: u.release, + dryRun: u.dryRun, + recreate: u.recreate, + force: u.force, + timeout: u.timeout, + wait: u.wait, + description: "", + revision: releaseHistory.Releases[0].Version, + disableHooks: u.disableHooks, + } + if err := rollback.run(); err != nil { return err } + } + return fmt.Errorf("UPGRADE FAILED: %v\n", prettyError(err)) } if settings.Debug { From 869efd59be7a960466055bc30966ebd572a4ee09 Mon Sep 17 00:00:00 2001 From: Alexander Nesterenko Date: Wed, 9 Jan 2019 13:39:09 +0200 Subject: [PATCH 062/146] Fix codestyle and update docs Signed-off-by: Alexander Nesterenko --- cmd/helm/install.go | 4 +++- cmd/helm/upgrade.go | 10 ++++++---- docs/helm/helm_install.md | 3 ++- docs/helm/helm_upgrade.md | 5 +++-- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/cmd/helm/install.go b/cmd/helm/install.go index 9e0b19487..0316b14bf 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -323,7 +323,9 @@ func (i *installCmd) run() error { out: i.out, client: i.client, } - if err := deleteSideEffects.run(); err != nil { return err } + if err := deleteSideEffects.run(); err != nil { + return err + } } return prettyError(err) } diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go index a20a1003a..527867e47 100644 --- a/cmd/helm/upgrade.go +++ b/cmd/helm/upgrade.go @@ -275,9 +275,9 @@ func (u *upgradeCmd) run() error { helm.UpgradeWait(u.wait), helm.UpgradeDescription(u.description)) if err != nil { - fmt.Fprintf(u.out, "UPGRADE FAILED\nROLLING BACK\nError: %v", prettyError(err)) + fmt.Fprintf(u.out, "UPGRADE FAILED\nROLLING BACK\nError: %v\n", prettyError(err)) if u.safe { - rollback := &rollbackCmd { + rollback := &rollbackCmd{ out: u.out, client: u.client, name: u.release, @@ -290,9 +290,11 @@ func (u *upgradeCmd) run() error { revision: releaseHistory.Releases[0].Version, disableHooks: u.disableHooks, } - if err := rollback.run(); err != nil { return err } + if err := rollback.run(); err != nil { + return err + } } - return fmt.Errorf("UPGRADE FAILED: %v\n", prettyError(err)) + return fmt.Errorf("UPGRADE FAILED: %v", prettyError(err)) } if settings.Debug { diff --git a/docs/helm/helm_install.md b/docs/helm/helm_install.md index 5406126fa..499e3222d 100644 --- a/docs/helm/helm_install.md +++ b/docs/helm/helm_install.md @@ -96,6 +96,7 @@ helm install [CHART] [flags] --render-subchart-notes render subchart notes along with the parent --replace re-use the given name, even if that name is already used. This is unsafe in production --repo string chart repository url where to locate the requested chart + --safe if set, upgrade process rolls back changes made in case of failed upgrade --set stringArray set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) --set-file stringArray set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2) --set-string stringArray set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) @@ -129,4 +130,4 @@ helm install [CHART] [flags] * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 1-Nov-2018 +###### Auto generated by spf13/cobra on 9-Jan-2019 diff --git a/docs/helm/helm_upgrade.md b/docs/helm/helm_upgrade.md index df5bfe6ca..081123278 100644 --- a/docs/helm/helm_upgrade.md +++ b/docs/helm/helm_upgrade.md @@ -19,7 +19,7 @@ To customize the chart values, use any of - '--set-string' to provide key=val forcing val to be stored as a string, - '--set-file' to provide key=path to read a single large value from a file at path. -To edit or append to the existing customized values, add the +To edit or append to the existing customized values, add the '--reuse-values' flag, otherwise any existing customized values are ignored. If no chart value arguments are provided on the command line, any existing customized values are carried @@ -83,6 +83,7 @@ helm upgrade [RELEASE] [CHART] [flags] --repo string chart repository url where to locate the requested chart --reset-values when upgrading, reset the values to the ones built into the chart --reuse-values when upgrading, reuse the last release's values and merge in any overrides from the command line via --set and -f. If '--reset-values' is specified, this is ignored. + --safe if set, upgrade process rolls back changes made in case of failed upgrade --set stringArray set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) --set-file stringArray set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2) --set-string stringArray set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) @@ -116,4 +117,4 @@ helm upgrade [RELEASE] [CHART] [flags] * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 1-Nov-2018 +###### Auto generated by spf13/cobra on 9-Jan-2019 From e137c55a3ae58a4ef6770259d7cc2249fbf0c0a4 Mon Sep 17 00:00:00 2001 From: Alexander Nesterenko Date: Wed, 23 Jan 2019 17:24:51 +0200 Subject: [PATCH 063/146] [#3338] Rename "safe" to "atomic" which gives more clear understanding, what it does Signed-off-by: Alexander Nesterenko --- cmd/helm/install.go | 11 ++++++----- cmd/helm/upgrade.go | 12 ++++++------ docs/helm/helm_install.md | 4 ++-- docs/helm/helm_upgrade.md | 4 ++-- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/cmd/helm/install.go b/cmd/helm/install.go index 0316b14bf..a6d6b0812 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -131,7 +131,7 @@ type installCmd struct { version string timeout int64 wait bool - safe bool + atomic bool repoURL string username string password string @@ -191,7 +191,7 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command { } inst.chartPath = cp inst.client = ensureHelmClient(inst.client) - inst.wait = inst.wait || inst.safe + inst.wait = inst.wait || inst.atomic return inst.run() }, @@ -215,7 +215,7 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command { f.StringVar(&inst.version, "version", "", "specify the exact chart version to install. If this is not specified, the latest version is installed") f.Int64Var(&inst.timeout, "timeout", 300, "time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks)") f.BoolVar(&inst.wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment are in a ready state before marking the release as successful. It will wait for as long as --timeout") - f.BoolVar(&inst.safe, "safe", false, "if set, upgrade process rolls back changes made in case of failed upgrade") + f.BoolVar(&inst.atomic, "atomic", false, "if set, installation process purges chart on fail") f.StringVar(&inst.repoURL, "repo", "", "chart repository url where to locate the requested chart") f.StringVar(&inst.username, "username", "", "chart repository username where to locate the requested chart") f.StringVar(&inst.password, "password", "", "chart repository password where to locate the requested chart") @@ -311,8 +311,8 @@ func (i *installCmd) run() error { helm.InstallWait(i.wait), helm.InstallDescription(i.description)) if err != nil { - if i.safe { - fmt.Fprintf(os.Stdout, "INSTALL FAILED\nPURGING CHART\nError: %v", prettyError(err)) + if i.atomic { + fmt.Fprintf(os.Stdout, "INSTALL FAILED\nPURGING CHART\nError: %v\n", prettyError(err)) deleteSideEffects := &deleteCmd{ name: i.name, disableHooks: i.disableHooks, @@ -326,6 +326,7 @@ func (i *installCmd) run() error { if err := deleteSideEffects.run(); err != nil { return err } + fmt.Fprintf(os.Stdout, "Successfully purged a chart!\n") } return prettyError(err) } diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go index 527867e47..5184a97ff 100644 --- a/cmd/helm/upgrade.go +++ b/cmd/helm/upgrade.go @@ -44,7 +44,7 @@ To customize the chart values, use any of - '--set-string' to provide key=val forcing val to be stored as a string, - '--set-file' to provide key=path to read a single large value from a file at path. -To edit or append to the existing customized values, add the +To edit or append to the existing customized values, add the '--reuse-values' flag, otherwise any existing customized values are ignored. If no chart value arguments are provided on the command line, any existing customized values are carried @@ -105,7 +105,7 @@ type upgradeCmd struct { resetValues bool reuseValues bool wait bool - safe bool + atomic bool repoURL string username string password string @@ -143,7 +143,7 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command { upgrade.release = args[0] upgrade.chart = args[1] upgrade.client = ensureHelmClient(upgrade.client) - upgrade.wait = upgrade.wait || upgrade.safe + upgrade.wait = upgrade.wait || upgrade.atomic return upgrade.run() }, @@ -169,7 +169,7 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command { f.BoolVar(&upgrade.resetValues, "reset-values", false, "when upgrading, reset the values to the ones built into the chart") f.BoolVar(&upgrade.reuseValues, "reuse-values", false, "when upgrading, reuse the last release's values and merge in any overrides from the command line via --set and -f. If '--reset-values' is specified, this is ignored.") f.BoolVar(&upgrade.wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment are in a ready state before marking the release as successful. It will wait for as long as --timeout") - f.BoolVar(&upgrade.safe, "safe", false, "if set, upgrade process rolls back changes made in case of failed upgrade") + f.BoolVar(&upgrade.atomic, "atomic", false, "if set, upgrade process rolls back changes made in case of failed upgrade") f.StringVar(&upgrade.repoURL, "repo", "", "chart repository url where to locate the requested chart") f.StringVar(&upgrade.username, "username", "", "chart repository username where to locate the requested chart") f.StringVar(&upgrade.password, "password", "", "chart repository password where to locate the requested chart") @@ -236,7 +236,7 @@ func (u *upgradeCmd) run() error { timeout: u.timeout, wait: u.wait, description: u.description, - safe: u.safe, + atomic: u.atomic, } return ic.run() } @@ -276,7 +276,7 @@ func (u *upgradeCmd) run() error { helm.UpgradeDescription(u.description)) if err != nil { fmt.Fprintf(u.out, "UPGRADE FAILED\nROLLING BACK\nError: %v\n", prettyError(err)) - if u.safe { + if u.atomic { rollback := &rollbackCmd{ out: u.out, client: u.client, diff --git a/docs/helm/helm_install.md b/docs/helm/helm_install.md index 499e3222d..5d0130286 100644 --- a/docs/helm/helm_install.md +++ b/docs/helm/helm_install.md @@ -78,6 +78,7 @@ helm install [CHART] [flags] ### Options ``` + --atomic if set, upgrade process rolls back changes made in case of failed upgrade --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 @@ -96,7 +97,6 @@ helm install [CHART] [flags] --render-subchart-notes render subchart notes along with the parent --replace re-use the given name, even if that name is already used. This is unsafe in production --repo string chart repository url where to locate the requested chart - --safe if set, upgrade process rolls back changes made in case of failed upgrade --set stringArray set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) --set-file stringArray set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2) --set-string stringArray set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) @@ -130,4 +130,4 @@ helm install [CHART] [flags] * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 9-Jan-2019 +###### Auto generated by spf13/cobra on 23-Jan-2019 diff --git a/docs/helm/helm_upgrade.md b/docs/helm/helm_upgrade.md index 081123278..ac2ab316a 100644 --- a/docs/helm/helm_upgrade.md +++ b/docs/helm/helm_upgrade.md @@ -65,6 +65,7 @@ helm upgrade [RELEASE] [CHART] [flags] ### Options ``` + --atomic if set, upgrade process rolls back changes made in case of failed upgrade --ca-file string verify certificates of HTTPS-enabled servers using this CA bundle --cert-file string identify HTTPS client using this SSL certificate file --description string specify the description to use for the upgrade, rather than the default @@ -83,7 +84,6 @@ helm upgrade [RELEASE] [CHART] [flags] --repo string chart repository url where to locate the requested chart --reset-values when upgrading, reset the values to the ones built into the chart --reuse-values when upgrading, reuse the last release's values and merge in any overrides from the command line via --set and -f. If '--reset-values' is specified, this is ignored. - --safe if set, upgrade process rolls back changes made in case of failed upgrade --set stringArray set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) --set-file stringArray set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2) --set-string stringArray set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) @@ -117,4 +117,4 @@ helm upgrade [RELEASE] [CHART] [flags] * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 9-Jan-2019 +###### Auto generated by spf13/cobra on 23-Jan-2019 From 599bce8b13e5b11e931f8a0f106d4b9232be203c Mon Sep 17 00:00:00 2001 From: Alexander Nesterenko Date: Sun, 27 Jan 2019 11:22:36 +0200 Subject: [PATCH 064/146] Upgrade installation docs Signed-off-by: Alexander Nesterenko --- docs/helm/helm_install.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/helm/helm_install.md b/docs/helm/helm_install.md index 5d0130286..75a3c0502 100644 --- a/docs/helm/helm_install.md +++ b/docs/helm/helm_install.md @@ -78,7 +78,7 @@ helm install [CHART] [flags] ### Options ``` - --atomic if set, upgrade process rolls back changes made in case of failed upgrade + --atomic if set, installation process purges chart on fail --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 @@ -130,4 +130,4 @@ helm install [CHART] [flags] * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 23-Jan-2019 +###### Auto generated by spf13/cobra on 27-Jan-2019 From 5744af51e8abc402927c2196ea2a16833353037b Mon Sep 17 00:00:00 2001 From: Alexander Nesterenko Date: Sun, 27 Jan 2019 12:49:01 +0200 Subject: [PATCH 065/146] Add smoke tests Signed-off-by: Alexander Nesterenko --- cmd/helm/install_test.go | 8 ++++++++ cmd/helm/upgrade_test.go | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/cmd/helm/install_test.go b/cmd/helm/install_test.go index 5f7ffdb50..24a5abe68 100644 --- a/cmd/helm/install_test.go +++ b/cmd/helm/install_test.go @@ -113,6 +113,14 @@ func TestInstall(t *testing.T) { expected: "apollo", resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "apollo"}), }, + // Install, with atomic + { + name: "install with a atomic", + args: []string{"testdata/testcharts/alpine"}, + flags: strings.Split("--name apollo", " "), + expected: "apollo", + resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "apollo"}), + }, // Install, using the name-template { name: "install with name-template", diff --git a/cmd/helm/upgrade_test.go b/cmd/helm/upgrade_test.go index 60b529f63..c2b1b4ea6 100644 --- a/cmd/helm/upgrade_test.go +++ b/cmd/helm/upgrade_test.go @@ -123,6 +123,14 @@ func TestUpgradeCmd(t *testing.T) { 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 --atomic'", + args: []string{"funny-bunny", chartPath}, + flags: []string{"--atomic"}, + resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "funny-bunny", Version: 6, Chart: ch}), + expected: "Release \"funny-bunny\" has been upgraded. Happy Helming!\n", + rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "funny-bunny", Version: 6, Chart: ch})}, + }, { name: "install a release with 'upgrade --install'", args: []string{"zany-bunny", chartPath}, From 2332b480c9cb70a0d8a85247992d6155fbe82416 Mon Sep 17 00:00:00 2001 From: Alexander Nesterenko Date: Mon, 28 Jan 2019 20:06:31 +0200 Subject: [PATCH 066/146] Update docs to include information about setting `--wait flag` Signed-off-by: Alexander Nesterenko --- cmd/helm/install.go | 2 +- cmd/helm/upgrade.go | 2 +- docs/helm/helm_install.md | 4 ++-- docs/helm/helm_upgrade.md | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cmd/helm/install.go b/cmd/helm/install.go index a6d6b0812..4602ea9fd 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -215,7 +215,7 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command { f.StringVar(&inst.version, "version", "", "specify the exact chart version to install. If this is not specified, the latest version is installed") f.Int64Var(&inst.timeout, "timeout", 300, "time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks)") f.BoolVar(&inst.wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment are in a ready state before marking the release as successful. It will wait for as long as --timeout") - f.BoolVar(&inst.atomic, "atomic", false, "if set, installation process purges chart on fail") + f.BoolVar(&inst.atomic, "atomic", false, "if set, installation process purges chart on fail, also sets --wait flag") f.StringVar(&inst.repoURL, "repo", "", "chart repository url where to locate the requested chart") f.StringVar(&inst.username, "username", "", "chart repository username where to locate the requested chart") f.StringVar(&inst.password, "password", "", "chart repository password where to locate the requested chart") diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go index 5184a97ff..044ec045d 100644 --- a/cmd/helm/upgrade.go +++ b/cmd/helm/upgrade.go @@ -169,7 +169,7 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command { f.BoolVar(&upgrade.resetValues, "reset-values", false, "when upgrading, reset the values to the ones built into the chart") f.BoolVar(&upgrade.reuseValues, "reuse-values", false, "when upgrading, reuse the last release's values and merge in any overrides from the command line via --set and -f. If '--reset-values' is specified, this is ignored.") f.BoolVar(&upgrade.wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment are in a ready state before marking the release as successful. It will wait for as long as --timeout") - f.BoolVar(&upgrade.atomic, "atomic", false, "if set, upgrade process rolls back changes made in case of failed upgrade") + f.BoolVar(&upgrade.atomic, "atomic", false, "if set, upgrade process rolls back changes made in case of failed upgrade, also sets --wait flag") f.StringVar(&upgrade.repoURL, "repo", "", "chart repository url where to locate the requested chart") f.StringVar(&upgrade.username, "username", "", "chart repository username where to locate the requested chart") f.StringVar(&upgrade.password, "password", "", "chart repository password where to locate the requested chart") diff --git a/docs/helm/helm_install.md b/docs/helm/helm_install.md index 75a3c0502..12ae81b78 100644 --- a/docs/helm/helm_install.md +++ b/docs/helm/helm_install.md @@ -78,7 +78,7 @@ helm install [CHART] [flags] ### Options ``` - --atomic if set, installation process purges chart on fail + --atomic if set, installation process purges chart on fail, also sets --wait flag --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 @@ -130,4 +130,4 @@ helm install [CHART] [flags] * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 27-Jan-2019 +###### Auto generated by spf13/cobra on 28-Jan-2019 diff --git a/docs/helm/helm_upgrade.md b/docs/helm/helm_upgrade.md index ac2ab316a..676c26595 100644 --- a/docs/helm/helm_upgrade.md +++ b/docs/helm/helm_upgrade.md @@ -65,7 +65,7 @@ helm upgrade [RELEASE] [CHART] [flags] ### Options ``` - --atomic if set, upgrade process rolls back changes made in case of failed upgrade + --atomic if set, upgrade process rolls back changes made in case of failed upgrade, also sets --wait flag --ca-file string verify certificates of HTTPS-enabled servers using this CA bundle --cert-file string identify HTTPS client using this SSL certificate file --description string specify the description to use for the upgrade, rather than the default @@ -117,4 +117,4 @@ helm upgrade [RELEASE] [CHART] [flags] * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 23-Jan-2019 +###### Auto generated by spf13/cobra on 28-Jan-2019 From 074dbcde4f51473eab19dea5a0d843981bb2f72a Mon Sep 17 00:00:00 2001 From: Bort Verwilst Date: Tue, 29 Jan 2019 19:41:34 +0100 Subject: [PATCH 067/146] Switch to numeric user id (#5203) Signed-off-by: Bart Verwilst --- rootfs/Dockerfile | 2 +- rootfs/Dockerfile.experimental | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rootfs/Dockerfile b/rootfs/Dockerfile index 82dfa0d4c..f918c4d51 100644 --- a/rootfs/Dockerfile +++ b/rootfs/Dockerfile @@ -22,6 +22,6 @@ COPY helm /helm COPY tiller /tiller EXPOSE 44134 -USER nobody +USER 65534 ENTRYPOINT ["/tiller"] diff --git a/rootfs/Dockerfile.experimental b/rootfs/Dockerfile.experimental index ca0c87f30..61e49ab67 100644 --- a/rootfs/Dockerfile.experimental +++ b/rootfs/Dockerfile.experimental @@ -21,6 +21,6 @@ ENV HOME /tmp COPY tiller /tiller EXPOSE 44134 -USER nobody +USER 65534 ENTRYPOINT ["/tiller", "--experimental-release"] From 7871ea9f736d4ec02db6512b779089219c9f0e3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20K=C5=82opotek?= Date: Tue, 29 Jan 2019 19:43:38 +0100 Subject: [PATCH 068/146] Update documentation with option to install helm on Windows via scoop (#5207) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcin Kłopotek --- docs/install.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/install.md b/docs/install.md index b47aea6f1..b9626a43a 100755 --- a/docs/install.md +++ b/docs/install.md @@ -45,7 +45,7 @@ brew install kubernetes-helm (Note: There is also a formula for emacs-helm, which is a different project.) -### From Chocolatey (Windows) +### From Chocolatey or scoop (Windows) Members of the Kubernetes community have contributed a [Helm package](https://chocolatey.org/packages/kubernetes-helm) build to [Chocolatey](https://chocolatey.org/). This package is generally up to date. @@ -54,6 +54,12 @@ Members of the Kubernetes community have contributed a [Helm package](https://ch choco install kubernetes-helm ``` +The binary can also be installed via [`scoop`](https://scoop.sh) command-line installer. + +``` +scoop install helm +``` + ## From Script Helm now has an installer script that will automatically grab the latest version From a47a35814973bbaa7d37eec9fa5e30ac8c863daf Mon Sep 17 00:00:00 2001 From: Maor Friedman Date: Tue, 29 Jan 2019 10:44:25 -0800 Subject: [PATCH 069/146] [docs/related] add helm tiller-info plugin, related to #5111 (#5154) Signed-off-by: Maor --- docs/related.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/related.md b/docs/related.md index 5c027cc36..4fc4d9737 100644 --- a/docs/related.md +++ b/docs/related.md @@ -53,6 +53,7 @@ or [pull request](https://github.com/helm/helm/pulls). - [helm-stop](https://github.com/IBM/helm-stop) - Plugin for stopping a release pods - [helm-template](https://github.com/technosophos/helm-template) - Debug/render templates client-side - [helm-tiller](https://github.com/adamreese/helm-tiller) - Additional commands to work with Tiller +- [helm-tiller-info](https://github.com/maorfr/helm-tiller-info) - Plugin which prints information about Tiller - [helm-unittest](https://github.com/lrills/helm-unittest) - Plugin for unit testing chart locally with YAML - [Tillerless Helm v2](https://github.com/rimusz/helm-tiller) - Helm plugin for using Tiller locally and in CI/CD pipelines From f8ae371388df01aa770a4f6e9511fe92d0f1d770 Mon Sep 17 00:00:00 2001 From: Christian Hildebrando Hercules Date: Tue, 29 Jan 2019 10:54:02 -0800 Subject: [PATCH 070/146] Updating SAP example of gathering charts in one place (#5125) Signed-off-by: Christian H Hercules --- 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 e948d3bcf..9f9cc84a6 100644 --- a/docs/charts_tips_and_tricks.md +++ b/docs/charts_tips_and_tricks.md @@ -255,9 +255,9 @@ embed each of the components. Two strong design patterns are illustrated by these projects: -**SAP's [OpenStack chart](https://github.com/sapcc/openstack-helm):** This chart -installs a full OpenStack IaaS on Kubernetes. All of the charts are collected -together in one GitHub repository. +**SAP's [Converged charts](https://github.com/sapcc/helm-charts):** These charts +install SAP Converged Cloud a full OpenStack IaaS on Kubernetes. All of the charts are collected +together in one GitHub repository, except for a few submodules. **Deis's [Workflow](https://github.com/deis/workflow/tree/master/charts/workflow):** This chart exposes the entire Deis PaaS system with one chart. But it's different From 4c1edcf0492f7e6a315dbeced3c008e96a40bc47 Mon Sep 17 00:00:00 2001 From: Peter Stalman Date: Tue, 29 Jan 2019 10:54:51 -0800 Subject: [PATCH 071/146] Fixes #5046, zsh completion (#5072) Signed-off-by: Peter Stalman --- cmd/helm/completion.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/helm/completion.go b/cmd/helm/completion.go index 2181e723c..d0249b2ea 100644 --- a/cmd/helm/completion.go +++ b/cmd/helm/completion.go @@ -212,6 +212,7 @@ __helm_convert_bash_to_zsh() { -e "s/${LWORD}compopt${RWORD}/__helm_compopt/g" \ -e "s/${LWORD}declare${RWORD}/__helm_declare/g" \ -e "s/\\\$(type${RWORD}/\$(__helm_type/g" \ + -e 's/aliashash\["\(\w\+\)"\]/aliashash[\1]/g' \ <<'BASH_COMPLETION_EOF' ` out.Write([]byte(zshInitialization)) From 6ceaef446f70ac125b9a6d02b1a7a46956b104af Mon Sep 17 00:00:00 2001 From: Laski Date: Tue, 29 Jan 2019 16:15:38 -0300 Subject: [PATCH 072/146] Clarify section title (#5226) As stated by @schollii in https://github.com/helm/helm/issues/4505#issuecomment-415886732 "Overriding Values from a Parent Chart" is unclear. This changes that text to "Overriding Values of a Child Chart". See @scholli's comment for justification. Signed-off-by: Nahuel Lascano --- docs/chart_template_guide/subcharts_and_globals.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/chart_template_guide/subcharts_and_globals.md b/docs/chart_template_guide/subcharts_and_globals.md index 1954df39a..b37a82bca 100644 --- a/docs/chart_template_guide/subcharts_and_globals.md +++ b/docs/chart_template_guide/subcharts_and_globals.md @@ -63,7 +63,7 @@ data: dessert: cake ``` -## Overriding Values from a Parent Chart +## Overriding Values of a Child Chart Our original chart, `mychart` is now the _parent_ chart of `mysubchart`. This relationship is based entirely on the fact that `mysubchart` is within `mychart/charts`. From 5cf932c140fd5b3557d1c345aaa5168e58fd82b1 Mon Sep 17 00:00:00 2001 From: Amim Knabben Date: Tue, 29 Jan 2019 18:00:51 -0200 Subject: [PATCH 073/146] Changing deprecated library reference and setting delete propagation background policy (#5161) Signed-off-by: Amim Knabben --- cmd/helm/installer/uninstall.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cmd/helm/installer/uninstall.go b/cmd/helm/installer/uninstall.go index db824ca0b..87fbd4050 100644 --- a/cmd/helm/installer/uninstall.go +++ b/cmd/helm/installer/uninstall.go @@ -47,10 +47,11 @@ func deleteService(client corev1.ServicesGetter, namespace string) error { } // deleteDeployment deletes the Tiller Deployment resource -// We need to use the reaper instead of the kube API because GC for deployment dependents -// is not yet supported at the k8s server level (<= 1.5) func deleteDeployment(client kubernetes.Interface, namespace string) error { - err := client.Extensions().Deployments(namespace).Delete(deploymentName, &metav1.DeleteOptions{}) + policy := metav1.DeletePropagationBackground + err := client.AppsV1().Deployments(namespace).Delete(deploymentName, &metav1.DeleteOptions{ + PropagationPolicy: &policy, + }) return ingoreNotFound(err) } From ab0ba3aa630f64e0fd46cdd6726645a7e3520db9 Mon Sep 17 00:00:00 2001 From: James Ravn Date: Tue, 29 Jan 2019 20:04:17 +0000 Subject: [PATCH 074/146] fix(tiller): respect resource policy on upgrade (#5225) Don't delete a resource on upgrade if it is annotated with helm.io/resource-policy=keep. This can cause data loss for users if the annotation is ignored (e.g. for a PVC). Closes #3673 Signed-off-by: James Ravn --- pkg/kube/client.go | 18 +++++++++++++++++- pkg/kube/client_test.go | 15 +++++++++++++++ pkg/kube/resource_policy.go | 26 ++++++++++++++++++++++++++ pkg/tiller/resource_policy.go | 13 ++----------- 4 files changed, 60 insertions(+), 12 deletions(-) create mode 100644 pkg/kube/resource_policy.go diff --git a/pkg/kube/client.go b/pkg/kube/client.go index 4a387d524..e897aced6 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -23,11 +23,12 @@ import ( goerrors "errors" "fmt" "io" + "k8s.io/apimachinery/pkg/api/meta" "log" "strings" "time" - jsonpatch "github.com/evanphx/json-patch" + "github.com/evanphx/json-patch" appsv1 "k8s.io/api/apps/v1" appsv1beta1 "k8s.io/api/apps/v1beta1" appsv1beta2 "k8s.io/api/apps/v1beta2" @@ -60,6 +61,8 @@ const 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") +var metadataAccessor = meta.NewAccessor() + // Client represents a client capable of communicating with the Kubernetes API. type Client struct { cmdutil.Factory @@ -308,6 +311,19 @@ func (c *Client) Update(namespace string, originalReader, targetReader io.Reader for _, info := range original.Difference(target) { c.Log("Deleting %q in %s...", info.Name, info.Namespace) + + if err := info.Get(); err != nil { + c.Log("Unable to get obj %q, err: %s", info.Name, err) + } + annotations, err := metadataAccessor.Annotations(info.Object) + if err != nil { + c.Log("Unable to get annotations on %q, err: %s", info.Name, err) + } + if annotations != nil && annotations[ResourcePolicyAnno] == KeepPolicy { + c.Log("Skipping delete of %q due to annotation [%s=%s]", info.Name, ResourcePolicyAnno, KeepPolicy) + continue + } + if err := deleteResource(info); err != nil { c.Log("Failed to delete %q, err: %s", info.Name, err) } diff --git a/pkg/kube/client_test.go b/pkg/kube/client_test.go index de33881c8..aa21b937c 100644 --- a/pkg/kube/client_test.go +++ b/pkg/kube/client_test.go @@ -151,6 +151,8 @@ func TestUpdate(t *testing.T) { return newResponse(200, &listB.Items[1]) case p == "/namespaces/default/pods/squid" && m == "DELETE": return newResponse(200, &listB.Items[1]) + case p == "/namespaces/default/pods/squid" && m == "GET": + return newResponse(200, &listA.Items[2]) default: t.Fatalf("unexpected request: %s %s", req.Method, req.URL.Path) return nil, nil @@ -183,6 +185,7 @@ func TestUpdate(t *testing.T) { "/namespaces/default/pods/otter:GET", "/namespaces/default/pods/dolphin:GET", "/namespaces/default/pods:POST", + "/namespaces/default/pods/squid:GET", "/namespaces/default/pods/squid:DELETE", } if len(expectedActions) != len(actions) { @@ -194,6 +197,18 @@ func TestUpdate(t *testing.T) { t.Errorf("expected %s request got %s", v, actions[k]) } } + + // Test resource policy is respected + actions = nil + listA.Items[2].ObjectMeta.Annotations = map[string]string{ResourcePolicyAnno: KeepPolicy} + if err := c.Update(v1.NamespaceDefault, objBody(&listA), objBody(&listB), false, false, 0, false); err != nil { + t.Fatal(err) + } + for _, v := range actions { + if v == "/namespaces/default/pods/squid:DELETE" { + t.Errorf("should not have deleted squid - it has helm.sh/resource-policy=keep") + } + } } func TestBuild(t *testing.T) { diff --git a/pkg/kube/resource_policy.go b/pkg/kube/resource_policy.go new file mode 100644 index 000000000..45cebcba8 --- /dev/null +++ b/pkg/kube/resource_policy.go @@ -0,0 +1,26 @@ +/* +Copyright The Helm Authors. + +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 kube + +// ResourcePolicyAnno is the annotation name for a resource policy +const ResourcePolicyAnno = "helm.sh/resource-policy" + +// KeepPolicy is the resource policy type for keep +// +// This resource policy type allows resources to skip being deleted +// during an uninstallRelease action. +const KeepPolicy = "keep" diff --git a/pkg/tiller/resource_policy.go b/pkg/tiller/resource_policy.go index cca2391d8..aa9c5d2bd 100644 --- a/pkg/tiller/resource_policy.go +++ b/pkg/tiller/resource_policy.go @@ -24,15 +24,6 @@ import ( "k8s.io/helm/pkg/tiller/environment" ) -// resourcePolicyAnno is the annotation name for a resource policy -const resourcePolicyAnno = "helm.sh/resource-policy" - -// keepPolicy is the resource policy type for keep -// -// This resource policy type allows resources to skip being deleted -// during an uninstallRelease action. -const keepPolicy = "keep" - func filterManifestsToKeep(manifests []Manifest) ([]Manifest, []Manifest) { remaining := []Manifest{} keep := []Manifest{} @@ -43,14 +34,14 @@ func filterManifestsToKeep(manifests []Manifest) ([]Manifest, []Manifest) { continue } - resourcePolicyType, ok := m.Head.Metadata.Annotations[resourcePolicyAnno] + resourcePolicyType, ok := m.Head.Metadata.Annotations[kube.ResourcePolicyAnno] if !ok { remaining = append(remaining, m) continue } resourcePolicyType = strings.ToLower(strings.TrimSpace(resourcePolicyType)) - if resourcePolicyType == keepPolicy { + if resourcePolicyType == kube.KeepPolicy { keep = append(keep, m) } From 51a7a4487b28a359738ac6b3135f6fbe7a0d95d6 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Tue, 29 Jan 2019 12:34:33 -0800 Subject: [PATCH 075/146] docs: add note on rolling back to the previous release (#5228) While deving at a Microsoft Open Hack my group discovered this useful piece of information in this issue comment: https://github.com/helm/helm/issues/1796#issuecomment-311385728 We found it very useful for our Blue Green CD pipeline and thought others might find it useful as well. Signed-off-by: Ethan Arrowood Signed-off-by: Matthew Fisher --- cmd/helm/rollback.go | 3 ++- docs/helm/helm_rollback.md | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/cmd/helm/rollback.go b/cmd/helm/rollback.go index 0c46fa818..78d79659d 100644 --- a/cmd/helm/rollback.go +++ b/cmd/helm/rollback.go @@ -31,7 +31,8 @@ This command rolls back a release to a previous revision. The first argument of the rollback command is the name of a release, and the second is a revision (version) number. To see revision numbers, run -'helm history RELEASE'. +'helm history RELEASE'. If you'd like to rollback to the previous release use +'helm rollback [RELEASE] 0'. ` type rollbackCmd struct { diff --git a/docs/helm/helm_rollback.md b/docs/helm/helm_rollback.md index 5862b180a..80fc83a83 100644 --- a/docs/helm/helm_rollback.md +++ b/docs/helm/helm_rollback.md @@ -9,7 +9,8 @@ This command rolls back a release to a previous revision. The first argument of the rollback command is the name of a release, and the second is a revision (version) number. To see revision numbers, run -'helm history RELEASE'. +'helm history RELEASE'. If you'd like to rollback to the previous release use +'helm rollback [RELEASE] 0'. ``` @@ -51,4 +52,4 @@ helm rollback [flags] [RELEASE] [REVISION] * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 10-Aug-2018 +###### Auto generated by spf13/cobra on 29-Jan-2019 From 9596dc768ad4b44aa3f6772a64912f8d04c4ea44 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Tue, 29 Jan 2019 12:35:44 -0800 Subject: [PATCH 076/146] add missing "and" (#5227) Signed-off-by: Matthew Fisher --- docs/chart_template_guide/variables.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/docs/chart_template_guide/variables.md b/docs/chart_template_guide/variables.md index d924fe2cf..dda92559b 100644 --- a/docs/chart_template_guide/variables.md +++ b/docs/chart_template_guide/variables.md @@ -98,10 +98,7 @@ data: 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. +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 and need to know the chart's release name. An example illustrating this: ```yaml @@ -111,8 +108,8 @@ 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.kubernetes.io/name: {{ template "fullname" $ }} # I cannot reference .Chart.Name, but I can do $.Chart.Name helm.sh/chart: "{{ $.Chart.Name }}-{{ $.Chart.Version }}" From 36d2c716b3194cceb4b22f32259990a04014b5f5 Mon Sep 17 00:00:00 2001 From: Patrick Stegmann Date: Wed, 30 Jan 2019 00:21:47 +0100 Subject: [PATCH 077/146] Adds the tip that you can pass custom objects (#3916) --- docs/charts_tips_and_tricks.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/charts_tips_and_tricks.md b/docs/charts_tips_and_tricks.md index 9f9cc84a6..e2c73b14f 100644 --- a/docs/charts_tips_and_tricks.md +++ b/docs/charts_tips_and_tricks.md @@ -36,6 +36,12 @@ is required, and will print an error message when that entry is missing: value: {{ required "A valid .Values.who entry required!" .Values.who }} ``` +When using the `include` function, you can pass it a custom object tree built from the current context by using the `dict` function: + +```yaml +{{- include "mytpl" (dict "key1" .Values.originalKey1 "key2" .Values.originalKey2) }} +``` + ## Quote Strings, Don't Quote Integers When you are working with string data, you are always safer quoting the From abd3659b649d6a463c5cd6c6aefd265590a138e2 Mon Sep 17 00:00:00 2001 From: "Pablo M. Canseco" Date: Tue, 29 Jan 2019 22:03:30 -0700 Subject: [PATCH 078/146] Update using_helm.md (#4690) * Update using_helm.md In docs/using_helm.md, it says on line 214 that you can pass in a YAML formatted file, but the example commands following that sentence create JSON code but names the file with a .yml extension. For clarity, I propose saying that it will accept JSON or YAML but clarify in the code that for the example we're making a JSON file. Signed-off-by: Pablo Canseco * update using_helm.md to accurately say that helm install -f only takes a yaml-formatted file. Signed-off-by: Pablo Canseco * updated wording to reflect the fact that -f / --values only accepts YAML Signed-off-by: Pablo Canseco --- docs/using_helm.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/using_helm.md b/docs/using_helm.md index 5716a1302..db723d993 100755 --- a/docs/using_helm.md +++ b/docs/using_helm.md @@ -1,4 +1,4 @@ -# Using Helm +# Using Helm This guide explains the basics of using Helm (and Tiller) to manage packages on your Kubernetes cluster. It assumes that you have already @@ -215,7 +215,10 @@ You can then override any of these settings in a YAML formatted file, and then pass that file during installation. ```console -$ echo '{mariadbUser: user0, mariadbDatabase: user0db}' > config.yaml +$ cat << EOF > config.yaml +mariadbUser: user0 +mariadbDatabase: user0db +EOF $ helm install -f config.yaml stable/mariadb ``` From 048b220205c581378b393155896ca5e862ee0480 Mon Sep 17 00:00:00 2001 From: Jacob Silva Date: Wed, 30 Jan 2019 01:11:07 -0500 Subject: [PATCH 079/146] Removed link for Cabin mobile app (#5231) Signed-off-by: Jacob Silva --- docs/related.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/related.md b/docs/related.md index 4fc4d9737..ba1b0dfbf 100644 --- a/docs/related.md +++ b/docs/related.md @@ -89,7 +89,6 @@ Tools layered on top of Helm or Tiller. Platforms, distributions, and services that include Helm support. -- [Cabin](http://www.skippbox.com/cabin/) - Mobile App for Managing Kubernetes - [Fabric8](https://fabric8.io) - Integrated development platform for Kubernetes - [Jenkins X](http://jenkins-x.io/) - open source automated CI/CD for Kubernetes which uses Helm for [promoting](http://jenkins-x.io/about/features/#promotion) applications through [environments via GitOps](http://jenkins-x.io/about/features/#environments) - [Kubernetic](https://kubernetic.com/) - Kubernetes Desktop Client From a2b1afc66bfc2b3d0a876ef7a2a25f38f12c1415 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20K=C5=82opotek?= Date: Wed, 30 Jan 2019 16:06:24 +0100 Subject: [PATCH 080/146] Update README with scoop install option (#5234) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcin Kłopotek --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 7e68df5c3..1889e818e 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ If you want to use a package manager: - [Homebrew](https://brew.sh/) users can use `brew install kubernetes-helm`. - [Chocolatey](https://chocolatey.org/) users can use `choco install kubernetes-helm`. +- [Scoop](https://scoop.sh/) users can use `scoop install helm`. - [GoFish](https://gofi.sh/) users can use `gofish install helm`. To rapidly get Helm up and running, start with the [Quick Start Guide](https://docs.helm.sh/using_helm/#quickstart-guide). From 7161095f79e2c9a35350d301ad820e57e56182ec Mon Sep 17 00:00:00 2001 From: lIuDuI <1693291525@qq.com> Date: Thu, 31 Jan 2019 12:10:26 +0800 Subject: [PATCH 081/146] Update func name (#5241) Signed-off-by: xichengliudui <1693291525@qq.com> --- cmd/helm/installer/install.go | 2 +- cmd/helm/installer/options.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/helm/installer/install.go b/cmd/helm/installer/install.go index 6027fdba8..d6d24eec4 100644 --- a/cmd/helm/installer/install.go +++ b/cmd/helm/installer/install.go @@ -183,7 +183,7 @@ func generateLabels(labels map[string]string) map[string]string { return labels } -// parseNodeSelectors parses a comma delimited list of key=values pairs into a map. +// parseNodeSelectorsInto 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 { diff --git a/cmd/helm/installer/options.go b/cmd/helm/installer/options.go index 196ad8de4..dbcb376c5 100644 --- a/cmd/helm/installer/options.go +++ b/cmd/helm/installer/options.go @@ -50,7 +50,7 @@ type Options struct { // AutoMountServiceAccountToken determines whether or not the service account should be added to Tiller. AutoMountServiceAccountToken bool - // Force allows to force upgrading tiller if deployed version is greater than current version + // ForceUpgrade allows to force upgrading tiller if deployed version is greater than current version ForceUpgrade bool // ImageSpec identifies the image Tiller will use when deployed. From 251a6a2b580158b5dfb34e8b08b10071e6353c1a Mon Sep 17 00:00:00 2001 From: Dean Coakley Date: Fri, 1 Feb 2019 05:32:40 +0000 Subject: [PATCH 082/146] Fix code syntax highlighting in docs (#5245) * Added yaml to undelcared code blocks * Changed YAML->yaml for consistency * Added console syntax highlighting Signed-off-by: Dean Coakley --- docs/chart_template_guide/control_structures.md | 6 +++--- docs/chart_template_guide/debugging.md | 4 ++-- docs/chart_template_guide/functions_and_pipelines.md | 4 ++-- docs/chart_template_guide/values_files.md | 4 ++-- docs/chart_template_guide/yaml_techniques.md | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/chart_template_guide/control_structures.md b/docs/chart_template_guide/control_structures.md index 61d9ef9e2..68820dfa7 100644 --- a/docs/chart_template_guide/control_structures.md +++ b/docs/chart_template_guide/control_structures.md @@ -20,7 +20,7 @@ The first control structure we'll look at is for conditionally including blocks The basic structure for a conditional looks like this: -``` +```yaml {{ if PIPELINE }} # Do something {{ else if OTHER PIPELINE }} @@ -115,7 +115,7 @@ data: `mug` is incorrectly indented. Let's simply out-dent that one line, and re-run: -``` +```yaml apiVersion: v1 kind: ConfigMap metadata: @@ -224,7 +224,7 @@ The next control structure to look at is the `with` action. This controls variab The syntax for `with` is similar to a simple `if` statement: -``` +```yaml {{ with PIPELINE }} # restricted scope {{ end }} diff --git a/docs/chart_template_guide/debugging.md b/docs/chart_template_guide/debugging.md index fac788cc4..23a6ae70b 100644 --- a/docs/chart_template_guide/debugging.md +++ b/docs/chart_template_guide/debugging.md @@ -12,7 +12,7 @@ When your YAML is failing to parse, but you want to see what is generated, one easy way to retrieve the YAML is to comment out the problem section in the template, and then re-run `helm install --dry-run --debug`: -```YAML +```yaml apiVersion: v1 # some: problem section # {{ .Values.foo | quote }} @@ -20,7 +20,7 @@ apiVersion: v1 The above will be rendered and returned with the comments intact: -```YAML +```yaml apiVersion: v1 # some: problem section # "bar" diff --git a/docs/chart_template_guide/functions_and_pipelines.md b/docs/chart_template_guide/functions_and_pipelines.md index 66176fc59..fe9c92d6e 100644 --- a/docs/chart_template_guide/functions_and_pipelines.md +++ b/docs/chart_template_guide/functions_and_pipelines.md @@ -4,7 +4,7 @@ So far, we've seen how to place information into a template. But that informatio Let's start with a best practice: When injecting strings from the `.Values` object into the template, we ought to quote these strings. We can do that by calling the `quote` function in the template directive: -``` +```yaml apiVersion: v1 kind: ConfigMap metadata: @@ -104,7 +104,7 @@ drink: {{ .Values.favorite.drink | default "tea" | quote }} If we run this as normal, we'll get our `coffee`: -``` +```yaml # Source: mychart/templates/configmap.yaml apiVersion: v1 kind: ConfigMap diff --git a/docs/chart_template_guide/values_files.md b/docs/chart_template_guide/values_files.md index a15047667..218da19dc 100644 --- a/docs/chart_template_guide/values_files.md +++ b/docs/chart_template_guide/values_files.md @@ -54,7 +54,7 @@ data: Because `favoriteDrink` is set in the default `values.yaml` file to `coffee`, that's the value displayed in the template. We can easily override that by adding a `--set` flag in our call to `helm install`: -``` +```console helm install --dry-run --debug --set favoriteDrink=slurm ./mychart SERVER: "localhost:44134" CHART PATH: /Users/mattbutcher/Code/Go/src/k8s.io/helm/_scratch/mychart @@ -85,7 +85,7 @@ favorite: Now we would have to modify the template slightly: -``` +```yaml apiVersion: v1 kind: ConfigMap metadata: diff --git a/docs/chart_template_guide/yaml_techniques.md b/docs/chart_template_guide/yaml_techniques.md index 44c41f903..00b33b674 100644 --- a/docs/chart_template_guide/yaml_techniques.md +++ b/docs/chart_template_guide/yaml_techniques.md @@ -177,7 +177,7 @@ Now the value of `coffee` will be `Latte\nCappuccino\nEspresso\n\n\n`. Indentation inside of a text block is preserved, and results in the preservation of line breaks, too: -``` +```yaml coffee: |- Latte 12 oz @@ -336,7 +336,7 @@ reference is expanded and then discarded. So if we were to decode and then re-encode the example above, the resulting YAML would be: -```YAML +```yaml coffee: yes, please favorite: Cappucino coffees: From 9e18364fea6cc8a2cd97a2fa1b40650583b1eeff Mon Sep 17 00:00:00 2001 From: JoeWrightss <42261994+JoeWrightss@users.noreply.github.com> Date: Fri, 1 Feb 2019 13:33:04 +0800 Subject: [PATCH 083/146] Fix some spelling errors in comment (#5246) Signed-off-by: zhoulin xie --- pkg/repo/repotest/server.go | 2 +- pkg/storage/driver/secrets.go | 2 +- pkg/tiller/release_list.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/repo/repotest/server.go b/pkg/repo/repotest/server.go index 36ab10d70..394294bcd 100644 --- a/pkg/repo/repotest/server.go +++ b/pkg/repo/repotest/server.go @@ -148,7 +148,7 @@ func (s *Server) URL() string { return s.srv.URL } -// LinkIndices links the index created with CreateIndex and makes a symboic link to the repositories/cache directory. +// LinkIndices links the index created with CreateIndex and makes a symbolic link to the repositories/cache directory. // // This makes it possible to simulate a local cache of a repository. func (s *Server) LinkIndices() error { diff --git a/pkg/storage/driver/secrets.go b/pkg/storage/driver/secrets.go index b79a84272..606d7960b 100644 --- a/pkg/storage/driver/secrets.go +++ b/pkg/storage/driver/secrets.go @@ -45,7 +45,7 @@ type Secrets struct { Log func(string, ...interface{}) } -// NewSecrets initializes a new Secrets wrapping an implmenetation of +// NewSecrets initializes a new Secrets wrapping an implementation of // the kubernetes SecretsInterface. func NewSecrets(impl corev1.SecretInterface) *Secrets { return &Secrets{ diff --git a/pkg/tiller/release_list.go b/pkg/tiller/release_list.go index 3299d3ef2..6d62c7bc4 100644 --- a/pkg/tiller/release_list.go +++ b/pkg/tiller/release_list.go @@ -140,7 +140,7 @@ func (s *ReleaseServer) partition(rels []*release.Release, cap int) <-chan []*re // Over-cap, push chunk onto channel to send over gRPC stream s.Log("partitioned at %d with %d releases (cap=%d)", fill, len(chunk), cap) chunks <- chunk - // reset paritioning state + // reset partitioning state chunk = nil fill = 0 } From 147dc225e2a0cc7f5e08a46ea9b59a1d78217f1c Mon Sep 17 00:00:00 2001 From: lIuDuI <1693291525@qq.com> Date: Fri, 1 Feb 2019 22:33:59 +0800 Subject: [PATCH 084/146] Update func name (#5250) * Update func name Signed-off-by: xichengliudui <1693291525@qq.com> * update pull request Signed-off-by: xichengliudui <1693291525@qq.com> --- pkg/tiller/environment/environment.go | 2 +- pkg/tiller/release_server.go | 2 +- pkg/urlutil/urlutil.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/tiller/environment/environment.go b/pkg/tiller/environment/environment.go index 86d077b89..290337d7b 100644 --- a/pkg/tiller/environment/environment.go +++ b/pkg/tiller/environment/environment.go @@ -119,7 +119,7 @@ type KubeClient interface { // by "\n---\n"). Delete(namespace string, reader io.Reader) error - // Watch the resource in reader until it is "ready". + // WatchUntilReady watch the resource in reader until it is "ready". // // For Jobs, "ready" means the job ran to completion (excited without error). // For all other kinds, it means the kind was created or modified without diff --git a/pkg/tiller/release_server.go b/pkg/tiller/release_server.go index 680c39dac..b85118cd2 100644 --- a/pkg/tiller/release_server.go +++ b/pkg/tiller/release_server.go @@ -456,7 +456,7 @@ func (s *ReleaseServer) deleteHookByPolicy(h *release.Hook, policy string, name, return nil } -// hookShouldBeDeleted determines whether the defined hook deletion policy matches the hook deletion polices +// hookHasDeletePolicy determines whether the defined hook deletion policy matches the hook deletion polices // supported by helm. If so, mark the hook as one should be deleted. func hookHasDeletePolicy(h *release.Hook, policy string) bool { if dp, ok := deletePolices[policy]; ok { diff --git a/pkg/urlutil/urlutil.go b/pkg/urlutil/urlutil.go index 272907de0..96b691c92 100644 --- a/pkg/urlutil/urlutil.go +++ b/pkg/urlutil/urlutil.go @@ -73,7 +73,7 @@ func ExtractHostname(addr string) (string, error) { return stripPort(u.Host), nil } -// Backported from Go 1.8 because Circle is still on 1.7 +// stripPort from Go 1.8 because Circle is still on 1.7 func stripPort(hostport string) string { colon := strings.IndexByte(hostport, ':') if colon == -1 { From d3373f568c63e48c3af3b181bca81ca61967e289 Mon Sep 17 00:00:00 2001 From: ahmadali shafiee Date: Fri, 1 Feb 2019 19:38:28 +0330 Subject: [PATCH 085/146] making ingress path configurations more customizable (#5175) * making ingress path configurations more customizable Signed-off-by: Ahmadali Shafiee * update notes ingress reference Signed-off-by: Ahmadali Shafiee --- pkg/chartutil/create.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pkg/chartutil/create.go b/pkg/chartutil/create.go index 8f713fcd1..9af4b8f45 100644 --- a/pkg/chartutil/create.go +++ b/pkg/chartutil/create.go @@ -75,9 +75,10 @@ ingress: annotations: {} # kubernetes.io/ingress.class: nginx # kubernetes.io/tls-acme: "true" - paths: [] hosts: - - chart-example.local + - host: chart-example.local + paths: [] + tls: [] # - secretName: chart-example-tls # hosts: @@ -128,7 +129,6 @@ const defaultIgnore = `# Patterns to ignore when building packages. const defaultIngress = `{{- if .Values.ingress.enabled -}} {{- $fullName := include ".fullname" . -}} -{{- $ingressPaths := .Values.ingress.paths -}} apiVersion: extensions/v1beta1 kind: Ingress metadata: @@ -155,10 +155,10 @@ spec: {{- end }} rules: {{- range .Values.ingress.hosts }} - - host: {{ . | quote }} + - host: {{ .host | quote }} http: paths: - {{- range $ingressPaths }} + {{- range .paths }} - path: {{ . }} backend: serviceName: {{ $fullName }} @@ -245,8 +245,8 @@ spec: const defaultNotes = `1. Get the application URL by running these commands: {{- if .Values.ingress.enabled }} {{- range $host := .Values.ingress.hosts }} - {{- range $.Values.ingress.paths }} - http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host }}{{ . }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} {{- end }} {{- end }} {{- else if contains "NodePort" .Values.service.type }} From 69c7ba320e041894c073f7f62a98075b72c6bfd8 Mon Sep 17 00:00:00 2001 From: Flavian Date: Fri, 1 Feb 2019 17:12:46 +0100 Subject: [PATCH 086/146] Fix: type conversion for zero values (#5151) * added test for zero values Signed-off-by: Flavian * implemented case for zero values Signed-off-by: Flavian --- pkg/strvals/parser.go | 4 ++++ pkg/strvals/parser_test.go | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/pkg/strvals/parser.go b/pkg/strvals/parser.go index 9d52f34c0..d0a647c67 100644 --- a/pkg/strvals/parser.go +++ b/pkg/strvals/parser.go @@ -393,6 +393,10 @@ func typedVal(v []rune, st bool) interface{} { return nil } + if strings.EqualFold(val, "0") { + return int64(0) + } + // If this value does not start with zero, try parsing it to an int if len(val) != 0 && val[0] != '0' { if iv, err := strconv.ParseInt(val, 10, 64); err == nil { diff --git a/pkg/strvals/parser_test.go b/pkg/strvals/parser_test.go index a096f16d2..5d77aed18 100644 --- a/pkg/strvals/parser_test.go +++ b/pkg/strvals/parser_test.go @@ -85,6 +85,11 @@ func TestParseSet(t *testing.T) { expect: map[string]interface{}{"is_null": "null"}, err: false, }, + { + str: "zero=0", + expect: map[string]interface{}{"zero": "0"}, + err: false, + }, } tests := []struct { str string @@ -123,6 +128,10 @@ func TestParseSet(t *testing.T) { str: "leading_zeros=00009", expect: map[string]interface{}{"leading_zeros": "00009"}, }, + { + str: "zero_int=0", + expect: map[string]interface{}{"zero_int": 0}, + }, { str: "long_int=1234567890", expect: map[string]interface{}{"long_int": 1234567890}, From 7a70459ca1913fcffeb374eca4446c5f97427da9 Mon Sep 17 00:00:00 2001 From: Alex Speaks Date: Fri, 1 Feb 2019 08:18:10 -0800 Subject: [PATCH 087/146] Fix incorrect flow example and improve operator documentation (#4919) * Fix incorrect flow example and improve operator documentation Signed-off-by: Alex * Use golang comment format Signed-off-by: Alex --- docs/chart_template_guide/control_structures.md | 2 +- .../functions_and_pipelines.md | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/docs/chart_template_guide/control_structures.md b/docs/chart_template_guide/control_structures.md index 68820dfa7..e2f9ca89d 100644 --- a/docs/chart_template_guide/control_structures.md +++ b/docs/chart_template_guide/control_structures.md @@ -53,7 +53,7 @@ data: myvalue: "Hello World" drink: {{ .Values.favorite.drink | default "tea" | quote }} food: {{ .Values.favorite.food | upper | quote }} - {{ if and (.Values.favorite.drink) (eq .Values.favorite.drink "coffee") }}mug: true{{ end }} + {{ if and .Values.favorite.drink (eq .Values.favorite.drink "coffee") }}mug: true{{ end }} ``` Note that `.Values.favorite.drink` must be defined or else it will throw an error when comparing it to "coffee". Since we commented out `drink: coffee` in our last example, the output should not include a `mug: true` flag. But if we add that line back into our `values.yaml` file, the output should look like this: diff --git a/docs/chart_template_guide/functions_and_pipelines.md b/docs/chart_template_guide/functions_and_pipelines.md index fe9c92d6e..fe5a3c2b2 100644 --- a/docs/chart_template_guide/functions_and_pipelines.md +++ b/docs/chart_template_guide/functions_and_pipelines.md @@ -150,6 +150,19 @@ Template functions and pipelines are a powerful way to transform information and ## Operators are functions -For templates, the operators (`eq`, `ne`, `lt`, `gt`, `and`, `or` and so on) are all implemented as functions. In pipelines, operations can be grouped with parentheses (`(`, and `)`). +Operators are implemented as functions that return a boolean value. To use `eq`, `ne`, `lt`, `gt`, `and`, `or`, `not` etcetera place the operator at the front of the statement followed by its parameters just as you would a function. To chain multiple operations together, separate individual functions by surrounding them with paranthesis. + +```yaml +{{/* include the body of this if statement when the variable .Values.fooString exists and is set to "foo" */}} +{{ if and .Values.fooString (eq .Values.fooString "foo") }} + {{ ... }} +{{ end }} + + +{{/* do not include the body of this if statement because unset variables evaluate to false and .Values.setVariable was negated with the not function. */}} +{{ if or .Values.anUnsetVariable (not .Values.aSetVariable) }} + {{ ... }} +{{ end }} +``` Now we can turn from functions and pipelines to flow control with conditions, loops, and scope modifiers. From c9dfd2507129fa392e9c8b57ade7e2dbb33b063c Mon Sep 17 00:00:00 2001 From: Ryan Hartje Date: Fri, 1 Feb 2019 10:45:54 -0600 Subject: [PATCH 088/146] added warning and set default image for unreleased versions of helm for #3770 (#3781) * added warning and set default image for unreleased versions of helm * changed to BuildMetadata * changed to BuildMetadata * added check for clientOnly flag --- cmd/helm/init.go | 9 +++++++++ cmd/helm/installer/install_test.go | 4 ++++ cmd/helm/installer/options.go | 3 +++ 3 files changed, 16 insertions(+) diff --git a/cmd/helm/init.go b/cmd/helm/init.go index b628dc008..db35ef037 100644 --- a/cmd/helm/init.go +++ b/cmd/helm/init.go @@ -36,6 +36,7 @@ import ( "k8s.io/helm/pkg/helm/helmpath" "k8s.io/helm/pkg/helm/portforwarder" "k8s.io/helm/pkg/repo" + "k8s.io/helm/pkg/version" ) const initDesc = ` @@ -315,6 +316,14 @@ func (i *initCmd) run() error { fmt.Fprintln(i.out, "Not installing Tiller due to 'client-only' flag having been set") } + needsDefaultImage := !i.clientOnly && !i.opts.UseCanary && len(i.opts.ImageSpec) == 0 && version.BuildMetadata == "unreleased" + if needsDefaultImage { + fmt.Fprintf(i.out, "\nWarning: You appear to be using an unreleased version of Helm. Please either use the\n"+ + "--canary-image flag, or specify your desired tiller version with --tiller-image.\n\n"+ + "Ex:\n"+ + "$ helm init --tiller-image gcr.io/kubernetes-helm/tiller:v2.8.2\n\n") + } + fmt.Fprintln(i.out, "Happy Helming!") return nil } diff --git a/cmd/helm/installer/install_test.go b/cmd/helm/installer/install_test.go index 561b3ed6d..50cc8b1d8 100644 --- a/cmd/helm/installer/install_test.go +++ b/cmd/helm/installer/install_test.go @@ -53,6 +53,10 @@ func TestDeployment(t *testing.T) { t.Fatalf("%s: error %q", tt.name, err) } + // Unreleased versions of helm don't have a release image. See issue 3370 + if tt.name == "default" && version.BuildMetadata == "unreleased" { + tt.expect = "gcr.io/kubernetes-helm/tiller:canary" + } if got := dep.Spec.Template.Spec.Containers[0].Image; got != tt.expect { t.Errorf("%s: expected image %q, got %q", tt.name, tt.expect, got) } diff --git a/cmd/helm/installer/options.go b/cmd/helm/installer/options.go index dbcb376c5..186286ec2 100644 --- a/cmd/helm/installer/options.go +++ b/cmd/helm/installer/options.go @@ -105,6 +105,9 @@ func (opts *Options) SelectImage() string { case opts.UseCanary: return defaultImage + ":canary" case opts.ImageSpec == "": + if version.BuildMetadata == "unreleased" { + return defaultImage + ":canary" + } return fmt.Sprintf("%s:%s", defaultImage, version.Version) default: return opts.ImageSpec From f5df47b1c855e02c66f57756af224bc9b1055b09 Mon Sep 17 00:00:00 2001 From: Alexander Matyushentsev Date: Fri, 1 Feb 2019 09:02:06 -0800 Subject: [PATCH 089/146] Fix: kind sorter incorrectly compares unknown and namespace (#5186) Signed-off-by: Alexander Matyushentsev --- pkg/tiller/kind_sorter.go | 17 ++++++++++++----- pkg/tiller/kind_sorter_test.go | 21 +++++++++++++++++++++ 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/pkg/tiller/kind_sorter.go b/pkg/tiller/kind_sorter.go index 8aff4e6c1..ceeb0f928 100644 --- a/pkg/tiller/kind_sorter.go +++ b/pkg/tiller/kind_sorter.go @@ -124,14 +124,16 @@ func (k *kindSorter) Less(i, j int) bool { b := k.manifests[j] first, aok := k.ordering[a.Head.Kind] second, bok := k.ordering[b.Head.Kind] - // if same kind (including unknown) sub sort alphanumeric - if first == second { - // if both are unknown and of different kind sort by kind alphabetically - if !aok && !bok && a.Head.Kind != b.Head.Kind { + + if !aok && !bok { + // if both are unknown then sort alphabetically by kind and name + if a.Head.Kind != b.Head.Kind { return a.Head.Kind < b.Head.Kind + } else { + return a.Name < b.Name } - return a.Name < b.Name } + // unknown kind is last if !aok { return false @@ -139,6 +141,11 @@ func (k *kindSorter) Less(i, j int) bool { if !bok { return true } + + // if same kind sub sort alphanumeric + if first == second { + return a.Name < b.Name + } // sort different kinds return first < second } diff --git a/pkg/tiller/kind_sorter_test.go b/pkg/tiller/kind_sorter_test.go index 1c187e90d..56822f995 100644 --- a/pkg/tiller/kind_sorter_test.go +++ b/pkg/tiller/kind_sorter_test.go @@ -223,3 +223,24 @@ func TestKindSorterSubSort(t *testing.T) { }) } } + +func TestKindSorterNamespaceAgainstUnknown(t *testing.T) { + unknown := Manifest{ + Name: "a", + Head: &util.SimpleHead{Kind: "Unknown"}, + } + namespace := Manifest{ + Name: "b", + Head: &util.SimpleHead{Kind: "Namespace"}, + } + + manifests := []Manifest{unknown, namespace} + sortByKind(manifests, InstallOrder) + + expectedOrder := []Manifest{namespace, unknown} + for i, manifest := range manifests { + if expectedOrder[i].Name != manifest.Name { + t.Errorf("Expected %s, got %s", expectedOrder[i].Name, manifest.Name) + } + } +} From 3953f0e884afd85a68ab4d8b4488cec735e2bc58 Mon Sep 17 00:00:00 2001 From: adshmh <23505281+adshmh@users.noreply.github.com> Date: Fri, 1 Feb 2019 12:12:03 -0500 Subject: [PATCH 090/146] fix(helm): add test for repo update strict flag (#5183) While adding the test, noticed a race in the repo update code, due to multiple go routines potentially incrementing the error counter. Included the required mutex in the repo update code in the same commit, since the new test uncovered the race condition. Signed-off-by: Arash Deshmeh --- cmd/helm/repo_update.go | 7 +++++++ cmd/helm/repo_update_test.go | 27 +++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/cmd/helm/repo_update.go b/cmd/helm/repo_update.go index 526300343..1a239b407 100644 --- a/cmd/helm/repo_update.go +++ b/cmd/helm/repo_update.go @@ -93,21 +93,28 @@ func updateCharts(repos []*repo.ChartRepository, out io.Writer, home helmpath.Ho var ( errorCounter int wg sync.WaitGroup + mu sync.Mutex ) for _, re := range repos { wg.Add(1) go func(re *repo.ChartRepository) { defer wg.Done() if re.Config.Name == localRepository { + mu.Lock() fmt.Fprintf(out, "...Skip %s chart repository\n", re.Config.Name) + mu.Unlock() return } err := re.DownloadIndexFile(home.Cache()) if err != nil { + mu.Lock() errorCounter++ fmt.Fprintf(out, "...Unable to get an update from the %q chart repository (%s):\n\t%s\n", re.Config.Name, re.Config.URL, err) + mu.Unlock() } else { + mu.Lock() fmt.Fprintf(out, "...Successfully got an update from the %q chart repository\n", re.Config.Name) + mu.Unlock() } }(re) } diff --git a/cmd/helm/repo_update_test.go b/cmd/helm/repo_update_test.go index 86af437c5..5b1058008 100644 --- a/cmd/helm/repo_update_test.go +++ b/cmd/helm/repo_update_test.go @@ -105,3 +105,30 @@ func TestUpdateCharts(t *testing.T) { t.Error("Update was not successful") } } + +func TestUpdateCmdStrictFlag(t *testing.T) { + thome, err := tempHelmHome(t) + if err != nil { + t.Fatal(err) + } + + cleanup := resetEnv() + defer func() { + os.RemoveAll(thome.String()) + cleanup() + }() + + settings.Home = thome + + out := bytes.NewBuffer(nil) + cmd := newRepoUpdateCmd(out) + cmd.ParseFlags([]string{"--strict"}) + + if err := cmd.RunE(cmd, []string{}); err == nil { + t.Fatal("expected error due to strict flag") + } + + if got := out.String(); !strings.Contains(got, "Unable to get an update") { + t.Errorf("Expected 'Unable to get an update', got %q", got) + } +} From c2e8720c7258dbfbee7cd2ed73114160a937e8fd Mon Sep 17 00:00:00 2001 From: Jecho Date: Fri, 1 Feb 2019 15:15:16 -0800 Subject: [PATCH 091/146] fixed minor typo in doc (#5249) Signed-off-by: Jecho Ricafrente --- docs/chart_tests.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/chart_tests.md b/docs/chart_tests.md index 300eeaf73..408656c4a 100644 --- a/docs/chart_tests.md +++ b/docs/chart_tests.md @@ -64,7 +64,7 @@ spec: ``` ## Steps to Run a Test Suite on a Release -1. `$ helm install wordpress` +1. `$ helm install stable/wordpress` ``` NAME: quirky-walrus LAST DEPLOYED: Mon Feb 13 13:50:43 2017 From 1f386a34ea170850f1239a850ce381356fd59ddd Mon Sep 17 00:00:00 2001 From: adshmh <23505281+adshmh@users.noreply.github.com> Date: Fri, 1 Feb 2019 18:44:46 -0500 Subject: [PATCH 092/146] add --devel flag to inspect command (#5141) * fix(helm): add --devel flag to allow inspect on pre-release chart versions Signed-off-by: Arash Deshmeh * fix(helm): remove some duplication from inspect command preparation Signed-off-by: Arash Deshmeh --- cmd/helm/inspect.go | 43 +++++++----- cmd/helm/inspect_test.go | 66 ++++++++++++++++++ .../prerelease-0.2.0-pre-release.tgz | Bin 0 -> 1064 bytes .../testdata/testcharts/prerelease/Chart.yaml | 6 ++ .../testdata/testcharts/prerelease/README.md | 13 ++++ .../prerelease/templates/alpine-pod.yaml | 26 +++++++ docs/helm/helm_inspect.md | 3 +- docs/helm/helm_inspect_chart.md | 3 +- docs/helm/helm_inspect_readme.md | 3 +- docs/helm/helm_inspect_values.md | 3 +- 10 files changed, 146 insertions(+), 20 deletions(-) create mode 100644 cmd/helm/testdata/testcharts/prerelease-0.2.0-pre-release.tgz create mode 100644 cmd/helm/testdata/testcharts/prerelease/Chart.yaml create mode 100644 cmd/helm/testdata/testcharts/prerelease/README.md create mode 100644 cmd/helm/testdata/testcharts/prerelease/templates/alpine-pod.yaml diff --git a/cmd/helm/inspect.go b/cmd/helm/inspect.go index 844116bc5..52e681e48 100644 --- a/cmd/helm/inspect.go +++ b/cmd/helm/inspect.go @@ -59,6 +59,7 @@ type inspectCmd struct { repoURL string username string password string + devel bool certFile string keyFile string @@ -88,12 +89,9 @@ func newInspectCmd(out io.Writer) *cobra.Command { if err := checkArgsLength(len(args), "chart name"); err != nil { return err } - cp, err := locateChartPath(insp.repoURL, insp.username, insp.password, args[0], insp.version, insp.verify, insp.keyring, - insp.certFile, insp.keyFile, insp.caFile) - if err != nil { + if err := insp.prepare(args[0]); err != nil { return err } - insp.chartpath = cp return insp.run() }, } @@ -107,12 +105,9 @@ func newInspectCmd(out io.Writer) *cobra.Command { if err := checkArgsLength(len(args), "chart name"); err != nil { return err } - cp, err := locateChartPath(insp.repoURL, insp.username, insp.password, args[0], insp.version, insp.verify, insp.keyring, - insp.certFile, insp.keyFile, insp.caFile) - if err != nil { + if err := insp.prepare(args[0]); err != nil { return err } - insp.chartpath = cp return insp.run() }, } @@ -126,12 +121,9 @@ func newInspectCmd(out io.Writer) *cobra.Command { if err := checkArgsLength(len(args), "chart name"); err != nil { return err } - cp, err := locateChartPath(insp.repoURL, insp.username, insp.password, args[0], insp.version, insp.verify, insp.keyring, - insp.certFile, insp.keyFile, insp.caFile) - if err != nil { + if err := insp.prepare(args[0]); err != nil { return err } - insp.chartpath = cp return insp.run() }, } @@ -145,12 +137,9 @@ func newInspectCmd(out io.Writer) *cobra.Command { if err := checkArgsLength(len(args), "chart name"); err != nil { return err } - cp, err := locateChartPath(insp.repoURL, insp.username, insp.password, args[0], insp.version, insp.verify, insp.keyring, - insp.certFile, insp.keyFile, insp.caFile) - if err != nil { + if err := insp.prepare(args[0]); err != nil { return err } - insp.chartpath = cp return insp.run() }, } @@ -193,6 +182,12 @@ func newInspectCmd(out io.Writer) *cobra.Command { valuesSubCmd.Flags().StringVar(&insp.password, password, "", passworddesc) chartSubCmd.Flags().StringVar(&insp.password, password, "", passworddesc) + develFlag := "devel" + develDesc := "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored." + for _, subCmd := range cmds { + subCmd.Flags().BoolVar(&insp.devel, develFlag, false, develDesc) + } + certFile := "cert-file" certFiledesc := "verify certificates of HTTPS-enabled servers using this CA bundle" for _, subCmd := range cmds { @@ -218,6 +213,22 @@ func newInspectCmd(out io.Writer) *cobra.Command { return inspectCommand } +func (i *inspectCmd) prepare(chart string) error { + debug("Original chart version: %q", i.version) + if i.version == "" && i.devel { + debug("setting version to >0.0.0-0") + i.version = ">0.0.0-0" + } + + cp, err := locateChartPath(i.repoURL, i.username, i.password, chart, i.version, i.verify, i.keyring, + i.certFile, i.keyFile, i.caFile) + if err != nil { + return err + } + i.chartpath = cp + return nil +} + func (i *inspectCmd) run() error { chrt, err := chartutil.Load(i.chartpath) if err != nil { diff --git a/cmd/helm/inspect_test.go b/cmd/helm/inspect_test.go index b9dbf2ab6..c4ce005b0 100644 --- a/cmd/helm/inspect_test.go +++ b/cmd/helm/inspect_test.go @@ -19,8 +19,11 @@ package main import ( "bytes" "io/ioutil" + "os" "strings" "testing" + + "k8s.io/helm/pkg/repo/repotest" ) func TestInspect(t *testing.T) { @@ -78,3 +81,66 @@ func TestInspect(t *testing.T) { t.Errorf("expected empty values buffer, got %q", b.String()) } } + +func TestInspectPreReleaseChart(t *testing.T) { + hh, err := tempHelmHome(t) + if err != nil { + t.Fatal(err) + } + cleanup := resetEnv() + defer func() { + os.RemoveAll(hh.String()) + cleanup() + }() + + settings.Home = hh + + srv := repotest.NewServer(hh.String()) + defer srv.Stop() + + if _, err := srv.CopyCharts("testdata/testcharts/*.tgz*"); err != nil { + t.Fatal(err) + } + if err := srv.LinkIndices(); err != nil { + t.Fatal(err) + } + + tests := []struct { + name string + args []string + flags []string + fail bool + expectedErr string + }{ + { + name: "inspect pre-release chart", + args: []string{"prerelease"}, + fail: true, + expectedErr: "chart \"prerelease\" not found", + }, + { + name: "inspect pre-release chart with 'devel' flag", + args: []string{"prerelease"}, + flags: []string{"--devel"}, + fail: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.flags = append(tt.flags, "--repo", srv.URL()) + cmd := newInspectCmd(ioutil.Discard) + cmd.SetArgs(tt.args) + cmd.ParseFlags(tt.flags) + if err := cmd.RunE(cmd, tt.args); err != nil { + if tt.fail { + if !strings.Contains(err.Error(), tt.expectedErr) { + t.Errorf("%q expected error: %s, got: %s", tt.name, tt.expectedErr, err.Error()) + } + return + } + t.Errorf("%q reported error: %s", tt.name, err) + } + }) + } +} diff --git a/cmd/helm/testdata/testcharts/prerelease-0.2.0-pre-release.tgz b/cmd/helm/testdata/testcharts/prerelease-0.2.0-pre-release.tgz new file mode 100644 index 0000000000000000000000000000000000000000..36c8f02da06c1b6b36342b1757e719074282c712 GIT binary patch literal 1064 zcmV+@1lRi?iwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0PI&ykJ~mA-m`wiK)J@UY`yD!>)WCU(4cJ)Y=ZzrQNUwyY!RkN zl|xzUI{xnkNonnMw#cE24T^d$hDpvdADnrHYAjh&giPb_E3_`#VXdy7SMog1Z?3Py zZ=UDpzxlK%t|rC*CfAeMO)kmL1xw{2$vo5AI(gg1EG@ank5H zyrD*!9Uv@`WeK;ck(%HqsoQ&Kj7Ta|(;O=28lI2GoBwkr&A1{}CmQ|Ev6vDztu2Y? z$>`zyTDq!TW~HfvPE_2I)M5@Fj7Vy7DA3_N0f^n5?)TYUtd;CN)^s?G z_WSG;s+PE4ND}~sOH%CB0A9hziXg4XN{4Go<0eRkmPvp!;4GFK=qg!O;EYiq0tb-* zgtgp~hBAz$9`2p%l~=8Tm9c=LmYSif40NcShh!q?Ds<2nHUmO~*2%I}XoHm=O)^;G z#%PvHMIJBO!KTSJ?UJk}M}g#O)VL-wTJGj>l7?T%Ze>aE8UAREBRCvR!|v^;P#V1@ z?Ku`|+z^9wK*+n007-y@t9}8M0i{PQcPyz3>!~2l1 zN4W4A&J2euespI3ly`lPpE;R;H|tPpvf>g{{`TA=k%)}OOimLbdN!|LxweJvSA{%UNMkh z-|n!e0(hWwh@7wp7zB&s^K$`0S}L8fyMbXm9d60)1}D8Q!!U$Sx(YBUP3yPJ%FjWp z$&uv&d>a|ezh)P(l8TPNUywA1IpFDaarO{iz~E$-B)^&#O4JYrsZ!uh6A?p?;SL9c iDS6x<7~a^6?80>yxyVJnk^B_^0RR8mc}r0M6aWC+uN4~r literal 0 HcmV?d00001 diff --git a/cmd/helm/testdata/testcharts/prerelease/Chart.yaml b/cmd/helm/testdata/testcharts/prerelease/Chart.yaml new file mode 100644 index 000000000..d8d901473 --- /dev/null +++ b/cmd/helm/testdata/testcharts/prerelease/Chart.yaml @@ -0,0 +1,6 @@ +description: Deploy a basic Alpine Linux pod +home: https://k8s.io/helm +name: prerelease +sources: +- https://github.com/helm/helm +version: 0.2.0-pre-release diff --git a/cmd/helm/testdata/testcharts/prerelease/README.md b/cmd/helm/testdata/testcharts/prerelease/README.md new file mode 100644 index 000000000..3c32de5db --- /dev/null +++ b/cmd/helm/testdata/testcharts/prerelease/README.md @@ -0,0 +1,13 @@ +#Alpine: A simple Helm chart + +Run a single pod of Alpine Linux. + +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.yaml` 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/cmd/helm/testdata/testcharts/prerelease/templates/alpine-pod.yaml b/cmd/helm/testdata/testcharts/prerelease/templates/alpine-pod.yaml new file mode 100644 index 000000000..f569d556c --- /dev/null +++ b/cmd/helm/testdata/testcharts/prerelease/templates/alpine-pod.yaml @@ -0,0 +1,26 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{.Release.Name}}-{{.Values.Name}}" + 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 + # is responsible for. + app.kubernetes.io/managed-by: {{.Release.Service | quote }} + # The "release" convention makes it easy to tie a release to all of the + # Kubernetes resources that were created as part of that release. + app.kubernetes.io/instance: {{.Release.Name | quote }} + # This makes it easy to audit chart usage. + helm.sh/chart: "{{.Chart.Name}}-{{.Chart.Version}}" + annotations: + "helm.sh/created": {{.Release.Time.Seconds | quote }} +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. + # {{default "Never" .restartPolicy}} is a slightly optimized version of the + # more conventional syntax: {{.restartPolicy | default "Never"}} + restartPolicy: {{default "Never" .Values.restartPolicy}} + containers: + - name: waiter + image: "alpine:3.3" + command: ["/bin/sleep","9000"] diff --git a/docs/helm/helm_inspect.md b/docs/helm/helm_inspect.md index 86689eeaa..8bdf1092d 100644 --- a/docs/helm/helm_inspect.md +++ b/docs/helm/helm_inspect.md @@ -20,6 +20,7 @@ helm inspect [CHART] [flags] ``` --ca-file string chart repository url where to locate the requested chart --cert-file string verify certificates of HTTPS-enabled servers using this CA bundle + --devel use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored. -h, --help help for inspect --key-file string identify HTTPS client using this SSL key file --keyring string path to the keyring containing public verification keys (default "~/.gnupg/pubring.gpg") @@ -49,4 +50,4 @@ helm inspect [CHART] [flags] * [helm inspect readme](helm_inspect_readme.md) - shows inspect readme * [helm inspect values](helm_inspect_values.md) - shows inspect values -###### Auto generated by spf13/cobra on 1-Aug-2018 +###### Auto generated by spf13/cobra on 8-Jan-2019 diff --git a/docs/helm/helm_inspect_chart.md b/docs/helm/helm_inspect_chart.md index 2b9adbb7e..1cd13fc72 100644 --- a/docs/helm/helm_inspect_chart.md +++ b/docs/helm/helm_inspect_chart.md @@ -18,6 +18,7 @@ helm inspect chart [CHART] [flags] ``` --ca-file string chart repository url where to locate the requested chart --cert-file string verify certificates of HTTPS-enabled servers using this CA bundle + --devel use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored. -h, --help help for chart --key-file string identify HTTPS client using this SSL key file --keyring string path to the keyring containing public verification keys (default "~/.gnupg/pubring.gpg") @@ -44,4 +45,4 @@ helm inspect chart [CHART] [flags] * [helm inspect](helm_inspect.md) - inspect a chart -###### Auto generated by spf13/cobra on 1-Aug-2018 +###### Auto generated by spf13/cobra on 8-Jan-2019 diff --git a/docs/helm/helm_inspect_readme.md b/docs/helm/helm_inspect_readme.md index d222cd53a..9570d19d6 100644 --- a/docs/helm/helm_inspect_readme.md +++ b/docs/helm/helm_inspect_readme.md @@ -18,6 +18,7 @@ helm inspect readme [CHART] [flags] ``` --ca-file string chart repository url where to locate the requested chart --cert-file string verify certificates of HTTPS-enabled servers using this CA bundle + --devel use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored. -h, --help help for readme --key-file string identify HTTPS client using this SSL key file --keyring string path to the keyring containing public verification keys (default "~/.gnupg/pubring.gpg") @@ -42,4 +43,4 @@ helm inspect readme [CHART] [flags] * [helm inspect](helm_inspect.md) - inspect a chart -###### Auto generated by spf13/cobra on 1-Aug-2018 +###### Auto generated by spf13/cobra on 8-Jan-2019 diff --git a/docs/helm/helm_inspect_values.md b/docs/helm/helm_inspect_values.md index 9cca2fc32..a634134dd 100644 --- a/docs/helm/helm_inspect_values.md +++ b/docs/helm/helm_inspect_values.md @@ -18,6 +18,7 @@ helm inspect values [CHART] [flags] ``` --ca-file string chart repository url where to locate the requested chart --cert-file string verify certificates of HTTPS-enabled servers using this CA bundle + --devel use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored. -h, --help help for values --key-file string identify HTTPS client using this SSL key file --keyring string path to the keyring containing public verification keys (default "~/.gnupg/pubring.gpg") @@ -44,4 +45,4 @@ helm inspect values [CHART] [flags] * [helm inspect](helm_inspect.md) - inspect a chart -###### Auto generated by spf13/cobra on 1-Aug-2018 +###### Auto generated by spf13/cobra on 8-Jan-2019 From 1984f436afa9e9d0bacb1a74bae67a0cf591b15c Mon Sep 17 00:00:00 2001 From: Aaron Roydhouse Date: Mon, 4 Feb 2019 10:22:06 -0500 Subject: [PATCH 093/146] Document the HELM_TLS_HOSTNAME variable in 'helm --help' (#5123) * Document the HELM_TLS_HOSTNAME environment variable in 'helm --help' Resolves #5120 Also adjust order `ENABLE` -> `VERIFY` -> `HOSTNAME` Signed-off-by: Aaron Roydhouse * Update docs folder for addition of HELM_TLS_HOSTNAME documentation Signed-off-by: Aaron Roydhouse --- cmd/helm/helm.go | 3 ++- docs/helm/helm.md | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/cmd/helm/helm.go b/cmd/helm/helm.go index f7628e44c..b815568cb 100644 --- a/cmd/helm/helm.go +++ b/cmd/helm/helm.go @@ -69,8 +69,9 @@ Environment: $HELM_TLS_CA_CERT path to TLS CA certificate used to verify the Helm client and Tiller server certificates (default "$HELM_HOME/ca.pem") $HELM_TLS_CERT path to TLS client certificate file for authenticating to Tiller (default "$HELM_HOME/cert.pem") $HELM_TLS_KEY path to TLS client key file for authenticating to Tiller (default "$HELM_HOME/key.pem") - $HELM_TLS_VERIFY enable TLS connection between Helm and Tiller and verify Tiller server certificate (default "false") $HELM_TLS_ENABLE enable TLS connection between Helm and Tiller (default "false") + $HELM_TLS_VERIFY enable TLS connection between Helm and Tiller and verify Tiller server certificate (default "false") + $HELM_TLS_HOSTNAME the hostname or IP address used to verify the Tiller server certificate (default "127.0.0.1") $HELM_KEY_PASSPHRASE set HELM_KEY_PASSPHRASE to the passphrase of your PGP private key. If set, you will not be prompted for the passphrase while signing helm charts diff --git a/docs/helm/helm.md b/docs/helm/helm.md index 177be7e88..b00ae91d6 100644 --- a/docs/helm/helm.md +++ b/docs/helm/helm.md @@ -29,8 +29,9 @@ Environment: $HELM_TLS_CA_CERT path to TLS CA certificate used to verify the Helm client and Tiller server certificates (default "$HELM_HOME/ca.pem") $HELM_TLS_CERT path to TLS client certificate file for authenticating to Tiller (default "$HELM_HOME/cert.pem") $HELM_TLS_KEY path to TLS client key file for authenticating to Tiller (default "$HELM_HOME/key.pem") - $HELM_TLS_VERIFY enable TLS connection between Helm and Tiller and verify Tiller server certificate (default "false") $HELM_TLS_ENABLE enable TLS connection between Helm and Tiller (default "false") + $HELM_TLS_VERIFY enable TLS connection between Helm and Tiller and verify Tiller server certificate (default "false") + $HELM_TLS_HOSTNAME the hostname or IP address used to verify the Tiller server certificate (default "127.0.0.1") $HELM_KEY_PASSPHRASE set HELM_KEY_PASSPHRASE to the passphrase of your PGP private key. If set, you will not be prompted for the passphrase while signing helm charts @@ -78,4 +79,4 @@ Environment: * [helm verify](helm_verify.md) - verify that a chart at the given path has been signed and is valid * [helm version](helm_version.md) - print the client/server version information -###### Auto generated by spf13/cobra on 16-Oct-2018 +###### Auto generated by spf13/cobra on 4-Feb-2019 From d8bdf484cc77e5e816b311d99609a2511c897eea Mon Sep 17 00:00:00 2001 From: adshmh <23505281+adshmh@users.noreply.github.com> Date: Mon, 4 Feb 2019 17:38:08 -0500 Subject: [PATCH 094/146] fix(helm): add descriptive error if dependency has blank "repository" (#5152) Signed-off-by: Arash Deshmeh --- pkg/downloader/manager.go | 3 +++ pkg/downloader/manager_test.go | 21 +++++++++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index 67f9dc7bf..aea48bd7e 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -371,6 +371,9 @@ func (m *Manager) getRepoNames(deps []*chartutil.Dependency) (map[string]string, // by Helm. missing := []string{} for _, dd := range deps { + if dd.Repository == "" { + return nil, fmt.Errorf("no 'repository' field specified for dependency: %q", dd.Name) + } // if dep chart is from local path, verify the path is valid if strings.HasPrefix(dd.Repository, "file://") { if _, err := resolver.GetLocalPath(dd.Repository, m.ChartPath); err != nil { diff --git a/pkg/downloader/manager_test.go b/pkg/downloader/manager_test.go index 8c2377e47..cb588394a 100644 --- a/pkg/downloader/manager_test.go +++ b/pkg/downloader/manager_test.go @@ -18,6 +18,7 @@ package downloader import ( "bytes" "reflect" + "strings" "testing" "k8s.io/helm/pkg/chartutil" @@ -99,10 +100,11 @@ func TestGetRepoNames(t *testing.T) { HelmHome: helmpath.Home("testdata/helmhome"), } tests := []struct { - name string - req []*chartutil.Dependency - expect map[string]string - err bool + name string + req []*chartutil.Dependency + expect map[string]string + err bool + expectedErr string }{ { name: "no repo definition failure", @@ -118,6 +120,14 @@ func TestGetRepoNames(t *testing.T) { }, err: true, }, + { + name: "dependency entry missing 'repository' field -- e.g. spelled 'repo'", + req: []*chartutil.Dependency{ + {Name: "dependency-missing-repository-field"}, + }, + err: true, + expectedErr: "no 'repository' field specified for dependency: \"dependency-missing-repository-field\"", + }, { name: "no repo definition failure", req: []*chartutil.Dependency{ @@ -152,6 +162,9 @@ func TestGetRepoNames(t *testing.T) { l, err := m.getRepoNames(tt.req) if err != nil { if tt.err { + if !strings.Contains(err.Error(), tt.expectedErr) { + t.Fatalf("%s: expected error: %s, got: %s", tt.name, tt.expectedErr, err.Error()) + } continue } t.Fatal(err) From 16c10be8e652165414eef007be3f57638d6894cf Mon Sep 17 00:00:00 2001 From: Henry Nash Date: Tue, 5 Feb 2019 16:24:54 +0000 Subject: [PATCH 095/146] Improve language describing deletion of hooks (#5065) * Improve language describing deletion of hooks The existing language was somewhat confusing and grammatically poor. Closes #5035 Signed-off-by: Henry Nash * Improve language describing deletion of hooks The existing language was somewhat confusing and grammatically poor. Closes #5035 Signed-off-by: Henry Nash --- docs/charts_hooks.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/docs/charts_hooks.md b/docs/charts_hooks.md index 59c9c91a2..fbb302481 100644 --- a/docs/charts_hooks.md +++ b/docs/charts_hooks.md @@ -246,12 +246,10 @@ annotated. ### Automatically delete hook from previous release -When helm release being updated it is possible, that hook resource already exists in cluster. By default helm will try to create resource and fail with `"... already exists"` error. +When a helm release, that uses a hook, is being updated, it is possible that the hook resource might already exist in the cluster. In such circumstances, by default, helm will fail trying to install the hook resource with an `"... already exists"` error. -One might choose `"helm.sh/hook-delete-policy": "before-hook-creation"` over `"helm.sh/hook-delete-policy": "hook-succeeded,hook-failed"` because: +A common reason why the hook resource might already exist is that it was not deleted following use on a previous install/upgrade. There are, in fact, good reasons why one might want to keep the hook: for example, to aid manual debugging in case something went wrong. In this case, the recommended way of ensuring subsequent attemps to create the hook do not fail is to define a `"hook-delete-policy"` that can handle this: `"helm.sh/hook-delete-policy": "before-hook-creation"`. This hook annotation causes any existing hook to be removed, before the new hook is installed. + +If it is preferred to actually delete the hook after each use (rather than have to handle it on a subsequent use, as shown above), then this can be achived using a delete policy of `"helm.sh/hook-delete-policy": "hook-succeeded,hook-failed"`. -* It is convenient to keep failed hook job resource in kubernetes for example for manual debug. -* It may be necessary to keep succeeded hook resource in kubernetes for some reason. -* At the same time it is not desirable to do manual resource deletion before helm release upgrade. -`"helm.sh/hook-delete-policy": "before-hook-creation"` annotation on hook causes tiller to remove the hook from previous release if there is one before the new hook is launched and can be used with another policy. From 6e26320befd19cc112f72d51e29230c26a191d9e Mon Sep 17 00:00:00 2001 From: Alex Ellis Date: Wed, 6 Feb 2019 21:01:46 +0000 Subject: [PATCH 096/146] Fix issue #5273 for get script on armv7l (#5275) This fixes issue #5273 in the get script by making the armv7l architecture point at the correctly named "arm" binary on the release page. Signed-off-by: Alex Ellis --- scripts/get | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/get b/scripts/get index bf13d25bc..9c93e1e84 100755 --- a/scripts/get +++ b/scripts/get @@ -29,7 +29,7 @@ initArch() { case $ARCH in armv5*) ARCH="armv5";; armv6*) ARCH="armv6";; - armv7*) ARCH="armv7";; + armv7*) ARCH="arm";; aarch64) ARCH="arm64";; x86) ARCH="386";; x86_64) ARCH="amd64";; From a1ea9678be1442fc04883cc4b2c8bab526f72a9c Mon Sep 17 00:00:00 2001 From: Ian Howell Date: Wed, 6 Feb 2019 15:51:11 -0600 Subject: [PATCH 097/146] Add unit tests for checking sort order on helm get Signed-off-by: Ian Howell --- pkg/kube/client.go | 2 +- pkg/kube/client_test.go | 131 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+), 1 deletion(-) diff --git a/pkg/kube/client.go b/pkg/kube/client.go index 9aa821b5a..c5f3bf77f 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -266,8 +266,8 @@ func (c *Client) Get(namespace string, reader io.Reader) (string, error) { // Now that each individual resource within the specific version/kind // is sorted, we print each resource using the k8s printer + vk := objs[t] for _, resourceName := range sortedResources { - vk := objs[t] if err := typePrinter.PrintObj(vk[resourceName], buf); err != nil { c.Log("failed to print object type %s, object: %q :\n %v", t, resourceName, err) return "", err diff --git a/pkg/kube/client_test.go b/pkg/kube/client_test.go index de33881c8..81356540e 100644 --- a/pkg/kube/client_test.go +++ b/pkg/kube/client_test.go @@ -21,6 +21,7 @@ import ( "io" "io/ioutil" "net/http" + "sort" "strings" "testing" @@ -77,6 +78,18 @@ func newPodList(names ...string) v1.PodList { return list } +func newService(name string) v1.Service { + ns := v1.NamespaceDefault + return v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: ns, + SelfLink: "/api/v1/namespaces/default/services/" + name, + }, + Spec: v1.ServiceSpec{}, + } +} + func notFoundBody() *metav1.Status { return &metav1.Status{ Code: http.StatusNotFound, @@ -280,6 +293,95 @@ func TestGet(t *testing.T) { } } +func TestResourceTypeSortOrder(t *testing.T) { + pod := newPod("my-pod") + service := newService("my-service") + c := newTestClient() + defer c.Cleanup() + c.TestFactory.UnstructuredClient = &fake.RESTClient{ + GroupVersion: schema.GroupVersion{Version: "v1"}, + NegotiatedSerializer: unstructuredSerializer, + Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { + p, m := req.URL.Path, req.Method + t.Logf("got request %s %s", p, m) + switch { + case p == "/namespaces/default/pods/my-pod" && m == "GET": + return newResponse(200, &pod) + case p == "/namespaces/default/services/my-service" && m == "GET": + return newResponse(200, &service) + default: + t.Fatalf("unexpected request: %s %s", req.Method, req.URL.Path) + return nil, nil + } + }), + } + + // Test sorting order + data := strings.NewReader(testResourceTypeSortOrder) + o, err := c.Get("default", data) + if err != nil { + t.Errorf("Expected missing results, got %q", err) + } + podIndex := strings.Index(o, "my-pod") + serviceIndex := strings.Index(o, "my-service") + if podIndex == -1 { + t.Errorf("Expected v1/Pod my-pod, got %s", o) + } + if serviceIndex == -1 { + t.Errorf("Expected v1/Service my-service, got %s", o) + } + if !sort.IntsAreSorted([]int{podIndex, serviceIndex}) { + t.Errorf("Expected order: [v1/Pod v1/Service], got %s", o) + } +} + +func TestResourceSortOrder(t *testing.T) { + list := newPodList("albacore", "coral", "beluga") + c := newTestClient() + defer c.Cleanup() + c.TestFactory.UnstructuredClient = &fake.RESTClient{ + GroupVersion: schema.GroupVersion{Version: "v1"}, + NegotiatedSerializer: unstructuredSerializer, + Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { + p, m := req.URL.Path, req.Method + t.Logf("got request %s %s", p, m) + switch { + case p == "/namespaces/default/pods/albacore" && m == "GET": + return newResponse(200, &list.Items[0]) + case p == "/namespaces/default/pods/coral" && m == "GET": + return newResponse(200, &list.Items[1]) + case p == "/namespaces/default/pods/beluga" && m == "GET": + return newResponse(200, &list.Items[2]) + default: + t.Fatalf("unexpected request: %s %s", req.Method, req.URL.Path) + return nil, nil + } + }), + } + + // Test sorting order + data := strings.NewReader(testResourceSortOrder) + o, err := c.Get("default", data) + if err != nil { + t.Errorf("Expected missing results, got %q", err) + } + albacoreIndex := strings.Index(o, "albacore") + belugaIndex := strings.Index(o, "beluga") + coralIndex := strings.Index(o, "coral") + if albacoreIndex == -1 { + t.Errorf("Expected v1/Pod albacore, got %s", o) + } + if belugaIndex == -1 { + t.Errorf("Expected v1/Pod beluga, got %s", o) + } + if coralIndex == -1 { + t.Errorf("Expected v1/Pod coral, got %s", o) + } + if !sort.IntsAreSorted([]int{albacoreIndex, belugaIndex, coralIndex}) { + t.Errorf("Expected order: [albacore beluga coral], got %s", o) + } +} + func TestPerform(t *testing.T) { tests := []struct { name string @@ -361,6 +463,35 @@ func TestReal(t *testing.T) { } } +const testResourceTypeSortOrder = ` +kind: Service +apiVersion: v1 +metadata: + name: my-service +--- +kind: Pod +apiVersion: v1 +metadata: + name: my-pod +` + +const testResourceSortOrder = ` +kind: Pod +apiVersion: v1 +metadata: + name: albacore +--- +kind: Pod +apiVersion: v1 +metadata: + name: beluga +--- +kind: Pod +apiVersion: v1 +metadata: + name: coral +` + const testServiceManifest = ` kind: Service apiVersion: v1 From 2734066bcccb67e2021e28c90f595ed25259f0bb Mon Sep 17 00:00:00 2001 From: Elad Iwanir Date: Thu, 7 Feb 2019 22:56:38 +0200 Subject: [PATCH 098/146] changing return order of test items so the sorting tests will fail if actually broken Signed-off-by: Elad Iwanir --- pkg/kube/client_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/kube/client_test.go b/pkg/kube/client_test.go index 81356540e..9c60f57e3 100644 --- a/pkg/kube/client_test.go +++ b/pkg/kube/client_test.go @@ -484,12 +484,12 @@ metadata: kind: Pod apiVersion: v1 metadata: - name: beluga + name: coral --- kind: Pod apiVersion: v1 metadata: - name: coral + name: beluga ` const testServiceManifest = ` From a3d7027152fc5ad0c7f057497026e6719f26d2bf Mon Sep 17 00:00:00 2001 From: Josh Dolitsky Date: Fri, 8 Feb 2019 12:09:45 -0600 Subject: [PATCH 099/146] Add docs on how to host repo with ChartMuseum (#5282) Signed-off-by: Josh Dolitsky --- docs/chart_repository.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/docs/chart_repository.md b/docs/chart_repository.md index 5291f65e4..e3bbe3c7d 100644 --- a/docs/chart_repository.md +++ b/docs/chart_repository.md @@ -123,6 +123,35 @@ startup. This part shows several ways to serve a chart repository. +### ChartMuseum + +The Helm project provides an open-source Helm repository server called [ChartMuseum](https://chartmuseum.com) that you can host yourself. + +ChartMuseum supports multiple cloud storage backends. Configure it to point to the directory or bucket containing your chart packages, and the index.yaml file will be generated dynamically. + +It can be deployed easily as a [Helm chart](https://github.com/helm/charts/tree/master/stable/chartmuseum): +``` +helm install stable/chartmuseum +``` + +and also as a [Docker image](https://hub.docker.com/r/chartmuseum/chartmuseum/tags): +``` +docker run --rm -it \ + -p 8080:8080 \ + -v $(pwd)/charts:/charts \ + -e DEBUG=true \ + -e STORAGE=local \ + -e STORAGE_LOCAL_ROOTDIR=/charts \ + chartmuseum/chartmuseum +``` + +You can then add the repo to your local repository list: +``` +helm repo add chartmuseum http://localhost:8080 +``` + +ChartMuseum provides other features, such as an API for chart uploads. Please see the [README](https://github.com/helm/chartmuseum) for more info. + ### Google Cloud Storage The first step is to **create your GCS bucket**. We'll call ours From bed4054c412f95d140c8c98b6387f40df7f3139e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Lipt=C3=A1k?= Date: Sun, 10 Feb 2019 04:14:32 -0500 Subject: [PATCH 100/146] Correct golint warning (#5287) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gábor Lipták --- pkg/tiller/kind_sorter.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/tiller/kind_sorter.go b/pkg/tiller/kind_sorter.go index ceeb0f928..f980277d2 100644 --- a/pkg/tiller/kind_sorter.go +++ b/pkg/tiller/kind_sorter.go @@ -129,9 +129,8 @@ func (k *kindSorter) Less(i, j int) bool { // if both are unknown then sort alphabetically by kind and name if a.Head.Kind != b.Head.Kind { return a.Head.Kind < b.Head.Kind - } else { - return a.Name < b.Name } + return a.Name < b.Name } // unknown kind is last From 5767f13aaa5bfb513747b73f3c5d8cd4b0640684 Mon Sep 17 00:00:00 2001 From: xichengliudui <1693291525@qq.com> Date: Sun, 10 Feb 2019 23:57:53 -0500 Subject: [PATCH 101/146] Fix function comment to consistent with its name Signed-off-by: xichengliudui <1693291525@qq.com> --- pkg/chartutil/capabilities.go | 2 +- pkg/chartutil/requirements.go | 2 +- pkg/downloader/chart_downloader.go | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pkg/chartutil/capabilities.go b/pkg/chartutil/capabilities.go index d7e660b8a..b4533e417 100644 --- a/pkg/chartutil/capabilities.go +++ b/pkg/chartutil/capabilities.go @@ -40,7 +40,7 @@ var ( // Capabilities describes the capabilities of the Kubernetes cluster that Tiller is attached to. type Capabilities struct { - // List of all supported API versions + // APIVersions list of all supported API versions APIVersions VersionSet // KubeVersion is the Kubernetes version KubeVersion *version.Info diff --git a/pkg/chartutil/requirements.go b/pkg/chartutil/requirements.go index 0f1128305..f21a22005 100644 --- a/pkg/chartutil/requirements.go +++ b/pkg/chartutil/requirements.go @@ -85,7 +85,7 @@ type Requirements struct { // // It represents the state that the dependencies should be in. type RequirementsLock struct { - // Genderated is the date the lock file was last generated. + // Generated is the date the lock file was last generated. Generated time.Time `json:"generated"` // Digest is a hash of the requirements file used to generate it. Digest string `json:"digest"` diff --git a/pkg/downloader/chart_downloader.go b/pkg/downloader/chart_downloader.go index 5e6287299..453e81470 100644 --- a/pkg/downloader/chart_downloader.go +++ b/pkg/downloader/chart_downloader.go @@ -65,11 +65,11 @@ type ChartDownloader struct { Keyring string // HelmHome is the $HELM_HOME. HelmHome helmpath.Home - // Getter collection for the operation + // Getters collection for the operation Getters getter.Providers - // Chart repository username + // Username chart repository username Username string - // Chart repository password + // Password chart repository password Password string } @@ -243,14 +243,14 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, ge return u, r.Client, nil } -// If HttpGetter is used, this method sets the configured repository credentials on the HttpGetter. +// setCredentials if HttpGetter is used, this method sets the configured repository credentials on the HttpGetter. func (c *ChartDownloader) setCredentials(r *repo.ChartRepository) { if t, ok := r.Client.(*getter.HttpGetter); ok { t.SetCredentials(c.getRepoCredentials(r)) } } -// If this ChartDownloader is not configured to use credentials, and the chart repository sent as an argument is, +// getRepoCredentials if this ChartDownloader is not configured to use credentials, and the chart repository sent as an argument is, // then the repository's configured credentials are returned. // Else, this ChartDownloader's credentials are returned. func (c *ChartDownloader) getRepoCredentials(r *repo.ChartRepository) (username, password string) { From 9fb9850aca4afab0d38bcd73218098a145b4e7ac Mon Sep 17 00:00:00 2001 From: lIuDuI <1693291525@qq.com> Date: Tue, 12 Feb 2019 22:26:24 +0800 Subject: [PATCH 102/146] Fix function comment to consistent with its name (#5294) Signed-off-by: xichengliudui <1693291525@qq.com> --- pkg/downloader/manager.go | 2 +- pkg/engine/engine.go | 2 +- pkg/helm/client.go | 22 +++++++++++----------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index aea48bd7e..372940880 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -604,7 +604,7 @@ func writeLock(chartpath string, lock *chartutil.RequirementsLock) error { return ioutil.WriteFile(dest, data, 0644) } -// archive a dep chart from local directory and save it into charts/ +// tarFromLocalDir archive a dep chart from local directory and save it into charts/ func tarFromLocalDir(chartpath string, name string, repo string, version string) (string, error) { destPath := filepath.Join(chartpath, "charts") diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index f3dd869c9..9a155de2e 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -130,7 +130,7 @@ type renderable struct { tpl string // vals are the values to be supplied to the template. vals chartutil.Values - // namespace prefix to the templates of the current chart + // basePath namespace prefix to the templates of the current chart basePath string } diff --git a/pkg/helm/client.go b/pkg/helm/client.go index 0d4d16039..fa867c2d3 100644 --- a/pkg/helm/client.go +++ b/pkg/helm/client.go @@ -334,7 +334,7 @@ func (h *Client) connect(ctx context.Context) (conn *grpc.ClientConn, err error) return conn, nil } -// Executes tiller.ListReleases RPC. +// list executes tiller.ListReleases RPC. func (h *Client) list(ctx context.Context, req *rls.ListReleasesRequest) (*rls.ListReleasesResponse, error) { c, err := h.connect(ctx) if err != nil { @@ -365,7 +365,7 @@ func (h *Client) list(ctx context.Context, req *rls.ListReleasesRequest) (*rls.L return resp, nil } -// Executes tiller.InstallRelease RPC. +// install executes tiller.InstallRelease RPC. func (h *Client) install(ctx context.Context, req *rls.InstallReleaseRequest) (*rls.InstallReleaseResponse, error) { c, err := h.connect(ctx) if err != nil { @@ -377,7 +377,7 @@ func (h *Client) install(ctx context.Context, req *rls.InstallReleaseRequest) (* return rlc.InstallRelease(ctx, req) } -// Executes tiller.UninstallRelease RPC. +// delete executes tiller.UninstallRelease RPC. func (h *Client) delete(ctx context.Context, req *rls.UninstallReleaseRequest) (*rls.UninstallReleaseResponse, error) { c, err := h.connect(ctx) if err != nil { @@ -389,7 +389,7 @@ func (h *Client) delete(ctx context.Context, req *rls.UninstallReleaseRequest) ( return rlc.UninstallRelease(ctx, req) } -// Executes tiller.UpdateRelease RPC. +// update executes tiller.UpdateRelease RPC. func (h *Client) update(ctx context.Context, req *rls.UpdateReleaseRequest) (*rls.UpdateReleaseResponse, error) { c, err := h.connect(ctx) if err != nil { @@ -401,7 +401,7 @@ func (h *Client) update(ctx context.Context, req *rls.UpdateReleaseRequest) (*rl return rlc.UpdateRelease(ctx, req) } -// Executes tiller.RollbackRelease RPC. +// rollback executes tiller.RollbackRelease RPC. func (h *Client) rollback(ctx context.Context, req *rls.RollbackReleaseRequest) (*rls.RollbackReleaseResponse, error) { c, err := h.connect(ctx) if err != nil { @@ -413,7 +413,7 @@ func (h *Client) rollback(ctx context.Context, req *rls.RollbackReleaseRequest) return rlc.RollbackRelease(ctx, req) } -// Executes tiller.GetReleaseStatus RPC. +// status executes tiller.GetReleaseStatus RPC. func (h *Client) status(ctx context.Context, req *rls.GetReleaseStatusRequest) (*rls.GetReleaseStatusResponse, error) { c, err := h.connect(ctx) if err != nil { @@ -425,7 +425,7 @@ func (h *Client) status(ctx context.Context, req *rls.GetReleaseStatusRequest) ( return rlc.GetReleaseStatus(ctx, req) } -// Executes tiller.GetReleaseContent RPC. +// content executes tiller.GetReleaseContent RPC. func (h *Client) content(ctx context.Context, req *rls.GetReleaseContentRequest) (*rls.GetReleaseContentResponse, error) { c, err := h.connect(ctx) if err != nil { @@ -437,7 +437,7 @@ func (h *Client) content(ctx context.Context, req *rls.GetReleaseContentRequest) return rlc.GetReleaseContent(ctx, req) } -// Executes tiller.GetVersion RPC. +// version executes tiller.GetVersion RPC. func (h *Client) version(ctx context.Context, req *rls.GetVersionRequest) (*rls.GetVersionResponse, error) { c, err := h.connect(ctx) if err != nil { @@ -449,7 +449,7 @@ func (h *Client) version(ctx context.Context, req *rls.GetVersionRequest) (*rls. return rlc.GetVersion(ctx, req) } -// Executes tiller.GetHistory RPC. +// history executes tiller.GetHistory RPC. func (h *Client) history(ctx context.Context, req *rls.GetHistoryRequest) (*rls.GetHistoryResponse, error) { c, err := h.connect(ctx) if err != nil { @@ -461,7 +461,7 @@ func (h *Client) history(ctx context.Context, req *rls.GetHistoryRequest) (*rls. return rlc.GetHistory(ctx, req) } -// Executes tiller.TestRelease RPC. +// test executes tiller.TestRelease RPC. func (h *Client) test(ctx context.Context, req *rls.TestReleaseRequest) (<-chan *rls.TestReleaseResponse, <-chan error) { errc := make(chan error, 1) c, err := h.connect(ctx) @@ -499,7 +499,7 @@ func (h *Client) test(ctx context.Context, req *rls.TestReleaseRequest) (<-chan return ch, errc } -// Executes tiller.Ping RPC. +// ping executes tiller.Ping RPC. func (h *Client) ping(ctx context.Context) error { c, err := h.connect(ctx) if err != nil { From 70c509e77ee2acecc722c429bc78415b2c660616 Mon Sep 17 00:00:00 2001 From: Matt Butcher Date: Tue, 12 Feb 2019 08:42:58 -0700 Subject: [PATCH 103/146] fix: Update gRPC to get better TLS connection handling (v2 minor release) (#5210) * fix: Update gRPC to get better TLS connection handling To avoid backward compatibility breakers, we have been pinned to a very old version of gRPC. But it appears that there have been some very significant network fixes since then. Looking closely at #3480, it appears that some of this fixes may be directly related to solving that bug. Note that this regenerates a few of the Go proto files, so the binary wire format may be broken. That means this MUST be held to a minor version, not a patch release. To test: - Build both client and server - Install Tiller into your cluster - Perform a number of Helm-Tiller interactions (`helm version`, `helm list`) Closes #3480 Signed-off-by: Matt Butcher * Switched to latest protobuf Signed-off-by: Matt Butcher --- glide.lock | 34 +++-- glide.yaml | 10 +- pkg/proto/hapi/services/tiller.pb.go | 195 ++++++++++++++------------- 3 files changed, 130 insertions(+), 109 deletions(-) diff --git a/glide.lock b/glide.lock index 105dada1f..1fa7c3d95 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: 2af9a5c4f891a0f44109a929a494b5aeaaffa3a87cd1f3881f25f79845703d5b -updated: 2018-12-14T21:39:31.112097Z +hash: 5dc21cc57b38ab1076f9e12d1e4248047ccc4470af8f81c8560560cb492bee9e +updated: 2019-02-08T15:20:12.179155-07:00 imports: - name: cloud.google.com/go version: 3b1ae45394a234c385be014e9a488f2bb6eef821 @@ -122,7 +122,7 @@ imports: subpackages: - lru - name: github.com/golang/protobuf - version: 1643683e1b54a9e88ad26d98f81400c8c9d9f4f9 + version: aa810b61a9c79d51363740d207bb46cf8e620ed5 subpackages: - proto - ptypes @@ -166,7 +166,7 @@ imports: subpackages: - simplelru - name: github.com/huandu/xstrings - version: 3959339b333561bf62a38b424fd41517c2c90f40 + version: f02667b379e2fb5916c3cda2cf31e0eb885d79f8 - name: github.com/imdario/mergo version: 9316a62528ac99aaecb4e47eadd6dc8aa6533d58 - name: github.com/inconshreveable/mousetrap @@ -184,7 +184,7 @@ imports: - name: github.com/Masterminds/semver version: 517734cc7d6470c0d07130e40fd40bdeb9bcd3fd - name: github.com/Masterminds/sprig - version: 15f9564e7e9cf0da02a48e0d25f12a7b83559aa6 + version: 544a9b1d90f323f6509491b389714fbbd126bee3 - name: github.com/Masterminds/vcs version: 3084677c2c188840777bff30054f2b553729d329 - name: github.com/mattn/go-runewidth @@ -281,7 +281,7 @@ imports: subpackages: - semaphore - name: golang.org/x/sys - version: 95c6576299259db960f6c5b9b69ea52422860fce + version: b90733256f2e882e81d52f9126de08df5615afd9 subpackages: - unix - windows @@ -325,26 +325,40 @@ imports: subpackages: - googleapis/rpc/status - name: google.golang.org/grpc - version: 5ffe3083946d5603a0578721101dc8165b1d5b5f + version: a02b0774206b209466313a0b525d2c738fe407eb subpackages: - balancer + - balancer/base + - balancer/roundrobin + - binarylog/grpc_binarylog_v1 - codes - connectivity - credentials - - grpclb/grpc_lb_v1/messages + - credentials/internal + - encoding + - encoding/proto - grpclog - health - health/grpc_health_v1 - internal + - internal/backoff + - internal/binarylog + - internal/channelz + - internal/envconfig + - internal/grpcrand + - internal/grpcsync + - internal/syscall + - internal/transport - keepalive - metadata - naming - peer - resolver + - resolver/dns + - resolver/passthrough - stats - status - tap - - transport - name: gopkg.in/inf.v0 version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4 - name: gopkg.in/square/go-jose.v2 @@ -597,7 +611,7 @@ imports: - pkg/util/proto/testing - pkg/util/proto/validation - name: k8s.io/kubernetes - version: f2c8f1cadf1808ec28476682e49a3cce2b09efbf + version: c6d339953bd4fd8c021a6b5fb46d7952b30be9f9 subpackages: - pkg/api/legacyscheme - pkg/api/service diff --git a/glide.yaml b/glide.yaml index bf81b22ee..42c10b347 100644 --- a/glide.yaml +++ b/glide.yaml @@ -6,6 +6,12 @@ import: - package: golang.org/x/sync subpackages: - semaphore + # This is temporary and can probably be removed the next time gRPC is updated + - package: golang.org/x/sys + version: b90733256f2e882e81d52f9126de08df5615afd9 + subpackages: + - unix + - windows - package: github.com/spf13/cobra version: fe5e611709b0c57fa4a89136deaa8e1d4004d053 - package: github.com/spf13/pflag @@ -22,13 +28,13 @@ import: - package: github.com/technosophos/moniker version: ~0.2 - package: github.com/golang/protobuf - version: 1643683e1b54a9e88ad26d98f81400c8c9d9f4f9 + version: 1.2.0 subpackages: - proto - ptypes/any - ptypes/timestamp - package: google.golang.org/grpc - version: 1.7.2 + version: 1.18.0 - package: github.com/gosuri/uitable - package: github.com/asaskevich/govalidator version: ^4.0.0 diff --git a/pkg/proto/hapi/services/tiller.pb.go b/pkg/proto/hapi/services/tiller.pb.go index 8708d0a18..ce76cad12 100644 --- a/pkg/proto/hapi/services/tiller.pb.go +++ b/pkg/proto/hapi/services/tiller.pb.go @@ -467,18 +467,18 @@ func (m *UpdateReleaseRequest) GetForce() bool { return false } -func (m *UpdateReleaseRequest) GetSubNotes() bool { +func (m *UpdateReleaseRequest) GetDescription() string { if m != nil { - return m.SubNotes + return m.Description } - return false + return "" } -func (m *UpdateReleaseRequest) GetDescription() string { +func (m *UpdateReleaseRequest) GetSubNotes() bool { if m != nil { - return m.Description + return m.SubNotes } - return "" + return false } // UpdateReleaseResponse is the response to an update request. @@ -711,18 +711,18 @@ func (m *InstallReleaseRequest) GetDisableCrdHook() bool { return false } -func (m *InstallReleaseRequest) GetSubNotes() bool { +func (m *InstallReleaseRequest) GetDescription() string { if m != nil { - return m.SubNotes + return m.Description } - return false + return "" } -func (m *InstallReleaseRequest) GetDescription() string { +func (m *InstallReleaseRequest) GetSubNotes() bool { if m != nil { - return m.Description + return m.SubNotes } - return "" + return false } // InstallReleaseResponse is the response from a release installation. @@ -752,7 +752,7 @@ type UninstallReleaseRequest struct { Purge bool `protobuf:"varint,3,opt,name=purge" json:"purge,omitempty"` // timeout specifies the max amount of time any kubernetes client command can run. Timeout int64 `protobuf:"varint,4,opt,name=timeout" json:"timeout,omitempty"` - // Description, if set, will set the description for the uninnstalled release + // Description, if set, will set the description for the uninstalled release Description string `protobuf:"bytes,5,opt,name=description" json:"description,omitempty"` } @@ -1018,7 +1018,7 @@ type ReleaseServiceClient interface { GetVersion(ctx context.Context, in *GetVersionRequest, opts ...grpc.CallOption) (*GetVersionResponse, error) // RollbackRelease rolls back a release to a previous version. RollbackRelease(ctx context.Context, in *RollbackReleaseRequest, opts ...grpc.CallOption) (*RollbackReleaseResponse, error) - // ReleaseHistory retrieves a releasse's history. + // ReleaseHistory retrieves a release's history. GetHistory(ctx context.Context, in *GetHistoryRequest, opts ...grpc.CallOption) (*GetHistoryResponse, error) // RunReleaseTest executes the tests defined of a named release RunReleaseTest(ctx context.Context, in *TestReleaseRequest, opts ...grpc.CallOption) (ReleaseService_RunReleaseTestClient, error) @@ -1190,7 +1190,7 @@ type ReleaseServiceServer interface { GetVersion(context.Context, *GetVersionRequest) (*GetVersionResponse, error) // RollbackRelease rolls back a release to a previous version. RollbackRelease(context.Context, *RollbackReleaseRequest) (*RollbackReleaseResponse, error) - // ReleaseHistory retrieves a releasse's history. + // ReleaseHistory retrieves a release's history. GetHistory(context.Context, *GetHistoryRequest) (*GetHistoryResponse, error) // RunReleaseTest executes the tests defined of a named release RunReleaseTest(*TestReleaseRequest, ReleaseService_RunReleaseTestServer) error @@ -1441,86 +1441,87 @@ var _ReleaseService_serviceDesc = grpc.ServiceDesc{ func init() { proto.RegisterFile("hapi/services/tiller.proto", fileDescriptor0) } var fileDescriptor0 = []byte{ - // 1289 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x57, 0xed, 0x72, 0xdb, 0x44, - 0x17, 0x8e, 0x2d, 0x7f, 0x1e, 0xa7, 0x7e, 0xdd, 0x6d, 0x9a, 0xa8, 0x7a, 0x0b, 0x63, 0xc4, 0x40, - 0xdd, 0x42, 0x1d, 0x30, 0xfc, 0x61, 0x86, 0x61, 0x26, 0x75, 0x3d, 0x49, 0x21, 0xa4, 0x33, 0x72, - 0x5b, 0x66, 0x98, 0x61, 0x3c, 0x8a, 0xbd, 0x6e, 0x45, 0x65, 0xc9, 0x68, 0x57, 0xa1, 0xb9, 0x00, - 0x98, 0xe1, 0x3e, 0xb8, 0x10, 0xee, 0x83, 0xeb, 0xe0, 0x3f, 0xb3, 0x5f, 0x8a, 0x56, 0x96, 0x1c, - 0x91, 0x3f, 0xb1, 0x76, 0xcf, 0xd9, 0xf3, 0xf1, 0x3c, 0x7b, 0xce, 0x9e, 0x80, 0xf5, 0xc6, 0x5d, - 0x7b, 0x87, 0x04, 0x47, 0x17, 0xde, 0x1c, 0x93, 0x43, 0xea, 0xf9, 0x3e, 0x8e, 0x86, 0xeb, 0x28, - 0xa4, 0x21, 0xda, 0x63, 0xb2, 0xa1, 0x92, 0x0d, 0x85, 0xcc, 0xda, 0xe7, 0x27, 0xe6, 0x6f, 0xdc, - 0x88, 0x8a, 0xbf, 0x42, 0xdb, 0x3a, 0x48, 0xef, 0x87, 0xc1, 0xd2, 0x7b, 0x2d, 0x05, 0xc2, 0x45, - 0x84, 0x7d, 0xec, 0x12, 0xac, 0x7e, 0xb5, 0x43, 0x4a, 0xe6, 0x05, 0xcb, 0x50, 0x0a, 0xfe, 0xaf, - 0x09, 0x28, 0x26, 0x74, 0x16, 0xc5, 0x81, 0x14, 0xde, 0xd3, 0x84, 0x84, 0xba, 0x34, 0x26, 0x9a, - 0xb3, 0x0b, 0x1c, 0x11, 0x2f, 0x0c, 0xd4, 0xaf, 0x90, 0xd9, 0x7f, 0x55, 0xe1, 0xce, 0xa9, 0x47, - 0xa8, 0x23, 0x0e, 0x12, 0x07, 0xff, 0x12, 0x63, 0x42, 0xd1, 0x1e, 0xd4, 0x7d, 0x6f, 0xe5, 0x51, - 0xb3, 0xd2, 0xaf, 0x0c, 0x0c, 0x47, 0x2c, 0xd0, 0x3e, 0x34, 0xc2, 0xe5, 0x92, 0x60, 0x6a, 0x56, - 0xfb, 0x95, 0x41, 0xdb, 0x91, 0x2b, 0xf4, 0x0d, 0x34, 0x49, 0x18, 0xd1, 0xd9, 0xf9, 0xa5, 0x69, - 0xf4, 0x2b, 0x83, 0xee, 0xe8, 0xa3, 0x61, 0x1e, 0x4e, 0x43, 0xe6, 0x69, 0x1a, 0x46, 0x74, 0xc8, - 0xfe, 0x3c, 0xb9, 0x74, 0x1a, 0x84, 0xff, 0x32, 0xbb, 0x4b, 0xcf, 0xa7, 0x38, 0x32, 0x6b, 0xc2, - 0xae, 0x58, 0xa1, 0x63, 0x00, 0x6e, 0x37, 0x8c, 0x16, 0x38, 0x32, 0xeb, 0xdc, 0xf4, 0xa0, 0x84, - 0xe9, 0xe7, 0x4c, 0xdf, 0x69, 0x13, 0xf5, 0x89, 0xbe, 0x86, 0x5d, 0x01, 0xc9, 0x6c, 0x1e, 0x2e, - 0x30, 0x31, 0x1b, 0x7d, 0x63, 0xd0, 0x1d, 0xdd, 0x13, 0xa6, 0x14, 0xfc, 0x53, 0x01, 0xda, 0x38, - 0x5c, 0x60, 0xa7, 0x23, 0xd4, 0xd9, 0x37, 0x41, 0xf7, 0xa1, 0x1d, 0xb8, 0x2b, 0x4c, 0xd6, 0xee, - 0x1c, 0x9b, 0x4d, 0x1e, 0xe1, 0xd5, 0x86, 0x1d, 0x40, 0x4b, 0x39, 0xb7, 0x9f, 0x40, 0x43, 0xa4, - 0x86, 0x3a, 0xd0, 0x7c, 0x79, 0xf6, 0xdd, 0xd9, 0xf3, 0x1f, 0xce, 0x7a, 0x3b, 0xa8, 0x05, 0xb5, - 0xb3, 0xa3, 0xef, 0x27, 0xbd, 0x0a, 0xba, 0x0d, 0xb7, 0x4e, 0x8f, 0xa6, 0x2f, 0x66, 0xce, 0xe4, - 0x74, 0x72, 0x34, 0x9d, 0x3c, 0xed, 0x55, 0x51, 0x17, 0x60, 0x7c, 0x72, 0xe4, 0xbc, 0x98, 0x71, - 0x15, 0xc3, 0x7e, 0x1f, 0xda, 0x49, 0x0e, 0xa8, 0x09, 0xc6, 0xd1, 0x74, 0x2c, 0x4c, 0x3c, 0x9d, - 0x4c, 0xc7, 0xbd, 0x8a, 0xfd, 0x47, 0x05, 0xf6, 0x74, 0xca, 0xc8, 0x3a, 0x0c, 0x08, 0x66, 0x9c, - 0xcd, 0xc3, 0x38, 0x48, 0x38, 0xe3, 0x0b, 0x84, 0xa0, 0x16, 0xe0, 0x77, 0x8a, 0x31, 0xfe, 0xcd, - 0x34, 0x69, 0x48, 0x5d, 0x9f, 0xb3, 0x65, 0x38, 0x62, 0x81, 0x3e, 0x87, 0x96, 0x84, 0x82, 0x98, - 0xb5, 0xbe, 0x31, 0xe8, 0x8c, 0xee, 0xea, 0x00, 0x49, 0x8f, 0x4e, 0xa2, 0x66, 0x1f, 0xc3, 0xc1, - 0x31, 0x56, 0x91, 0x08, 0xfc, 0xd4, 0x0d, 0x62, 0x7e, 0xdd, 0x15, 0xe6, 0xc1, 0x30, 0xbf, 0xee, - 0x0a, 0x23, 0x13, 0x9a, 0xf2, 0xfa, 0xf1, 0x70, 0xea, 0x8e, 0x5a, 0xda, 0x14, 0xcc, 0x4d, 0x43, - 0x32, 0xaf, 0x3c, 0x4b, 0x1f, 0x43, 0x8d, 0x55, 0x06, 0x37, 0xd3, 0x19, 0x21, 0x3d, 0xce, 0x67, - 0xc1, 0x32, 0x74, 0xb8, 0x5c, 0xa7, 0xce, 0xc8, 0x52, 0x77, 0x92, 0xf6, 0x3a, 0x0e, 0x03, 0x8a, - 0x03, 0x7a, 0xb3, 0xf8, 0x4f, 0xe1, 0x5e, 0x8e, 0x25, 0x99, 0xc0, 0x21, 0x34, 0x65, 0x68, 0xdc, - 0x5a, 0x21, 0xae, 0x4a, 0xcb, 0xfe, 0xcd, 0x80, 0xbd, 0x97, 0xeb, 0x85, 0x4b, 0xb1, 0x12, 0x6d, - 0x09, 0xea, 0x01, 0xd4, 0x79, 0x87, 0x91, 0x58, 0xdc, 0x16, 0xb6, 0x45, 0x1b, 0x1a, 0xb3, 0xbf, - 0x8e, 0x90, 0xa3, 0x47, 0xd0, 0xb8, 0x70, 0xfd, 0x18, 0x13, 0x0e, 0x44, 0x82, 0x9a, 0xd4, 0xe4, - 0xed, 0xc9, 0x91, 0x1a, 0xe8, 0x00, 0x9a, 0x8b, 0xe8, 0x92, 0xf5, 0x17, 0x5e, 0x92, 0x2d, 0xa7, - 0xb1, 0x88, 0x2e, 0x9d, 0x38, 0x40, 0x1f, 0xc2, 0xad, 0x85, 0x47, 0xdc, 0x73, 0x1f, 0xcf, 0xde, - 0x84, 0xe1, 0x5b, 0xc2, 0xab, 0xb2, 0xe5, 0xec, 0xca, 0xcd, 0x13, 0xb6, 0x87, 0x2c, 0x76, 0x93, - 0xe6, 0x11, 0x76, 0x29, 0x36, 0x1b, 0x5c, 0x9e, 0xac, 0x19, 0x86, 0xd4, 0x5b, 0xe1, 0x30, 0xa6, - 0xbc, 0x94, 0x0c, 0x47, 0x2d, 0xd1, 0x07, 0xb0, 0x1b, 0x61, 0x82, 0xe9, 0x4c, 0x46, 0xd9, 0xe2, - 0x27, 0x3b, 0x7c, 0xef, 0x95, 0x08, 0x0b, 0x41, 0xed, 0x57, 0xd7, 0xa3, 0x66, 0x9b, 0x8b, 0xf8, - 0xb7, 0x38, 0x16, 0x13, 0xac, 0x8e, 0x81, 0x3a, 0x16, 0x13, 0x2c, 0x8f, 0xed, 0x41, 0x7d, 0x19, - 0x46, 0x73, 0x6c, 0x76, 0xb8, 0x4c, 0x2c, 0x50, 0x1f, 0x3a, 0x0b, 0x4c, 0xe6, 0x91, 0xb7, 0xa6, - 0x8c, 0xd1, 0x5d, 0x8e, 0x69, 0x7a, 0xcb, 0x3e, 0x81, 0xbb, 0x19, 0x1a, 0x6e, 0xca, 0xe8, 0xef, - 0x55, 0xd8, 0x77, 0x42, 0xdf, 0x3f, 0x77, 0xe7, 0x6f, 0x4b, 0x70, 0x9a, 0x82, 0xbf, 0xba, 0x1d, - 0x7e, 0x23, 0x07, 0xfe, 0xd4, 0x35, 0xad, 0x69, 0xd7, 0x54, 0x23, 0xa6, 0x5e, 0x4c, 0x4c, 0x43, - 0x27, 0x46, 0xa1, 0xde, 0x4c, 0xa1, 0x9e, 0x40, 0xda, 0xda, 0x02, 0x69, 0x7b, 0x13, 0xd2, 0x6f, - 0xe1, 0x60, 0x03, 0x87, 0x9b, 0x82, 0xfa, 0x4f, 0x15, 0xee, 0x3e, 0x0b, 0x08, 0x75, 0x7d, 0x3f, - 0x83, 0x69, 0x52, 0x13, 0x95, 0xd2, 0x35, 0x51, 0xfd, 0x2f, 0x35, 0x61, 0x68, 0xa4, 0x28, 0x06, - 0x6b, 0x29, 0x06, 0x4b, 0xd5, 0x89, 0xd6, 0x9d, 0x1a, 0x99, 0xee, 0x84, 0xde, 0x03, 0x10, 0x17, - 0x9b, 0x1b, 0x17, 0xe0, 0xb7, 0xf9, 0xce, 0x99, 0x6c, 0x46, 0x8a, 0xaf, 0x56, 0x3e, 0x5f, 0xe9, - 0x2a, 0x19, 0x40, 0x4f, 0xc5, 0x33, 0x8f, 0x16, 0x3c, 0x26, 0x59, 0x29, 0x5d, 0xb9, 0x3f, 0x8e, - 0x16, 0x2c, 0xaa, 0x2c, 0x87, 0x9d, 0x4d, 0x0e, 0x9f, 0xc1, 0x7e, 0x16, 0xf6, 0x9b, 0x52, 0xf8, - 0x67, 0x05, 0x0e, 0x5e, 0x06, 0x5e, 0x2e, 0x89, 0x79, 0x85, 0xb1, 0x01, 0x6b, 0x35, 0x07, 0xd6, - 0x3d, 0xa8, 0xaf, 0xe3, 0xe8, 0x35, 0x96, 0x34, 0x89, 0x45, 0x1a, 0xaf, 0x9a, 0x8e, 0x57, 0x26, - 0xe3, 0xfa, 0x66, 0xc6, 0x33, 0x30, 0x37, 0xa3, 0xbc, 0x61, 0xce, 0x2c, 0xaf, 0xe4, 0xed, 0x6a, - 0x8b, 0x77, 0xca, 0xbe, 0x03, 0xb7, 0x8f, 0x31, 0x7d, 0x25, 0xca, 0x54, 0x02, 0x60, 0x4f, 0x00, - 0xa5, 0x37, 0xaf, 0xfc, 0xc9, 0x2d, 0xdd, 0x9f, 0x1a, 0xec, 0x94, 0xbe, 0xd2, 0xb2, 0xbf, 0xe2, - 0xb6, 0x4f, 0x3c, 0x42, 0xc3, 0xe8, 0x72, 0x1b, 0xb8, 0x3d, 0x30, 0x56, 0xee, 0x3b, 0xf9, 0xb4, - 0xb1, 0x4f, 0xfb, 0x98, 0x47, 0x90, 0x1c, 0x95, 0x11, 0xa4, 0x07, 0x85, 0x4a, 0xb9, 0x41, 0xe1, - 0x1d, 0xa0, 0x17, 0x38, 0x99, 0x59, 0xae, 0x79, 0x63, 0x15, 0x4d, 0x55, 0x9d, 0x26, 0x13, 0x9a, - 0x73, 0x1f, 0xbb, 0x41, 0xbc, 0x96, 0xc4, 0xaa, 0x25, 0x6b, 0x6b, 0x6b, 0x37, 0x72, 0x7d, 0x1f, - 0xfb, 0xf2, 0xb9, 0x4a, 0xd6, 0xf6, 0x4f, 0x70, 0x47, 0xf3, 0x2c, 0x73, 0x60, 0xb9, 0x92, 0xd7, - 0xd2, 0x33, 0xfb, 0x44, 0x5f, 0x42, 0x43, 0x0c, 0x7d, 0xdc, 0x6f, 0x77, 0x74, 0x5f, 0xcf, 0x89, - 0x1b, 0x89, 0x03, 0x39, 0x25, 0x3a, 0x52, 0x77, 0xf4, 0x77, 0x0b, 0xba, 0x6a, 0x6c, 0x11, 0x23, - 0x29, 0xf2, 0x60, 0x37, 0x3d, 0x9f, 0xa1, 0x87, 0xc5, 0x13, 0x6b, 0x66, 0xec, 0xb6, 0x1e, 0x95, - 0x51, 0x15, 0x19, 0xd8, 0x3b, 0x9f, 0x55, 0x10, 0x81, 0x5e, 0x76, 0x6c, 0x42, 0x8f, 0xf3, 0x6d, - 0x14, 0xcc, 0x69, 0xd6, 0xb0, 0xac, 0xba, 0x72, 0x8b, 0x2e, 0xf8, 0x7d, 0xd2, 0x67, 0x1d, 0x74, - 0xad, 0x19, 0x7d, 0xbc, 0xb2, 0x0e, 0x4b, 0xeb, 0x27, 0x7e, 0x7f, 0x86, 0x5b, 0xda, 0x6b, 0x8c, - 0x0a, 0xd0, 0xca, 0x9b, 0x9c, 0xac, 0x4f, 0x4a, 0xe9, 0x26, 0xbe, 0x56, 0xd0, 0xd5, 0x5b, 0x1c, - 0x2a, 0x30, 0x90, 0xfb, 0xfe, 0x58, 0x9f, 0x96, 0x53, 0x4e, 0xdc, 0x11, 0xe8, 0x65, 0xfb, 0x4b, - 0x11, 0x8f, 0x05, 0xdd, 0xb2, 0x88, 0xc7, 0xa2, 0xb6, 0x65, 0xef, 0x20, 0x17, 0xe0, 0xaa, 0xbd, - 0xa0, 0x07, 0x85, 0x84, 0xe8, 0x5d, 0xc9, 0x1a, 0x5c, 0xaf, 0x98, 0xb8, 0x58, 0xc3, 0xff, 0x32, - 0xaf, 0x3d, 0x2a, 0x80, 0x26, 0x7f, 0x38, 0xb2, 0x1e, 0x97, 0xd4, 0xce, 0x24, 0x25, 0x3b, 0xd6, - 0x96, 0xa4, 0xf4, 0x76, 0xb8, 0x25, 0xa9, 0x4c, 0xf3, 0xb3, 0x77, 0x90, 0x07, 0x5d, 0x27, 0x0e, - 0xa4, 0x6b, 0xd6, 0x16, 0x50, 0xc1, 0xe9, 0xcd, 0x8e, 0x67, 0x3d, 0x2c, 0xa1, 0x79, 0x55, 0xdf, - 0x4f, 0xe0, 0xc7, 0x96, 0x52, 0x3d, 0x6f, 0xf0, 0xff, 0xd8, 0xbf, 0xf8, 0x37, 0x00, 0x00, 0xff, - 0xff, 0xb6, 0x48, 0x98, 0x76, 0x9f, 0x10, 0x00, 0x00, + // 1308 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x57, 0xed, 0x6e, 0x1b, 0x45, + 0x17, 0x8e, 0xbd, 0xfe, 0x3c, 0x4e, 0xfc, 0xba, 0xd3, 0x34, 0xd9, 0xee, 0x5b, 0x50, 0x58, 0x04, + 0x75, 0x0b, 0x75, 0xc0, 0xf0, 0x07, 0x09, 0x21, 0xa5, 0xae, 0x95, 0x14, 0x82, 0x2b, 0xad, 0xdb, + 0x22, 0x21, 0x21, 0x6b, 0x63, 0x8f, 0xdb, 0xa5, 0xeb, 0x5d, 0xb3, 0x33, 0x1b, 0x9a, 0x1b, 0x40, + 0xe2, 0x27, 0x97, 0x80, 0xc4, 0x85, 0x70, 0x1f, 0xdc, 0x0c, 0x9a, 0xaf, 0xcd, 0xce, 0x7a, 0xd7, + 0x5d, 0xf2, 0x27, 0xde, 0x99, 0x73, 0xe6, 0x7c, 0x3c, 0xcf, 0x9c, 0x33, 0x27, 0x60, 0xbd, 0x76, + 0xd7, 0xde, 0x31, 0xc1, 0xd1, 0xa5, 0x37, 0xc7, 0xe4, 0x98, 0x7a, 0xbe, 0x8f, 0xa3, 0xc1, 0x3a, + 0x0a, 0x69, 0x88, 0xf6, 0x99, 0x6c, 0xa0, 0x64, 0x03, 0x21, 0xb3, 0x0e, 0xf8, 0x89, 0xf9, 0x6b, + 0x37, 0xa2, 0xe2, 0xaf, 0xd0, 0xb6, 0x0e, 0xd3, 0xfb, 0x61, 0xb0, 0xf4, 0x5e, 0x49, 0x81, 0x70, + 0x11, 0x61, 0x1f, 0xbb, 0x04, 0xab, 0x5f, 0xed, 0x90, 0x92, 0x79, 0xc1, 0x32, 0x94, 0x82, 0xff, + 0x6b, 0x02, 0x8a, 0x09, 0x9d, 0x45, 0x71, 0x20, 0x85, 0x77, 0x35, 0x21, 0xa1, 0x2e, 0x8d, 0x89, + 0xe6, 0xec, 0x12, 0x47, 0xc4, 0x0b, 0x03, 0xf5, 0x2b, 0x64, 0xf6, 0xdf, 0x55, 0xb8, 0x7d, 0xee, + 0x11, 0xea, 0x88, 0x83, 0xc4, 0xc1, 0xbf, 0xc4, 0x98, 0x50, 0xb4, 0x0f, 0x75, 0xdf, 0x5b, 0x79, + 0xd4, 0xac, 0x1c, 0x55, 0xfa, 0x86, 0x23, 0x16, 0xe8, 0x00, 0x1a, 0xe1, 0x72, 0x49, 0x30, 0x35, + 0xab, 0x47, 0x95, 0x7e, 0xdb, 0x91, 0x2b, 0xf4, 0x0d, 0x34, 0x49, 0x18, 0xd1, 0xd9, 0xc5, 0x95, + 0x69, 0x1c, 0x55, 0xfa, 0xdd, 0xe1, 0x47, 0x83, 0x3c, 0x9c, 0x06, 0xcc, 0xd3, 0x34, 0x8c, 0xe8, + 0x80, 0xfd, 0x79, 0x7c, 0xe5, 0x34, 0x08, 0xff, 0x65, 0x76, 0x97, 0x9e, 0x4f, 0x71, 0x64, 0xd6, + 0x84, 0x5d, 0xb1, 0x42, 0xa7, 0x00, 0xdc, 0x6e, 0x18, 0x2d, 0x70, 0x64, 0xd6, 0xb9, 0xe9, 0x7e, + 0x09, 0xd3, 0xcf, 0x98, 0xbe, 0xd3, 0x26, 0xea, 0x13, 0x7d, 0x0d, 0xbb, 0x02, 0x92, 0xd9, 0x3c, + 0x5c, 0x60, 0x62, 0x36, 0x8e, 0x8c, 0x7e, 0x77, 0x78, 0x57, 0x98, 0x52, 0xf0, 0x4f, 0x05, 0x68, + 0xa3, 0x70, 0x81, 0x9d, 0x8e, 0x50, 0x67, 0xdf, 0x04, 0xdd, 0x83, 0x76, 0xe0, 0xae, 0x30, 0x59, + 0xbb, 0x73, 0x6c, 0x36, 0x79, 0x84, 0xd7, 0x1b, 0x76, 0x00, 0x2d, 0xe5, 0xdc, 0x7e, 0x0c, 0x0d, + 0x91, 0x1a, 0xea, 0x40, 0xf3, 0xc5, 0xe4, 0xbb, 0xc9, 0xb3, 0x1f, 0x26, 0xbd, 0x1d, 0xd4, 0x82, + 0xda, 0xe4, 0xe4, 0xfb, 0x71, 0xaf, 0x82, 0x6e, 0xc1, 0xde, 0xf9, 0xc9, 0xf4, 0xf9, 0xcc, 0x19, + 0x9f, 0x8f, 0x4f, 0xa6, 0xe3, 0x27, 0xbd, 0x2a, 0xea, 0x02, 0x8c, 0xce, 0x4e, 0x9c, 0xe7, 0x33, + 0xae, 0x62, 0xd8, 0xef, 0x43, 0x3b, 0xc9, 0x01, 0x35, 0xc1, 0x38, 0x99, 0x8e, 0x84, 0x89, 0x27, + 0xe3, 0xe9, 0xa8, 0x57, 0xb1, 0x7f, 0xaf, 0xc0, 0xbe, 0x4e, 0x19, 0x59, 0x87, 0x01, 0xc1, 0x8c, + 0xb3, 0x79, 0x18, 0x07, 0x09, 0x67, 0x7c, 0x81, 0x10, 0xd4, 0x02, 0xfc, 0x56, 0x31, 0xc6, 0xbf, + 0x99, 0x26, 0x0d, 0xa9, 0xeb, 0x73, 0xb6, 0x0c, 0x47, 0x2c, 0xd0, 0xe7, 0xd0, 0x92, 0x50, 0x10, + 0xb3, 0x76, 0x64, 0xf4, 0x3b, 0xc3, 0x3b, 0x3a, 0x40, 0xd2, 0xa3, 0x93, 0xa8, 0xd9, 0xa7, 0x70, + 0x78, 0x8a, 0x55, 0x24, 0x02, 0x3f, 0x75, 0x83, 0x98, 0x5f, 0x77, 0x85, 0x79, 0x30, 0xcc, 0xaf, + 0xbb, 0xc2, 0xc8, 0x84, 0xa6, 0xbc, 0x7e, 0x3c, 0x9c, 0xba, 0xa3, 0x96, 0x36, 0x05, 0x73, 0xd3, + 0x90, 0xcc, 0x2b, 0xcf, 0xd2, 0xc7, 0x50, 0x63, 0x95, 0xc1, 0xcd, 0x74, 0x86, 0x48, 0x8f, 0xf3, + 0x69, 0xb0, 0x0c, 0x1d, 0x2e, 0xd7, 0xa9, 0x33, 0xb2, 0xd4, 0x9d, 0xa5, 0xbd, 0x8e, 0xc2, 0x80, + 0xe2, 0x80, 0xde, 0x2c, 0xfe, 0x73, 0xb8, 0x9b, 0x63, 0x49, 0x26, 0x70, 0x0c, 0x4d, 0x19, 0x1a, + 0xb7, 0x56, 0x88, 0xab, 0xd2, 0xb2, 0xff, 0x34, 0x60, 0xff, 0xc5, 0x7a, 0xe1, 0x52, 0xac, 0x44, + 0x5b, 0x82, 0xba, 0x0f, 0x75, 0xde, 0x61, 0x24, 0x16, 0xb7, 0x84, 0x6d, 0xd1, 0x86, 0x46, 0xec, + 0xaf, 0x23, 0xe4, 0xe8, 0x21, 0x34, 0x2e, 0x5d, 0x3f, 0xc6, 0x84, 0x03, 0x91, 0xa0, 0x26, 0x35, + 0x79, 0x7b, 0x72, 0xa4, 0x06, 0x3a, 0x84, 0xe6, 0x22, 0xba, 0x62, 0xfd, 0x85, 0x97, 0x64, 0xcb, + 0x69, 0x2c, 0xa2, 0x2b, 0x27, 0x0e, 0xd0, 0x87, 0xb0, 0xb7, 0xf0, 0x88, 0x7b, 0xe1, 0xe3, 0xd9, + 0xeb, 0x30, 0x7c, 0x43, 0x78, 0x55, 0xb6, 0x9c, 0x5d, 0xb9, 0x79, 0xc6, 0xf6, 0x90, 0xc5, 0x6e, + 0xd2, 0x3c, 0xc2, 0x2e, 0xc5, 0x66, 0x83, 0xcb, 0x93, 0x35, 0xc3, 0x90, 0x7a, 0x2b, 0x1c, 0xc6, + 0x94, 0x97, 0x92, 0xe1, 0xa8, 0x25, 0xfa, 0x00, 0x76, 0x23, 0x4c, 0x30, 0x9d, 0xc9, 0x28, 0x5b, + 0xfc, 0x64, 0x87, 0xef, 0xbd, 0x14, 0x61, 0x21, 0xa8, 0xfd, 0xea, 0x7a, 0xd4, 0x6c, 0x73, 0x11, + 0xff, 0x16, 0xc7, 0x62, 0x82, 0xd5, 0x31, 0x50, 0xc7, 0x62, 0x82, 0xe5, 0xb1, 0x7d, 0xa8, 0x2f, + 0xc3, 0x68, 0x8e, 0xcd, 0x0e, 0x97, 0x89, 0x05, 0x3a, 0x82, 0xce, 0x02, 0x93, 0x79, 0xe4, 0xad, + 0x29, 0x63, 0x74, 0x97, 0x63, 0x9a, 0xde, 0x62, 0x79, 0x90, 0xf8, 0x62, 0x12, 0x52, 0x4c, 0xcc, + 0x3d, 0x91, 0x87, 0x5a, 0xdb, 0x67, 0x70, 0x27, 0x43, 0xd1, 0x4d, 0xd9, 0xfe, 0xad, 0x0a, 0x07, + 0x4e, 0xe8, 0xfb, 0x17, 0xee, 0xfc, 0x4d, 0x09, 0xbe, 0x53, 0xd4, 0x54, 0xb7, 0x53, 0x63, 0xe4, + 0x50, 0x93, 0xba, 0xc2, 0x35, 0xed, 0x0a, 0x6b, 0xa4, 0xd5, 0x8b, 0x49, 0x6b, 0xe8, 0xa4, 0x29, + 0x46, 0x9a, 0x29, 0x46, 0x12, 0xb8, 0x5b, 0x5b, 0xe0, 0x6e, 0x6f, 0xc0, 0x6d, 0x7f, 0x0b, 0x87, + 0x1b, 0x38, 0xdc, 0x14, 0xd4, 0x3f, 0x0c, 0xb8, 0xf3, 0x34, 0x20, 0xd4, 0xf5, 0xfd, 0x0c, 0xa6, + 0x49, 0xbd, 0x54, 0x4a, 0xd7, 0x4b, 0xf5, 0xbf, 0xd4, 0x8b, 0xa1, 0x91, 0xa2, 0x18, 0xac, 0xa5, + 0x18, 0x2c, 0x55, 0x43, 0x5a, 0xe7, 0x6a, 0x64, 0x3a, 0x17, 0x7a, 0x0f, 0x40, 0x5c, 0x7a, 0x6e, + 0x5c, 0x80, 0xdf, 0xe6, 0x3b, 0x13, 0xd9, 0xa8, 0x14, 0x5f, 0xad, 0x7c, 0xbe, 0xd2, 0x15, 0xd4, + 0x87, 0x9e, 0x8a, 0x67, 0x1e, 0x2d, 0x78, 0x4c, 0xb2, 0x8a, 0xba, 0x72, 0x7f, 0x14, 0x2d, 0x58, + 0x54, 0x59, 0x0e, 0x3b, 0xdb, 0x4b, 0x66, 0x37, 0x53, 0x32, 0x4f, 0xe1, 0x20, 0x4b, 0xc9, 0x4d, + 0xe9, 0xfd, 0xab, 0x02, 0x87, 0x2f, 0x02, 0x2f, 0x97, 0xe0, 0xbc, 0xa2, 0xd9, 0x80, 0xbc, 0x9a, + 0x03, 0xf9, 0x3e, 0xd4, 0xd7, 0x71, 0xf4, 0x0a, 0x4b, 0x0a, 0xc5, 0x22, 0x8d, 0x65, 0x4d, 0xc7, + 0x32, 0x83, 0x46, 0x7d, 0xf3, 0x46, 0xcf, 0xc0, 0xdc, 0x8c, 0xf2, 0x86, 0x39, 0xb3, 0xbc, 0x92, + 0x37, 0xaf, 0x2d, 0xde, 0x37, 0xfb, 0x36, 0xdc, 0x3a, 0xc5, 0xf4, 0xa5, 0x28, 0x61, 0x09, 0x80, + 0x3d, 0x06, 0x94, 0xde, 0xbc, 0xf6, 0x27, 0xb7, 0x74, 0x7f, 0x6a, 0x20, 0x54, 0xfa, 0x4a, 0xcb, + 0xfe, 0x8a, 0xdb, 0x3e, 0xf3, 0x08, 0x0d, 0xa3, 0xab, 0x6d, 0xe0, 0xf6, 0xc0, 0x58, 0xb9, 0x6f, + 0xe5, 0x93, 0xc8, 0x3e, 0xed, 0x53, 0x1e, 0x41, 0x72, 0x54, 0x46, 0x90, 0x1e, 0x30, 0x2a, 0xe5, + 0x06, 0x8c, 0xb7, 0x80, 0x9e, 0xe3, 0x64, 0xd6, 0x79, 0xc7, 0xdb, 0xac, 0x68, 0xaa, 0xea, 0x34, + 0x99, 0xd0, 0x9c, 0xfb, 0xd8, 0x0d, 0xe2, 0xb5, 0x24, 0x56, 0x2d, 0xd9, 0x65, 0x5d, 0xbb, 0x91, + 0xeb, 0xfb, 0xd8, 0x97, 0xcf, 0x5c, 0xb2, 0xb6, 0x7f, 0x82, 0xdb, 0x9a, 0x67, 0x99, 0x03, 0xcb, + 0x95, 0xbc, 0x92, 0x9e, 0xd9, 0x27, 0xfa, 0x12, 0x1a, 0x62, 0x58, 0xe4, 0x7e, 0xbb, 0xc3, 0x7b, + 0x7a, 0x4e, 0xdc, 0x48, 0x1c, 0xc8, 0xe9, 0xd2, 0x91, 0xba, 0xc3, 0x7f, 0x5a, 0xd0, 0x55, 0xe3, + 0x8e, 0x18, 0x65, 0x91, 0x07, 0xbb, 0xe9, 0xb9, 0x0e, 0x3d, 0x28, 0x9e, 0x74, 0x33, 0xe3, 0xba, + 0xf5, 0xb0, 0x8c, 0xaa, 0xc8, 0xc0, 0xde, 0xf9, 0xac, 0x82, 0x08, 0xf4, 0xb2, 0xe3, 0x16, 0x7a, + 0x94, 0x6f, 0xa3, 0x60, 0xbe, 0xb3, 0x06, 0x65, 0xd5, 0x95, 0x5b, 0x74, 0xc9, 0xef, 0x93, 0x3e, + 0x23, 0xa1, 0x77, 0x9a, 0xd1, 0xc7, 0x32, 0xeb, 0xb8, 0xb4, 0x7e, 0xe2, 0xf7, 0x67, 0xd8, 0xd3, + 0x5e, 0x6a, 0x54, 0x80, 0x56, 0xde, 0xc4, 0x65, 0x7d, 0x52, 0x4a, 0x37, 0xf1, 0xb5, 0x82, 0xae, + 0xde, 0xe2, 0x50, 0x81, 0x81, 0xdc, 0xb7, 0xc9, 0xfa, 0xb4, 0x9c, 0x72, 0xe2, 0x8e, 0x40, 0x2f, + 0xdb, 0x5f, 0x8a, 0x78, 0x2c, 0xe8, 0x96, 0x45, 0x3c, 0x16, 0xb5, 0x2d, 0x7b, 0x07, 0xb9, 0x00, + 0xd7, 0xed, 0x05, 0xdd, 0x2f, 0x24, 0x44, 0xef, 0x4a, 0x56, 0xff, 0xdd, 0x8a, 0x89, 0x8b, 0x35, + 0xfc, 0x2f, 0x33, 0x09, 0xa0, 0x02, 0x68, 0xf2, 0x07, 0x27, 0xeb, 0x51, 0x49, 0xed, 0x4c, 0x52, + 0xb2, 0x63, 0x6d, 0x49, 0x4a, 0x6f, 0x87, 0x5b, 0x92, 0xca, 0x34, 0x3f, 0x7b, 0x07, 0x79, 0xd0, + 0x75, 0xe2, 0x40, 0xba, 0x66, 0x6d, 0x01, 0x15, 0x9c, 0xde, 0xec, 0x78, 0xd6, 0x83, 0x12, 0x9a, + 0xd7, 0xf5, 0xfd, 0x18, 0x7e, 0x6c, 0x29, 0xd5, 0x8b, 0x06, 0xff, 0x4f, 0xff, 0x8b, 0x7f, 0x03, + 0x00, 0x00, 0xff, 0xff, 0x30, 0x18, 0x95, 0x9c, 0xd7, 0x10, 0x00, 0x00, } From f5986db184cf6d16dcd48760ac749a20236fb845 Mon Sep 17 00:00:00 2001 From: liaoj Date: Wed, 13 Feb 2019 01:02:09 +0800 Subject: [PATCH 104/146] fix: helm fetch wrong version chart (#4850) when customer use --version flag, the version format include the Build metadata, the metadata will be ingorned Signed-off-by: jliao --- pkg/repo/index.go | 9 +++++++++ pkg/repo/index_test.go | 20 +++++++++++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/pkg/repo/index.go b/pkg/repo/index.go index 9031463f3..ac19528fa 100644 --- a/pkg/repo/index.go +++ b/pkg/repo/index.go @@ -168,6 +168,15 @@ func (i IndexFile) Get(name, version string) (*ChartVersion, error) { } } + // when customer input exact version, check whether have exact match one first + if len(version) != 0 { + for _, ver := range vs { + if version == ver.Version { + return ver, nil + } + } + } + for _, ver := range vs { test, err := semver.NewVersion(ver.Version) if err != nil { diff --git a/pkg/repo/index_test.go b/pkg/repo/index_test.go index 7c9239b7a..7e9998a4d 100644 --- a/pkg/repo/index_test.go +++ b/pkg/repo/index_test.go @@ -20,6 +20,7 @@ import ( "io/ioutil" "os" "path/filepath" + "strings" "testing" "k8s.io/helm/pkg/getter" @@ -39,14 +40,17 @@ func TestIndexFile(t *testing.T) { i.Add(&chart.Metadata{Name: "cutter", Version: "0.1.1"}, "cutter-0.1.1.tgz", "http://example.com/charts", "sha256:1234567890abc") i.Add(&chart.Metadata{Name: "cutter", Version: "0.1.0"}, "cutter-0.1.0.tgz", "http://example.com/charts", "sha256:1234567890abc") i.Add(&chart.Metadata{Name: "cutter", Version: "0.2.0"}, "cutter-0.2.0.tgz", "http://example.com/charts", "sha256:1234567890abc") + i.Add(&chart.Metadata{Name: "setter", Version: "0.1.9+alpha"}, "setter-0.1.9+alpha.tgz", "http://example.com/charts", "sha256:1234567890abc") + i.Add(&chart.Metadata{Name: "setter", Version: "0.1.9+beta"}, "setter-0.1.9+beta.tgz", "http://example.com/charts", "sha256:1234567890abc") + i.SortEntries() if i.APIVersion != APIVersionV1 { t.Error("Expected API version v1") } - if len(i.Entries) != 2 { - t.Errorf("Expected 2 charts. Got %d", len(i.Entries)) + if len(i.Entries) != 3 { + t.Errorf("Expected 3 charts. Got %d", len(i.Entries)) } if i.Entries["clipper"][0].Name != "clipper" { @@ -54,13 +58,23 @@ func TestIndexFile(t *testing.T) { } if len(i.Entries["cutter"]) != 3 { - t.Error("Expected two cutters.") + t.Error("Expected three cutters.") } // Test that the sort worked. 0.2 should be at the first index for Cutter. if v := i.Entries["cutter"][0].Version; v != "0.2.0" { t.Errorf("Unexpected first version: %s", v) } + + cv, err := i.Get("setter", "0.1.9") + if err == nil && strings.Index(cv.Metadata.Version, "0.1.9") < 0 { + t.Errorf("Unexpected version: %s", cv.Metadata.Version) + } + + cv, err = i.Get("setter", "0.1.9+alpha") + if err != nil || cv.Metadata.Version != "0.1.9+alpha" { + t.Errorf("Expected version: 0.1.9+alpha") + } } func TestLoadIndex(t *testing.T) { From 5b38cc2d888218b74a8ba1cef4341e7a18e1df26 Mon Sep 17 00:00:00 2001 From: Matt Butcher Date: Tue, 12 Feb 2019 13:54:11 -0700 Subject: [PATCH 105/146] ref: Update Sprig to 2.18.0 (#5300) * ref: Update Sprig to 2.18.0 This fixes a problem with Go 1.11 and also adds some new functions. Signed-off-by: Matt Butcher * Added the glide.lock file. Signed-off-by: Matt Butcher --- glide.lock | 10 +++++----- glide.yaml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/glide.lock b/glide.lock index 1fa7c3d95..792ef28cd 100644 --- a/glide.lock +++ b/glide.lock @@ -1,13 +1,11 @@ -hash: 5dc21cc57b38ab1076f9e12d1e4248047ccc4470af8f81c8560560cb492bee9e -updated: 2019-02-08T15:20:12.179155-07:00 +hash: 70f4fe304d0034fd077f122570adc6bb5f40ceee5f4f53d8930ba5ad700a911d +updated: 2019-02-12T13:10:08.039408-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-ansiterm @@ -181,10 +179,12 @@ imports: - jwriter - name: github.com/MakeNowJust/heredoc version: bb23615498cded5e105af4ce27de75b089cbe851 +- name: github.com/Masterminds/goutils + version: 41ac8693c5c10a92ea1ff5ac3a7f95646f6123b0 - name: github.com/Masterminds/semver version: 517734cc7d6470c0d07130e40fd40bdeb9bcd3fd - name: github.com/Masterminds/sprig - version: 544a9b1d90f323f6509491b389714fbbd126bee3 + version: b1fe2752acccf8c3d7f8a1e7c75c7ae7d83a1975 - name: github.com/Masterminds/vcs version: 3084677c2c188840777bff30054f2b553729d329 - name: github.com/mattn/go-runewidth diff --git a/glide.yaml b/glide.yaml index 42c10b347..e482e23c2 100644 --- a/glide.yaml +++ b/glide.yaml @@ -21,7 +21,7 @@ import: - package: github.com/imdario/mergo version: v0.3.5 - package: github.com/Masterminds/sprig - version: ^2.16.0 + version: ^2.18.0 - package: github.com/ghodss/yaml - package: github.com/Masterminds/semver version: ~1.3.1 From c99a3c676a11206352024d7851076106d2840b45 Mon Sep 17 00:00:00 2001 From: tuanvcw Date: Wed, 13 Feb 2019 21:59:17 +0700 Subject: [PATCH 106/146] Update deprecated links in docs (#5302) Signed-off-by: Vu Cong Tuan --- docs/chart_template_guide/control_structures.md | 2 +- docs/chart_template_guide/getting_started.md | 4 ++-- docs/chart_template_guide/wrapping_up.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/chart_template_guide/control_structures.md b/docs/chart_template_guide/control_structures.md index e2f9ca89d..d411c2f79 100644 --- a/docs/chart_template_guide/control_structures.md +++ b/docs/chart_template_guide/control_structures.md @@ -329,7 +329,7 @@ data: - "Onions" ``` -Now, in this example we've done something tricky. The `toppings: |-` line is declaring a multi-line string. So our list of toppings is actually not a YAML list. It's a big string. Why would we do this? Because the data in ConfigMaps `data` is composed of key/value pairs, where both the key and the value are simple strings. To understand why this is the case, take a look at the [Kubernetes ConfigMap docs](http://kubernetes.io/docs/user-guide/configmap/). For us, though, this detail doesn't matter much. +Now, in this example we've done something tricky. The `toppings: |-` line is declaring a multi-line string. So our list of toppings is actually not a YAML list. It's a big string. Why would we do this? Because the data in ConfigMaps `data` is composed of key/value pairs, where both the key and the value are simple strings. To understand why this is the case, take a look at the [Kubernetes ConfigMap docs](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/). For us, though, this detail doesn't matter much. > The `|-` marker in YAML takes a multi-line string. This can be a useful technique for embedding big blocks of data inside of your manifests, as exemplified here. diff --git a/docs/chart_template_guide/getting_started.md b/docs/chart_template_guide/getting_started.md index 87ae5fa3c..eb1d966d3 100644 --- a/docs/chart_template_guide/getting_started.md +++ b/docs/chart_template_guide/getting_started.md @@ -51,8 +51,8 @@ already there. - `NOTES.txt`: The "help text" for your chart. This will be displayed to your users when they run `helm install`. -- `deployment.yaml`: A basic manifest for creating a Kubernetes [deployment](http://kubernetes.io/docs/user-guide/deployments/) -- `service.yaml`: A basic manifest for creating a [service endpoint](http://kubernetes.io/docs/user-guide/services/) for your deployment +- `deployment.yaml`: A basic manifest for creating a Kubernetes [deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) +- `service.yaml`: A basic manifest for creating a [service endpoint](https://kubernetes.io/docs/concepts/services-networking/service/) for your deployment - `_helpers.tpl`: A place to put template helpers that you can re-use throughout the chart And what we're going to do is... _remove them all!_ That way we can work through our tutorial from scratch. We'll actually create our own `NOTES.txt` and `_helpers.tpl` as we go. diff --git a/docs/chart_template_guide/wrapping_up.md b/docs/chart_template_guide/wrapping_up.md index ea5dc1183..c7ecad475 100755 --- a/docs/chart_template_guide/wrapping_up.md +++ b/docs/chart_template_guide/wrapping_up.md @@ -5,7 +5,7 @@ This guide is intended to give you, the chart developer, a strong understanding But there are many things this guide has not covered when it comes to the practical day-to-day development of charts. Here are some useful pointers to other documentation that will help you as you create new charts: - The [Helm Charts project](https://github.com/helm/charts) is an indispensable source of charts. That project is also sets the standard for best practices in chart development. -- The Kubernetes [User's Guide](http://kubernetes.io/docs/user-guide/) provides detailed examples of the various resource kinds that you can use, from ConfigMaps and Secrets to DaemonSets and Deployments. +- The Kubernetes [Documentation](https://kubernetes.io/docs/home/) provides detailed examples of the various resource kinds that you can use, from ConfigMaps and Secrets to DaemonSets and Deployments. - The Helm [Charts Guide](../charts.md) explains the workflow of using charts. - The Helm [Chart Hooks Guide](../charts_hooks.md) explains how to create lifecycle hooks. - The Helm [Charts Tips and Tricks](../charts_tips_and_tricks.md) article provides some useful tips for writing charts. From 5464a822ccd6d99da8b25d8ef690263c6d7a2d8c Mon Sep 17 00:00:00 2001 From: Nguyen Van Trung Date: Fri, 15 Feb 2019 12:17:44 +0700 Subject: [PATCH 107/146] Change http to https for security links Signed-off-by: Nguyen Van Trung --- CONTRIBUTING.md | 2 +- docs/chart_best_practices/conventions.md | 2 +- docs/chart_template_guide/yaml_techniques.md | 2 +- docs/charts.md | 4 ++-- docs/developers.md | 4 ++-- docs/glossary.md | 2 +- docs/history.md | 2 +- docs/provenance.md | 6 +++--- docs/related.md | 6 +++--- docs/release_checklist.md | 2 +- docs/using_helm.md | 4 ++-- 11 files changed, 18 insertions(+), 18 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7736cbd6b..a20c2b90b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -15,7 +15,7 @@ us a chance to try to fix the issue before it is exploited in the wild. The sign-off is a simple line at the end of the explanation for a commit. All commits needs to be signed. Your signature certifies that you wrote the patch or otherwise have the right to contribute the material. The rules are pretty simple, -if you can certify the below (from [developercertificate.org](http://developercertificate.org/)): +if you can certify the below (from [developercertificate.org](https://developercertificate.org/)): ``` Developer Certificate of Origin diff --git a/docs/chart_best_practices/conventions.md b/docs/chart_best_practices/conventions.md index 524928e25..c8bbd7d94 100644 --- a/docs/chart_best_practices/conventions.md +++ b/docs/chart_best_practices/conventions.md @@ -22,7 +22,7 @@ The directory that contains a chart MUST have the same name as the chart. Thus, ## Version Numbers -Wherever possible, Helm uses [SemVer 2](http://semver.org) to represent version numbers. (Note that Docker image tags do not necessarily follow SemVer, and are thus considered an unfortunate exception to the rule.) +Wherever possible, Helm uses [SemVer 2](https://semver.org) to represent version numbers. (Note that Docker image tags do not necessarily follow SemVer, and are thus considered an unfortunate exception to the rule.) When SemVer versions are stored in Kubernetes labels, we conventionally alter the `+` character to an `_` character, as labels do not allow the `+` sign as a value. diff --git a/docs/chart_template_guide/yaml_techniques.md b/docs/chart_template_guide/yaml_techniques.md index 00b33b674..0a84e4a25 100644 --- a/docs/chart_template_guide/yaml_techniques.md +++ b/docs/chart_template_guide/yaml_techniques.md @@ -7,7 +7,7 @@ to read. ## Scalars and Collections -According to the [YAML spec](http://yaml.org/spec/1.2/spec.html), there are two +According to the [YAML spec](https://yaml.org/spec/1.2/spec.html), there are two types of collections, and many scalar types. The two types of collections are maps and sequences: diff --git a/docs/charts.md b/docs/charts.md index 7bc4f0020..d91dfe54e 100644 --- a/docs/charts.md +++ b/docs/charts.md @@ -71,7 +71,7 @@ Other fields will be silently ignored. ### Charts and Versioning Every chart must have a version number. A version must follow the -[SemVer 2](http://semver.org/) standard. Unlike Helm Classic, Kubernetes +[SemVer 2](https://semver.org/) standard. Unlike Helm Classic, Kubernetes Helm uses version numbers as release markers. Packages in repositories are identified by name plus version. @@ -792,7 +792,7 @@ standard references that will help you out. - [Go templates](https://godoc.org/text/template) - [Extra template functions](https://godoc.org/github.com/Masterminds/sprig) -- [The YAML format](http://yaml.org/spec/) +- [The YAML format](https://yaml.org/spec/) ## Using Helm to Manage Charts diff --git a/docs/developers.md b/docs/developers.md index 4edc4bea1..fb704cb17 100644 --- a/docs/developers.md +++ b/docs/developers.md @@ -170,7 +170,7 @@ workflow for doing this is as follows: 5. When you are ready for us to review, sign your commit, push your branch to GitHub, and then open a new pull request with us. -For Git commit messages, we follow the [Semantic Commit Messages](http://karma-runner.github.io/0.13/dev/git-commit-msg.html): +For Git commit messages, we follow the [Semantic Commit Messages](https://karma-runner.github.io/0.13/dev/git-commit-msg.html): ``` fix(helm): add --foo flag to 'helm install' @@ -201,7 +201,7 @@ Common scopes: Read more: - The [Deis Guidelines](https://github.com/deis/workflow/blob/master/src/contributing/submitting-a-pull-request.md) were the inspiration for this section. -- Karma Runner [defines](http://karma-runner.github.io/0.13/dev/git-commit-msg.html) the semantic commit message idea. +- Karma Runner [defines](https://karma-runner.github.io/0.13/dev/git-commit-msg.html) the semantic commit message idea. ### Go Conventions diff --git a/docs/glossary.md b/docs/glossary.md index 875807268..02a5c125f 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -37,7 +37,7 @@ are bundled with it. ## Chart Version Charts are versioned according to the [SemVer 2 -spec](http://semver.org). A version number is required on every chart. +spec](https://semver.org). A version number is required on every chart. ## Chart.yaml diff --git a/docs/history.md b/docs/history.md index 71e63c6b2..1a3d9dbe4 100644 --- a/docs/history.md +++ b/docs/history.md @@ -12,7 +12,7 @@ Differences from Helm Classic: - Helm's chart format has changed for the better: - Dependencies are immutable and stored inside of a chart's `charts/` directory. - - Charts are strongly versioned using [SemVer 2](http://semver.org/spec/v2.0.0.html) + - Charts are strongly versioned using [SemVer 2](https://semver.org/spec/v2.0.0.html) - Charts can be loaded from directories or from chart archive files - Helm supports Go templates without requiring you to run `generate` or `template` commands. diff --git a/docs/provenance.md b/docs/provenance.md index 163e72842..3f259a391 100644 --- a/docs/provenance.md +++ b/docs/provenance.md @@ -180,7 +180,7 @@ The following pieces of provenance data are added: * The signature (SHA256, just like Docker) of the chart package (the .tgz file) is included, and may be used to verify the integrity of the chart package. * The entire body is signed using the algorithm used by PGP (see - [http://keybase.io] for an emerging way of making crypto signing and + [https://keybase.io] for an emerging way of making crypto signing and verification easy). The combination of this gives users the following assurances: @@ -202,7 +202,7 @@ keywords: - proxy source: - https://github.com/foo/bar -home: http://nginx.com +home: https://nginx.com ... files: @@ -221,7 +221,7 @@ first is the Chart.yaml. The second is the checksums, a map of filenames to SHA-256 digests (value shown is fake/truncated) The signature block is a standard PGP signature, which provides [tamper -resistance](http://www.rossde.com/PGP/pgp_signatures.html). +resistance](https://www.rossde.com/PGP/pgp_signatures.html). ## Chart Repositories diff --git a/docs/related.md b/docs/related.md index ba1b0dfbf..a8e494172 100644 --- a/docs/related.md +++ b/docs/related.md @@ -8,9 +8,9 @@ or [pull request](https://github.com/helm/helm/pulls). ## Article, Blogs, How-Tos, and Extra Documentation - [Awesome Helm](https://github.com/cdwv/awesome-helm) - List of awesome Helm resources -- [CI/CD with Kubernetes, Helm & Wercker ](http://www.slideshare.net/Diacode/cicd-with-kubernetes-helm-wercker-madscalability) +- [CI/CD with Kubernetes, Helm & Wercker ](https://www.slideshare.net/Diacode/cicd-with-kubernetes-helm-wercker-madscalability) - [Creating a Helm Plugin in 3 Steps](http://technosophos.com/2017/03/21/creating-a-helm-plugin.html) -- [Deploying Kubernetes Applications with Helm](http://cloudacademy.com/blog/deploying-kubernetes-applications-with-helm/) +- [Deploying Kubernetes Applications with Helm](https://cloudacademy.com/blog/deploying-kubernetes-applications-with-helm/) - [GitLab, Consumer Driven Contracts, Helm and Kubernetes](https://medium.com/@enxebre/gitlab-consumer-driven-contracts-helm-and-kubernetes-b7235a60a1cb#.xwp1y4tgi) - [Honestbee's Helm Chart Conventions](https://gist.github.com/so0k/f927a4b60003cedd101a0911757c605a) - [Releasing backward-incompatible changes: Kubernetes, Jenkins, Prometheus Operator, Helm and Traefik](https://medium.com/@enxebre/releasing-backward-incompatible-changes-kubernetes-jenkins-plugin-prometheus-operator-helm-self-6263ca61a1b1#.e0c7elxhq) @@ -90,7 +90,7 @@ Tools layered on top of Helm or Tiller. Platforms, distributions, and services that include Helm support. - [Fabric8](https://fabric8.io) - Integrated development platform for Kubernetes -- [Jenkins X](http://jenkins-x.io/) - open source automated CI/CD for Kubernetes which uses Helm for [promoting](http://jenkins-x.io/about/features/#promotion) applications through [environments via GitOps](http://jenkins-x.io/about/features/#environments) +- [Jenkins X](https://jenkins-x.io/) - open source automated CI/CD for Kubernetes which uses Helm for [promoting](https://jenkins-x.io/about/features/#promotion) applications through [environments via GitOps](https://jenkins-x.io/about/features/#environments) - [Kubernetic](https://kubernetic.com/) - Kubernetes Desktop Client - [Qstack](https://qstack.com) diff --git a/docs/release_checklist.md b/docs/release_checklist.md index 4011b6675..d1c6c967a 100644 --- a/docs/release_checklist.md +++ b/docs/release_checklist.md @@ -41,7 +41,7 @@ Just kidding! :trollface: All releases will be of the form vX.Y.Z where X is the major version number, Y is the minor version number and Z is the patch release number. This project -strictly follows [semantic versioning](http://semver.org/) so following this +strictly follows [semantic versioning](https://semver.org/) so following this step is critical. It is important to note that this document assumes that the git remote in your diff --git a/docs/using_helm.md b/docs/using_helm.md index db723d993..79b5aef6f 100755 --- a/docs/using_helm.md +++ b/docs/using_helm.md @@ -17,7 +17,7 @@ cluster. Think of it like the Kubernetes equivalent of a Homebrew formula, an Apt dpkg, or a Yum RPM file. A *Repository* is the place where charts can be collected and shared. -It's like Perl's [CPAN archive](http://www.cpan.org) or the +It's like Perl's [CPAN archive](https://www.cpan.org) or the [Fedora Package Database](https://admin.fedoraproject.org/pkgdb/), but for Kubernetes packages. @@ -190,7 +190,7 @@ imageTag: 10.1.14-r3 ## Specify a imagePullPolicy ## Default to 'Always' if imageTag is 'latest', else set to 'IfNotPresent' -## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images +## ref: https://kubernetes.io/docs/user-guide/images/#pre-pulling-images ## # imagePullPolicy: From 9f964c11da1c1ae865aed2be87c1929f04683b82 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 15 Feb 2019 17:28:31 +0000 Subject: [PATCH 108/146] fix: helm display confused error message if version is empty (without quotes) (#5310) Signed-off-by: Alex Gladkikh --- pkg/downloader/chart_downloader.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/downloader/chart_downloader.go b/pkg/downloader/chart_downloader.go index 453e81470..1ef85f501 100644 --- a/pkg/downloader/chart_downloader.go +++ b/pkg/downloader/chart_downloader.go @@ -213,7 +213,7 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, ge cv, err := i.Get(chartName, version) if err != nil { - return u, r.Client, fmt.Errorf("chart %q matching %s not found in %s index. (try 'helm repo update'). %s", chartName, version, r.Config.Name, err) + return u, r.Client, fmt.Errorf("chart %q matching %q not found in %s index. (try 'helm repo update'). %s", chartName, version, r.Config.Name, err) } if len(cv.URLs) == 0 { From 35b782219041d39a56557728b5b6933cca7178d9 Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Fri, 15 Feb 2019 12:48:46 -0500 Subject: [PATCH 109/146] Noting the version as the match element That the match is based on version is implicit. Making it explicit because I had to think when I saw it. Signed-off-by: Matt Farina --- pkg/downloader/chart_downloader.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/downloader/chart_downloader.go b/pkg/downloader/chart_downloader.go index 1ef85f501..563188ec3 100644 --- a/pkg/downloader/chart_downloader.go +++ b/pkg/downloader/chart_downloader.go @@ -213,7 +213,7 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, ge cv, err := i.Get(chartName, version) if err != nil { - return u, r.Client, fmt.Errorf("chart %q matching %q not found in %s index. (try 'helm repo update'). %s", chartName, version, r.Config.Name, err) + return u, r.Client, fmt.Errorf("chart %q matching version %q not found in %s index. (try 'helm repo update'). %s", chartName, version, r.Config.Name, err) } if len(cv.URLs) == 0 { From 63d262e5ec3c1b0d935995c7354b2b239c18ff14 Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Fri, 15 Feb 2019 12:58:23 -0500 Subject: [PATCH 110/146] Display the checksums in CI When Helm is packaging up the bundles it generates the checksums but does not display them. Having them here will aide in the generation of release notes and provide another source listing them. Signed-off-by: Matt Farina --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 0677cafe4..20ce7e5a4 100644 --- a/Makefile +++ b/Makefile @@ -48,6 +48,7 @@ dist: checksum: for f in _dist/*.{gz,zip} ; do \ shasum -a 256 "$${f}" | awk '{print $$1}' > "$${f}.sha256" ; \ + echo -n "Checksum: " && cat $${f}.sha256 ; \ done .PHONY: check-docker From d76eebb319eda349371f561c881ca91cc53907ad Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Fri, 15 Feb 2019 15:22:23 -0500 Subject: [PATCH 111/146] Adding PGP signing to the release process Signed-off-by: Matt Farina --- docs/release_checklist.md | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/docs/release_checklist.md b/docs/release_checklist.md index d1c6c967a..c1595fb58 100644 --- a/docs/release_checklist.md +++ b/docs/release_checklist.md @@ -250,7 +250,21 @@ git tag --sign --annotate "${RELEASE_NAME}" --message "Helm release ${RELEASE_NA git push upstream $RELEASE_NAME ``` -## 7. Write the Release Notes +## 7. PGP Sign the downloads + +While hashes provide a signature that the content of the downloads is what it +was generated, signed packages provide traceability of where the package came +from. + +To do this follow the following steps: + +1. Download each of the release bundles generated by the CI system +2. Sign each of them using GnuPG using the command `gpg --armor --detach-sign [FILE NAME]`. + This will generate a file name `[FILE NAME].asc` with an ascii armored signature. + +Each of the signature files needs to be uploaded to the release on GitHub. + +## 8. Write the Release Notes We will auto-generate a changelog based on the commits that occurred during a release cycle, but it is usually more beneficial to the end-user if the release @@ -286,14 +300,14 @@ The community keeps growing, and we'd love to see you there! Download Helm X.Y. The common platform binaries are here: -- [MacOS amd64](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-darwin-amd64.tar.gz) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-darwin-amd64.tar.gz.sha256)) -- [Linux amd64](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-amd64.tar.gz) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-amd64.tar.gz.sha256)) -- [Linux arm](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-arm.tar.gz) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-arm.tar.gz.sha256)) -- [Linux arm64](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-arm64.tar.gz) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-arm64.tar.gz.sha256)) -- [Linux i386](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-386.tar.gz) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-386.tar.gz.sha256)) -- [Linux ppc64le](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-ppc64le.tar.gz) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-ppc64le.tar.gz.sha256)) -- [Linux s390x](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-s390x.tar.gz) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-s390x.tar.gz.sha256)) -- [Windows amd64](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-windows-amd64.zip) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-windows-amd64.zip.sha256)) +- [MacOS amd64](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-darwin-amd64.tar.gz) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-darwin-amd64.tar.gz.sha256) / CHECKSUM_VAL) +- [Linux amd64](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-amd64.tar.gz) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-amd64.tar.gz.sha256) / CHECKSUM_VAL) +- [Linux arm](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-arm.tar.gz) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-arm.tar.gz.sha256) / CHECKSUM_VAL) +- [Linux arm64](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-arm64.tar.gz) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-arm64.tar.gz.sha256) / CHECKSUM_VAL) +- [Linux i386](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-386.tar.gz) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-386.tar.gz.sha256) / CHECKSUM_VAL) +- [Linux ppc64le](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-ppc64le.tar.gz) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-ppc64le.tar.gz.sha256) / CHECKSUM_VAL) +- [Linux s390x](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-s390x.tar.gz) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-s390x.tar.gz.sha256) / CHECKSUM_VAL) +- [Windows amd64](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-windows-amd64.zip) ([checksum](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-windows-amd64.zip.sha256) / CHECKSUM_VAL) Once you have the client installed, upgrade Tiller with `helm init --upgrade`. @@ -335,7 +349,7 @@ in the example above. Once finished, go into GitHub and edit the release notes for the tagged release with the notes written here. -## 8. Evangelize +## 9. Evangelize Congratulations! You're done. Go grab yourself a $DRINK_OF_CHOICE. You've earned it. From 8224e3348ef004cbff7321e2b26b8fbcd7e190a3 Mon Sep 17 00:00:00 2001 From: Marc Jansen Date: Tue, 19 Feb 2019 13:31:47 +0100 Subject: [PATCH 112/146] Symmetrical asterisks (#5325) Signed-off-by: Marc Jansen --- cmd/helm/repo_update.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/helm/repo_update.go b/cmd/helm/repo_update.go index 1a239b407..42d242b83 100644 --- a/cmd/helm/repo_update.go +++ b/cmd/helm/repo_update.go @@ -124,6 +124,6 @@ func updateCharts(repos []*repo.ChartRepository, out io.Writer, home helmpath.Ho return errors.New("Update Failed. Check log for details") } - fmt.Fprintln(out, "Update Complete. ⎈ Happy Helming!⎈ ") + fmt.Fprintln(out, "Update Complete. ⎈ Happy Helming! ⎈") return nil } From 73a17eb59900348234ad7c4cba75a537dcef9708 Mon Sep 17 00:00:00 2001 From: Miroslav Spousta Date: Tue, 19 Feb 2019 23:46:01 +0100 Subject: [PATCH 113/146] Fix wording in error message (#5322) Signed-off-by: Miroslav Spousta --- pkg/tiller/release_server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/tiller/release_server.go b/pkg/tiller/release_server.go index b85118cd2..ffb922e40 100644 --- a/pkg/tiller/release_server.go +++ b/pkg/tiller/release_server.go @@ -61,7 +61,7 @@ var ( // errInvalidRevision indicates that an invalid release revision number was provided. errInvalidRevision = errors.New("invalid release revision") //errInvalidName indicates that an invalid release name was provided - errInvalidName = errors.New("invalid release name, must match regex ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])+$ and the length must not longer than 53") + errInvalidName = errors.New("invalid release name, must match regex ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])+$ and the length must not be longer than 53") ) // ListDefaultLimit is the default limit for number of items returned in a list. From d24ba97faeb39f692f74c87d183a723b4138ee52 Mon Sep 17 00:00:00 2001 From: Nguyen Hai Truong Date: Wed, 20 Feb 2019 13:29:50 +0700 Subject: [PATCH 114/146] Correct misspelling of Helm Although it is spelling mistakes, it might make an affects while reading. Signed-off-by: Nguyen Hai Truong --- _proto/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_proto/README.md b/_proto/README.md index 0ebd6b6a4..7704572eb 100644 --- a/_proto/README.md +++ b/_proto/README.md @@ -3,7 +3,7 @@ Protobuf3 type declarations for the Helm API Packages - - `hapi.chart` Complete serialization of Heml charts + - `hapi.chart` Complete serialization of Helm charts - `hapi.release` Information about installed charts (Releases) such as metadata about when they were installed, their status, and how they were configured. - `hapi.services.rudder` Definition for the ReleaseModuleService used by Tiller to manipulate releases on a given node - `hapi.services.tiller` Definition of the ReleaseService provided by Tiller and used by Helm clients to manipulate releases cluster wide. From 2ca5d2ab9cf41a23a1d650ae2dc88a44344c898b Mon Sep 17 00:00:00 2001 From: Nguyen Hai Truong Date: Wed, 20 Feb 2019 14:35:35 +0700 Subject: [PATCH 115/146] trivial fix typo Signed-off-by: Nguyen Hai Truong --- docs/tiller_ssl.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tiller_ssl.md b/docs/tiller_ssl.md index 41e704653..3d64635ae 100644 --- a/docs/tiller_ssl.md +++ b/docs/tiller_ssl.md @@ -288,7 +288,7 @@ not available for public resolution. By default, the Helm client connects to Tiller via tunnel (i.e. kube proxy) at 127.0.0.1. During the TLS handshake, a target, usually provided as a hostname (e.g. example.com), is checked against the subject and subject alternative -names of the certificate (i.e. hostname verficiation). However, because of the tunnel, the target is an IP address. +names of the certificate (i.e. hostname verification). However, because of the tunnel, the target is an IP address. Therefore, to validate the certificate, the IP address 127.0.0.1 must be listed as an IP subject alternative name (IP SAN) in the Tiller certificate. From 8f9144332665f1aecb1b29925e70504cfb9210f5 Mon Sep 17 00:00:00 2001 From: Nguyen Hai Truong Date: Thu, 21 Feb 2019 01:25:43 +0700 Subject: [PATCH 116/146] Adding '/usr/bin/env bash' (#5334) This commit aims to add '/usr/bin/env bash' as a shebang line to indicates scripts use bash shell for interpreting. Signed-off-by: Nguyen Hai Truong --- scripts/completions.bash | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/completions.bash b/scripts/completions.bash index c24f3d257..36cb01f15 100644 --- a/scripts/completions.bash +++ b/scripts/completions.bash @@ -1,3 +1,5 @@ +#!/usr/bin/env bash + # bash completion for helm -*- shell-script -*- __debug() From fbc89e13d1e0a92b39d3088dc02f5fdccae48aca Mon Sep 17 00:00:00 2001 From: Nguyen Hai Truong Date: Thu, 21 Feb 2019 01:25:59 +0700 Subject: [PATCH 117/146] The 'Linuxes' is obscure (#5332) Using `Linux distributions` instead of `Linuxes` Signed-off-by: Nguyen Hai Truong --- docs/developers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/developers.md b/docs/developers.md index fb704cb17..70203b2d0 100644 --- a/docs/developers.md +++ b/docs/developers.md @@ -32,7 +32,7 @@ docker-test`. To run Helm and Tiller locally, you can run `bin/helm` or `bin/tiller`. -- Helm and Tiller are known to run on macOS and most Linuxes, including +- Helm and Tiller are known to run on macOS and most Linux distributions, including Alpine. - Tiller must have access to a Kubernetes cluster. It learns about the cluster by examining the Kube config files that `kubectl` uses. From ead111dd4f699b3cb0a56f1e6d4585e3363f925b Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Wed, 20 Feb 2019 10:30:31 -0800 Subject: [PATCH 118/146] add `make sign` and `make fetch-dist` (#5329) Signed-off-by: Matthew Fisher --- Makefile | 15 +++++++++++++++ docs/release_checklist.md | 21 +++++++++++++-------- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 20ce7e5a4..7248bbed2 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,7 @@ DEV_IMAGE ?= golang:1.11 SHORT_NAME ?= tiller SHORT_NAME_RUDDER ?= rudder TARGETS ?= darwin/amd64 linux/amd64 linux/386 linux/arm linux/arm64 linux/ppc64le linux/s390x windows/amd64 +TARGET_OBJS ?= darwin-amd64.tar.gz darwin-amd64.tar.gz.sha256 linux-amd64.tar.gz linux-amd64.tar.gz.sha256 linux-386.tar.gz linux-386.tar.gz.sha256 linux-arm.tar.gz linux-arm.tar.gz.sha256 linux-arm64.tar.gz linux-arm64.tar.gz.sha256 linux-ppc64le.tar.gz linux-ppc64le.tar.gz.sha256 linux-s390x.tar.gz linux-s390x.tar.gz.sha256 windows-amd64.zip windows-amd64.zip.sha256 DIST_DIRS = find * -type d -exec # go option @@ -44,6 +45,20 @@ dist: $(DIST_DIRS) zip -r helm-${VERSION}-{}.zip {} \; \ ) +.PHONY: fetch-dist +fetch-dist: + mkdir -p _dist + cd _dist && \ + for obj in ${TARGET_OBJS} ; do \ + curl -sSL -o helm-${VERSION}-$${obj} https://storage.googleapis.com/kubernetes-helm/helm-${VERSION}-$${obj} ; \ + done + +.PHONY: sign +sign: + for f in _dist/*.{gz,zip,sha256} ; do \ + gpg --armor --detach-sign $${f} ; \ + done + .PHONY: checksum checksum: for f in _dist/*.{gz,zip} ; do \ diff --git a/docs/release_checklist.md b/docs/release_checklist.md index c1595fb58..bddb50ffb 100644 --- a/docs/release_checklist.md +++ b/docs/release_checklist.md @@ -256,13 +256,17 @@ While hashes provide a signature that the content of the downloads is what it was generated, signed packages provide traceability of where the package came from. -To do this follow the following steps: +To do this, run the following `make` commands: -1. Download each of the release bundles generated by the CI system -2. Sign each of them using GnuPG using the command `gpg --armor --detach-sign [FILE NAME]`. - This will generate a file name `[FILE NAME].asc` with an ascii armored signature. +```shell +make clean +make fetch-dist +make sign +``` -Each of the signature files needs to be uploaded to the release on GitHub. +This will generate ascii armored signature files for each of the files pushed by CI. + +All of the signature files need to be uploaded to the release on GitHub. ## 8. Write the Release Notes @@ -322,7 +326,7 @@ The [Quickstart Guide](https://docs.helm.sh/using_helm/#quickstart-guide) will g ### Features - ref(*): kubernetes v1.11 support efadbd88035654b2951f3958167afed014c46bc6 (Adam Reese) -- feat(helm): add $HELM_KEY_PASSPHRASE environment variable for signing helm charts (#4778) 1e26b5300b5166fabb90002535aacd2f9cc7d787 +- feat(helm): add $HELM_KEY_PASSPHRASE environment variable for signing helm charts (#4778) 1e26b5300b5166fabb90002535aacd2f9cc7d787 ### Bug fixes - fix circle not building tags f4f932fabd197f7e6d608c8672b33a483b4b76fa (Matthew Fisher) @@ -346,8 +350,9 @@ git log --no-merges --pretty=format:'- %s %H (%aN)' $PREVIOUS_RELEASE..$RELEASE_ After generating the changelog, you will need to categorize the changes as shown in the example above. -Once finished, go into GitHub and edit the release notes for the tagged release -with the notes written here. +Once finished, go into GitHub and edit the release notes for the tagged release with the notes written here. + +Remember to attach the ascii armored signatures generated in the previous step to the release notes. ## 9. Evangelize From d9d2b3ae4812d756297ac89b8930eee61273c871 Mon Sep 17 00:00:00 2001 From: Nguyen Hai Truong Date: Tue, 26 Feb 2019 22:36:23 +0700 Subject: [PATCH 119/146] Fix many misspelling words (#5357) Although it is spelling mistakes, it might make an affects while reading. Co-Authored-By: Dao Cong Tien tiendc@vn.fujitsu.com Signed-off-by: Nguyen Hai Truong --- cmd/helm/verify.go | 2 +- docs/helm/helm_verify.md | 2 +- docs/man/man1/helm_verify.1 | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/helm/verify.go b/cmd/helm/verify.go index bbc8347c1..6b8e6895d 100644 --- a/cmd/helm/verify.go +++ b/cmd/helm/verify.go @@ -27,7 +27,7 @@ import ( const verifyDesc = ` Verify that the given chart has a valid provenance file. -Provenance files provide crytographic verification that a chart has not been +Provenance files provide cryptographic verification that a chart has not been tampered with, and was packaged by a trusted provider. This command can be used to verify a local chart. Several other commands provide diff --git a/docs/helm/helm_verify.md b/docs/helm/helm_verify.md index 30ed43679..acd1c2923 100644 --- a/docs/helm/helm_verify.md +++ b/docs/helm/helm_verify.md @@ -7,7 +7,7 @@ verify that a chart at the given path has been signed and is valid Verify that the given chart has a valid provenance file. -Provenance files provide crytographic verification that a chart has not been +Provenance files provide cryptographic verification that a chart has not been tampered with, and was packaged by a trusted provider. This command can be used to verify a local chart. Several other commands provide diff --git a/docs/man/man1/helm_verify.1 b/docs/man/man1/helm_verify.1 index 5297924ae..341449ad8 100644 --- a/docs/man/man1/helm_verify.1 +++ b/docs/man/man1/helm_verify.1 @@ -18,7 +18,7 @@ helm\-verify \- verify that a chart at the given path has been signed and is val Verify that the given chart has a valid provenance file. .PP -Provenance files provide crytographic verification that a chart has not been +Provenance files provide cryptographic verification that a chart has not been tampered with, and was packaged by a trusted provider. .PP From 44eba6d28c87a58299d94e0832fb52385923d2d1 Mon Sep 17 00:00:00 2001 From: hnwolf Date: Tue, 26 Feb 2019 22:40:06 +0700 Subject: [PATCH 120/146] Update incorrect link (#5359) Signed-off-by: Nguyen Hung Phuong --- docs/using_helm.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/using_helm.md b/docs/using_helm.md index 79b5aef6f..faf3cc20f 100755 --- a/docs/using_helm.md +++ b/docs/using_helm.md @@ -18,8 +18,8 @@ an Apt dpkg, or a Yum RPM file. A *Repository* is the place where charts can be collected and shared. It's like Perl's [CPAN archive](https://www.cpan.org) or the -[Fedora Package Database](https://admin.fedoraproject.org/pkgdb/), but for -Kubernetes packages. +[Fedora Package Database](https://apps.fedoraproject.org/packages/s/pkgdb), but +for Kubernetes packages. A *Release* is an instance of a chart running in a Kubernetes cluster. One chart can often be installed many times into the same cluster. And From 268695813ba957821e53a784ac849aa3ca7f70a3 Mon Sep 17 00:00:00 2001 From: tuanvcw Date: Tue, 26 Feb 2019 22:41:50 +0700 Subject: [PATCH 121/146] Fix typos in various places (#5360) Signed-off-by: Vu Cong Tuan --- _proto/hapi/release/status.proto | 2 +- pkg/repo/chartrepo_test.go | 2 +- pkg/tiller/release_server.go | 4 ++-- pkg/tlsutil/cfg.go | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/_proto/hapi/release/status.proto b/_proto/hapi/release/status.proto index aa90760b3..e6ccd3d6e 100644 --- a/_proto/hapi/release/status.proto +++ b/_proto/hapi/release/status.proto @@ -29,7 +29,7 @@ message Status { UNKNOWN = 0; // Status_DEPLOYED indicates that the release has been pushed to Kubernetes. DEPLOYED = 1; - // Status_DELETED indicates that a release has been deleted from Kubermetes. + // Status_DELETED indicates that a release has been deleted from Kubernetes. DELETED = 2; // Status_SUPERSEDED indicates that this release object is outdated and a newer one exists. SUPERSEDED = 3; diff --git a/pkg/repo/chartrepo_test.go b/pkg/repo/chartrepo_test.go index a2f1daeb8..ed09b5c6d 100644 --- a/pkg/repo/chartrepo_test.go +++ b/pkg/repo/chartrepo_test.go @@ -175,7 +175,7 @@ func verifyIndex(t *testing.T, actual *IndexFile) { t.Errorf("Expected %q, got %q", e.Version, g.Version) } if len(g.Keywords) != 3 { - t.Error("Expected 3 keyrwords.") + t.Error("Expected 3 keywords.") } if len(g.Maintainers) != 2 { t.Error("Expected 2 maintainers.") diff --git a/pkg/tiller/release_server.go b/pkg/tiller/release_server.go index ffb922e40..eb3e876d0 100644 --- a/pkg/tiller/release_server.go +++ b/pkg/tiller/release_server.go @@ -115,7 +115,7 @@ func NewReleaseServer(env *environment.Environment, clientset kubernetes.Interfa // request values are not altered. func (s *ReleaseServer) reuseValues(req *services.UpdateReleaseRequest, current *release.Release) error { if req.ResetValues { - // If ResetValues is set, we comletely ignore current.Config. + // If ResetValues is set, we completely ignore current.Config. s.Log("resetting values to the chart's original version") return nil } @@ -191,7 +191,7 @@ func (s *ReleaseServer) uniqName(start string, reuse bool) (string, error) { rel := h[0] if st := rel.Info.Status.Code; reuse && (st == release.Status_DELETED || st == release.Status_FAILED) { - // Allowe re-use of names if the previous release is marked deleted. + // Allow re-use of names if the previous release is marked deleted. s.Log("name %s exists but is not in use, reusing name", start) return start, nil } else if reuse { diff --git a/pkg/tlsutil/cfg.go b/pkg/tlsutil/cfg.go index 2c1dfd340..6c2a829df 100644 --- a/pkg/tlsutil/cfg.go +++ b/pkg/tlsutil/cfg.go @@ -40,7 +40,7 @@ type Options struct { ClientAuth tls.ClientAuthType } -// ClientConfig retusn a TLS configuration for use by a Helm client. +// ClientConfig returns a TLS configuration for use by a Helm client. func ClientConfig(opts Options) (cfg *tls.Config, err error) { var cert *tls.Certificate var pool *x509.CertPool From cdc09e54bca50a53c1e54f0e67b15a0913f5af1d Mon Sep 17 00:00:00 2001 From: Nguyen Hai Truong Date: Wed, 27 Feb 2019 01:30:52 +0700 Subject: [PATCH 122/146] Ignore Unix swap files `*.swp` in .gitignore (#5364) Co-Authored-By: Dao Cong Tien tiendc@vn.fujitsu.com Signed-off-by: Nguyen Hai Truong --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 2414f7f2b..cfba70998 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,5 @@ rootfs/rudder vendor/ *.exe .idea/ -*.iml \ No newline at end of file +*.iml +*.swp From 42e424bb3bd24df1508d43b0bd40e0047e24abe9 Mon Sep 17 00:00:00 2001 From: Nguyen Hai Truong Date: Wed, 27 Feb 2019 10:09:39 +0700 Subject: [PATCH 123/146] Insert *~ when using emacs in .gitignore (#5366) Ignore temporary files *~ when editting source codes with emacs. Signed-off-by: Nguyen Hai Truong --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index cfba70998..14d942bf1 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ vendor/ .idea/ *.iml *.swp +*~ From 63c970c5ce29b0971cdc6409d9c0e156321ea32a Mon Sep 17 00:00:00 2001 From: Nguyen Quang Huy Date: Wed, 27 Feb 2019 22:00:20 +0700 Subject: [PATCH 124/146] Fix some typos (#5352) Correct some words spelling for reading more easily. Signed-off-by: Nguyen Quang Huy Co-Authored-By: Nguyen Van Trung --- CONTRIBUTING.md | 2 +- docs/chart_template_guide/functions_and_pipelines.md | 2 +- docs/chart_template_guide/helm_ignore_file.md | 2 +- docs/charts.md | 2 +- docs/charts_hooks.md | 4 ++-- docs/charts_tips_and_tricks.md | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a20c2b90b..c9716d0ce 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -242,7 +242,7 @@ Documentation PRs will follow the same lifecycle as other PRs. They will also be ## The Triager Each week, one of the core maintainers will serve as the designated "triager" starting after the -public standup meetings on Thursday. This person will be in charge triaging new PRs and issues +public stand-up meetings on Thursday. This person will be in charge triaging new PRs and issues throughout the work week. ## Labels diff --git a/docs/chart_template_guide/functions_and_pipelines.md b/docs/chart_template_guide/functions_and_pipelines.md index fe5a3c2b2..1c099887d 100644 --- a/docs/chart_template_guide/functions_and_pipelines.md +++ b/docs/chart_template_guide/functions_and_pipelines.md @@ -150,7 +150,7 @@ Template functions and pipelines are a powerful way to transform information and ## Operators are functions -Operators are implemented as functions that return a boolean value. To use `eq`, `ne`, `lt`, `gt`, `and`, `or`, `not` etcetera place the operator at the front of the statement followed by its parameters just as you would a function. To chain multiple operations together, separate individual functions by surrounding them with paranthesis. +Operators are implemented as functions that return a boolean value. To use `eq`, `ne`, `lt`, `gt`, `and`, `or`, `not` etcetera place the operator at the front of the statement followed by its parameters just as you would a function. To chain multiple operations together, separate individual functions by surrounding them with parentheses. ```yaml {{/* include the body of this if statement when the variable .Values.fooString exists and is set to "foo" */}} diff --git a/docs/chart_template_guide/helm_ignore_file.md b/docs/chart_template_guide/helm_ignore_file.md index 6793bdfec..5980f439c 100644 --- a/docs/chart_template_guide/helm_ignore_file.md +++ b/docs/chart_template_guide/helm_ignore_file.md @@ -4,7 +4,7 @@ The `.helmignore` file is used to specify files you don't want to include in you If this file exists, the `helm package` command will ignore all the files that match the pattern specified in the `.helmignore` file while packaging your application. -This can help in avoiding unncessary or sensitive files or directories from being added in your helm chart. +This can help in avoiding unnecessary or sensitive files or directories from being added in your helm chart. The `.helmignore` file supports Unix shell glob matching, relative path matching, and negation (prefixed with !). Only one pattern per line is considered. diff --git a/docs/charts.md b/docs/charts.md index d91dfe54e..6137898c2 100644 --- a/docs/charts.md +++ b/docs/charts.md @@ -492,7 +492,7 @@ create/update all of the above Kubernetes objects in the following order: This is because when Helm installs/upgrades charts, the Kubernetes objects from the charts and all its dependencies are -- aggregrated into a single set; then +- aggregated into a single set; then - sorted by type followed by name; and then - created/updated in that order. diff --git a/docs/charts_hooks.md b/docs/charts_hooks.md index fbb302481..6d436402d 100644 --- a/docs/charts_hooks.md +++ b/docs/charts_hooks.md @@ -248,8 +248,8 @@ annotated. When a helm release, that uses a hook, is being updated, it is possible that the hook resource might already exist in the cluster. In such circumstances, by default, helm will fail trying to install the hook resource with an `"... already exists"` error. -A common reason why the hook resource might already exist is that it was not deleted following use on a previous install/upgrade. There are, in fact, good reasons why one might want to keep the hook: for example, to aid manual debugging in case something went wrong. In this case, the recommended way of ensuring subsequent attemps to create the hook do not fail is to define a `"hook-delete-policy"` that can handle this: `"helm.sh/hook-delete-policy": "before-hook-creation"`. This hook annotation causes any existing hook to be removed, before the new hook is installed. +A common reason why the hook resource might already exist is that it was not deleted following use on a previous install/upgrade. There are, in fact, good reasons why one might want to keep the hook: for example, to aid manual debugging in case something went wrong. In this case, the recommended way of ensuring subsequent attempts to create the hook do not fail is to define a `"hook-delete-policy"` that can handle this: `"helm.sh/hook-delete-policy": "before-hook-creation"`. This hook annotation causes any existing hook to be removed, before the new hook is installed. -If it is preferred to actually delete the hook after each use (rather than have to handle it on a subsequent use, as shown above), then this can be achived using a delete policy of `"helm.sh/hook-delete-policy": "hook-succeeded,hook-failed"`. +If it is preferred to actually delete the hook after each use (rather than have to handle it on a subsequent use, as shown above), then this can be achieved using a delete policy of `"helm.sh/hook-delete-policy": "hook-succeeded,hook-failed"`. diff --git a/docs/charts_tips_and_tricks.md b/docs/charts_tips_and_tricks.md index e2c73b14f..d988184c5 100644 --- a/docs/charts_tips_and_tricks.md +++ b/docs/charts_tips_and_tricks.md @@ -281,7 +281,7 @@ According to the YAML specification, YAML is a superset of JSON. That means that any valid JSON structure ought to be valid in YAML. This has an advantage: Sometimes template developers may find it easier -to express a datastructure with a JSON-like syntax rather than deal with +to express a data structure with a JSON-like syntax rather than deal with YAML's whitespace sensitivity. As a best practice, templates should follow a YAML-like syntax _unless_ From 33589472cf02d8d10e96e06085d95791c0611a75 Mon Sep 17 00:00:00 2001 From: Nguyen Van Duc Date: Thu, 28 Feb 2019 01:38:51 +0700 Subject: [PATCH 125/146] Add .gitignore files for Eclipse (#5368) Signed-off-by: vanduc95 --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 14d942bf1..d1ec13265 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,6 @@ vendor/ *.iml *.swp *~ +.classpath +.project +.settings/** From 55fbed95d586db554b33cfa4dceff1475d2d4d41 Mon Sep 17 00:00:00 2001 From: Jacob LeGrone Date: Mon, 4 Mar 2019 10:09:05 -0500 Subject: [PATCH 126/146] feat(resource-policy): delete manifests when policy value is delete Signed-off-by: Jacob LeGrone --- pkg/kube/client.go | 8 +++++--- pkg/kube/resource_policy.go | 23 +++++++++++++++++++---- pkg/tiller/resource_policy.go | 12 +++--------- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/pkg/kube/client.go b/pkg/kube/client.go index eccf888e8..955c75ab1 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -23,12 +23,13 @@ import ( goerrors "errors" "fmt" "io" - "k8s.io/apimachinery/pkg/api/meta" "log" "sort" "strings" "time" + "k8s.io/apimachinery/pkg/api/meta" + "github.com/evanphx/json-patch" appsv1 "k8s.io/api/apps/v1" appsv1beta1 "k8s.io/api/apps/v1beta1" @@ -362,8 +363,9 @@ func (c *Client) Update(namespace string, originalReader, targetReader io.Reader if err != nil { c.Log("Unable to get annotations on %q, err: %s", info.Name, err) } - if annotations != nil && annotations[ResourcePolicyAnno] == KeepPolicy { - c.Log("Skipping delete of %q due to annotation [%s=%s]", info.Name, ResourcePolicyAnno, KeepPolicy) + if ResourcePolicyIsKeep(annotations) { + policy := annotations[ResourcePolicyAnno] + c.Log("Skipping delete of %q due to annotation [%s=%s]", info.Name, ResourcePolicyAnno, policy) continue } diff --git a/pkg/kube/resource_policy.go b/pkg/kube/resource_policy.go index 45cebcba8..9bce63a7c 100644 --- a/pkg/kube/resource_policy.go +++ b/pkg/kube/resource_policy.go @@ -19,8 +19,23 @@ package kube // ResourcePolicyAnno is the annotation name for a resource policy const ResourcePolicyAnno = "helm.sh/resource-policy" -// KeepPolicy is the resource policy type for keep +// deletePolicy is the resource policy type for delete // -// This resource policy type allows resources to skip being deleted -// during an uninstallRelease action. -const KeepPolicy = "keep" +// This resource policy type allows explicitly opting in to the default +// resource deletion behavior, for example when overriding a chart's +// default annotations. Any other value allows resources to skip being +// deleted during an uninstallRelease action. +const deletePolicy = "delete" + +// ResourcePolicyIsKeep accepts a map of Kubernetes resource annotations and +// returns true if the resource should be kept, otherwise false if it is safe +// for Helm to delete. +func ResourcePolicyIsKeep(annotations map[string]string) bool { + if annotations != nil { + resourcePolicyType, ok := annotations[ResourcePolicyAnno] + if ok && resourcePolicyType != deletePolicy { + return true + } + } + return false +} diff --git a/pkg/tiller/resource_policy.go b/pkg/tiller/resource_policy.go index aa9c5d2bd..c97621fcd 100644 --- a/pkg/tiller/resource_policy.go +++ b/pkg/tiller/resource_policy.go @@ -34,17 +34,11 @@ func filterManifestsToKeep(manifests []Manifest) ([]Manifest, []Manifest) { continue } - resourcePolicyType, ok := m.Head.Metadata.Annotations[kube.ResourcePolicyAnno] - if !ok { - remaining = append(remaining, m) - continue - } - - resourcePolicyType = strings.ToLower(strings.TrimSpace(resourcePolicyType)) - if resourcePolicyType == kube.KeepPolicy { + if kube.ResourcePolicyIsKeep(m.Head.Metadata.Annotations) { keep = append(keep, m) + } else { + remaining = append(remaining, m) } - } return keep, remaining } From ce4c3f51ade97b71a6eee5068d4f529d60b1272b Mon Sep 17 00:00:00 2001 From: Jacob LeGrone Date: Mon, 4 Mar 2019 10:17:37 -0500 Subject: [PATCH 127/146] test(resource-policy): verify behavior of non-standard policy types Signed-off-by: Jacob LeGrone --- pkg/kube/client_test.go | 2 +- pkg/kube/resource_policy_test.go | 72 ++++++++++++++++++++++++++++ pkg/tiller/release_server_test.go | 27 ++++++++--- pkg/tiller/release_uninstall_test.go | 5 +- 4 files changed, 97 insertions(+), 9 deletions(-) create mode 100644 pkg/kube/resource_policy_test.go diff --git a/pkg/kube/client_test.go b/pkg/kube/client_test.go index f601b6536..89e630bb3 100644 --- a/pkg/kube/client_test.go +++ b/pkg/kube/client_test.go @@ -213,7 +213,7 @@ func TestUpdate(t *testing.T) { // Test resource policy is respected actions = nil - listA.Items[2].ObjectMeta.Annotations = map[string]string{ResourcePolicyAnno: KeepPolicy} + listA.Items[2].ObjectMeta.Annotations = map[string]string{ResourcePolicyAnno: "keep"} if err := c.Update(v1.NamespaceDefault, objBody(&listA), objBody(&listB), false, false, 0, false); err != nil { t.Fatal(err) } diff --git a/pkg/kube/resource_policy_test.go b/pkg/kube/resource_policy_test.go new file mode 100644 index 000000000..de6061b48 --- /dev/null +++ b/pkg/kube/resource_policy_test.go @@ -0,0 +1,72 @@ +/* +Copyright The Helm Authors. + +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 kube + +import "testing" + +func TestResourcePolicyIsKeep(t *testing.T) { + type annotations map[string]string + type testcase struct { + annotations + keep bool + } + cases := []testcase{ + {nil, false}, + { + annotations{ + "foo": "bar", + }, + false, + }, + { + annotations{ + ResourcePolicyAnno: "keep", + }, + true, + }, + { + annotations{ + ResourcePolicyAnno: "KEEP ", + }, + true, + }, + { + annotations{ + ResourcePolicyAnno: "", + }, + true, + }, + { + annotations{ + ResourcePolicyAnno: "delete", + }, + false, + }, + { + annotations{ + ResourcePolicyAnno: "DELETE", + }, + true, + }, + } + + for _, tc := range cases { + if tc.keep != ResourcePolicyIsKeep(tc.annotations) { + t.Errorf("Expected function to return %t for annotations %v", tc.keep, tc.annotations) + } + } +} diff --git a/pkg/tiller/release_server_test.go b/pkg/tiller/release_server_test.go index a1502e8a2..4e29e4413 100644 --- a/pkg/tiller/release_server_test.go +++ b/pkg/tiller/release_server_test.go @@ -89,13 +89,22 @@ spec: var manifestWithKeep = `kind: ConfigMap metadata: - name: test-cm-keep + name: test-cm-keep-a annotations: "helm.sh/resource-policy": keep data: name: value ` +var manifestWithKeepEmpty = `kind: ConfigMap +metadata: + name: test-cm-keep-b + annotations: + "helm.sh/resource-policy": "" +data: + name: value +` + var manifestWithUpgradeHooks = `kind: ConfigMap metadata: name: test-cm @@ -449,23 +458,27 @@ func releaseWithKeepStub(rlsName string) *release.Release { Name: "bunnychart", }, Templates: []*chart.Template{ - {Name: "templates/configmap", Data: []byte(manifestWithKeep)}, + {Name: "templates/configmap-keep-a", Data: []byte(manifestWithKeep)}, + {Name: "templates/configmap-keep-b", Data: []byte(manifestWithKeepEmpty)}, }, } date := timestamp.Timestamp{Seconds: 242085845, Nanos: 0} - return &release.Release{ + rl := &release.Release{ Name: rlsName, Info: &release.Info{ FirstDeployed: &date, LastDeployed: &date, Status: &release.Status{Code: release.Status_DEPLOYED}, }, - Chart: ch, - Config: &chart.Config{Raw: `name: value`}, - Version: 1, - Manifest: manifestWithKeep, + Chart: ch, + Config: &chart.Config{Raw: `name: value`}, + Version: 1, } + + helm.RenderReleaseMock(rl, false) + + return rl } func MockEnvironment() *environment.Environment { diff --git a/pkg/tiller/release_uninstall_test.go b/pkg/tiller/release_uninstall_test.go index cb59b6bf5..d95a52c4d 100644 --- a/pkg/tiller/release_uninstall_test.go +++ b/pkg/tiller/release_uninstall_test.go @@ -150,7 +150,10 @@ func TestUninstallReleaseWithKeepPolicy(t *testing.T) { if res.Info == "" { t.Errorf("Expected response info to not be empty") } else { - if !strings.Contains(res.Info, "[ConfigMap] test-cm-keep") { + if !strings.Contains(res.Info, "[ConfigMap] test-cm-keep-a") { + t.Errorf("unexpected output: %s", res.Info) + } + if !strings.Contains(res.Info, "[ConfigMap] test-cm-keep-b") { t.Errorf("unexpected output: %s", res.Info) } } From e06c605b88d38c369a52dc86a2fa9890ea1aab66 Mon Sep 17 00:00:00 2001 From: Jacob LeGrone Date: Mon, 4 Mar 2019 10:18:26 -0500 Subject: [PATCH 128/146] docs(resource-policy): explain "delete" policy type Signed-off-by: Jacob LeGrone --- docs/charts_tips_and_tricks.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/charts_tips_and_tricks.md b/docs/charts_tips_and_tricks.md index d988184c5..fd7a08f7e 100644 --- a/docs/charts_tips_and_tricks.md +++ b/docs/charts_tips_and_tricks.md @@ -235,6 +235,9 @@ orphaned. Helm will no longer manage it in any way. This can lead to problems if using `helm install --replace` on a release that has already been deleted, but has kept resources. +To explicitly opt in to resource deletion, for example when overriding a chart's +default annotations, set the resource policy annotation value to `delete`. + ## Using "Partials" and Template Includes Sometimes you want to create some reusable parts in your chart, whether From 9689b02321be284f001a58c469d5ce13cd044b71 Mon Sep 17 00:00:00 2001 From: anton <0verc1ocker@users.noreply.github.com> Date: Mon, 4 Mar 2019 18:18:26 -0500 Subject: [PATCH 129/146] Add --max-history tip and to the quickstart helm init docs (#5328) Signed-off-by: 0verc1ocker --- docs/quickstart.md | 4 +++- docs/rbac.md | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/quickstart.md b/docs/quickstart.md index ef3cb460e..d7f2e3b91 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -54,9 +54,11 @@ Once you have Helm ready, you can initialize the local CLI and also install Tiller into your Kubernetes cluster in one step: ```console -$ helm init +$ helm init --max-history 200 ``` +**TIP:** Setting `--max-history` on helm init is recommended as configmaps and other objects in helm history can grow large in number if not purged by max limit. Without a max history set the history is kept indefinitely, leaving a large number of records for helm and tiller to maintain. + This will install Tiller into the Kubernetes cluster you saw with `kubectl config current-context`. diff --git a/docs/rbac.md b/docs/rbac.md index 4b39ecdc6..45371cda8 100644 --- a/docs/rbac.md +++ b/docs/rbac.md @@ -43,7 +43,7 @@ _Note: The cluster-admin role is created by default in a Kubernetes cluster, so $ kubectl create -f rbac-config.yaml serviceaccount "tiller" created clusterrolebinding "tiller" created -$ helm init --service-account tiller +$ helm init --service-account tiller --max-history 200 ``` ### Example: Deploy Tiller in a namespace, restricted to deploying resources only in that namespace From c94c00915f29fba5e816c277ff617babb3790cb1 Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Tue, 5 Mar 2019 18:04:54 -0500 Subject: [PATCH 130/146] Fix #5046 compatible with MacOS (#5406) Signed-off-by: Marc Khouzam --- cmd/helm/completion.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/helm/completion.go b/cmd/helm/completion.go index d0249b2ea..3c0318941 100644 --- a/cmd/helm/completion.go +++ b/cmd/helm/completion.go @@ -212,7 +212,7 @@ __helm_convert_bash_to_zsh() { -e "s/${LWORD}compopt${RWORD}/__helm_compopt/g" \ -e "s/${LWORD}declare${RWORD}/__helm_declare/g" \ -e "s/\\\$(type${RWORD}/\$(__helm_type/g" \ - -e 's/aliashash\["\(\w\+\)"\]/aliashash[\1]/g' \ + -e 's/aliashash\["\(.\{1,\}\)"\]/aliashash[\1]/g' \ <<'BASH_COMPLETION_EOF' ` out.Write([]byte(zshInitialization)) From 7da53d6e70e7dde7760fb89a29bd63a8cf30e897 Mon Sep 17 00:00:00 2001 From: Patrick Decat Date: Sat, 19 Jan 2019 14:52:14 +0100 Subject: [PATCH 131/146] Refactor helm init command for reuse, allowing other programs to initialize local helm home directory without shelling out to the helm binary Signed-off-by: Patrick Decat --- cmd/helm/helm_test.go | 3 +- cmd/helm/init.go | 129 +----------------- cmd/helm/init_test.go | 47 +------ cmd/helm/installer/init.go | 166 +++++++++++++++++++++++ cmd/helm/installer/init_test.go | 120 ++++++++++++++++ cmd/helm/{ => installer}/init_unix.go | 2 +- cmd/helm/{ => installer}/init_windows.go | 2 +- cmd/helm/repo_update.go | 3 +- 8 files changed, 295 insertions(+), 177 deletions(-) create mode 100644 cmd/helm/installer/init.go create mode 100644 cmd/helm/installer/init_test.go rename cmd/helm/{ => installer}/init_unix.go (92%) rename cmd/helm/{ => installer}/init_windows.go (92%) diff --git a/cmd/helm/helm_test.go b/cmd/helm/helm_test.go index 6e915fa7b..83f1173f2 100644 --- a/cmd/helm/helm_test.go +++ b/cmd/helm/helm_test.go @@ -30,6 +30,7 @@ import ( "github.com/spf13/cobra" "k8s.io/client-go/util/homedir" + "k8s.io/helm/cmd/helm/installer" "k8s.io/helm/pkg/helm" "k8s.io/helm/pkg/helm/environment" "k8s.io/helm/pkg/helm/helmpath" @@ -137,7 +138,7 @@ func ensureTestHome(home helmpath.Home, t *testing.T) error { } } - localRepoIndexFile := home.LocalRepository(localRepositoryIndexFile) + localRepoIndexFile := home.LocalRepository(installer.LocalRepositoryIndexFile) if fi, err := os.Stat(localRepoIndexFile); err != nil { i := repo.NewIndexFile() if err := i.WriteFile(localRepoIndexFile, 0644); err != nil { diff --git a/cmd/helm/init.go b/cmd/helm/init.go index db35ef037..682189f84 100644 --- a/cmd/helm/init.go +++ b/cmd/helm/init.go @@ -31,11 +31,9 @@ import ( "k8s.io/apimachinery/pkg/util/yaml" "k8s.io/helm/cmd/helm/installer" - "k8s.io/helm/pkg/getter" "k8s.io/helm/pkg/helm" "k8s.io/helm/pkg/helm/helmpath" "k8s.io/helm/pkg/helm/portforwarder" - "k8s.io/helm/pkg/repo" "k8s.io/helm/pkg/version" ) @@ -60,12 +58,6 @@ To dump a manifest containing the Tiller deployment YAML, combine the '--dry-run' and '--debug' flags. ` -const ( - stableRepository = "stable" - localRepository = "local" - localRepositoryIndexFile = "index.yaml" -) - var ( stableRepositoryURL = "https://kubernetes-charts.storage.googleapis.com" // This is the IPv4 loopback, not localhost, because we have to force IPv4 @@ -266,14 +258,8 @@ func (i *initCmd) run() error { return nil } - if err := ensureDirectories(i.home, i.out); err != nil { - return err - } - if err := ensureDefaultRepos(i.home, i.out, i.skipRefresh); err != nil { - return err - } - if err := ensureRepoFileFormat(i.home.RepositoryFile(), i.out); err != nil { - return err + if err := installer.Initialize(i.home, i.out, i.skipRefresh, settings, stableRepositoryURL, localRepositoryURL); err != nil { + return fmt.Errorf("error initializing: %s", err) } fmt.Fprintf(i.out, "$HELM_HOME has been configured at %s.\n", settings.Home) @@ -351,117 +337,6 @@ func (i *initCmd) ping(image string) error { return nil } -// ensureDirectories checks to see if $HELM_HOME exists. -// -// If $HELM_HOME does not exist, this function will create it. -func ensureDirectories(home helmpath.Home, out io.Writer) error { - configDirectories := []string{ - home.String(), - home.Repository(), - home.Cache(), - home.LocalRepository(), - home.Plugins(), - home.Starters(), - home.Archive(), - } - for _, p := range configDirectories { - if fi, err := os.Stat(p); err != nil { - fmt.Fprintf(out, "Creating %s \n", p) - if err := os.MkdirAll(p, 0755); err != nil { - return fmt.Errorf("Could not create %s: %s", p, err) - } - } else if !fi.IsDir() { - return fmt.Errorf("%s must be a directory", p) - } - } - - return nil -} - -func ensureDefaultRepos(home helmpath.Home, out io.Writer, skipRefresh bool) error { - repoFile := home.RepositoryFile() - if fi, err := os.Stat(repoFile); err != nil { - fmt.Fprintf(out, "Creating %s \n", repoFile) - f := repo.NewRepoFile() - sr, err := initStableRepo(home.CacheIndex(stableRepository), out, skipRefresh, home) - if err != nil { - return err - } - lr, err := initLocalRepo(home.LocalRepository(localRepositoryIndexFile), home.CacheIndex("local"), out, home) - if err != nil { - return err - } - f.Add(sr) - f.Add(lr) - if err := f.WriteFile(repoFile, 0644); err != nil { - return err - } - } else if fi.IsDir() { - return fmt.Errorf("%s must be a file, not a directory", repoFile) - } - return nil -} - -func initStableRepo(cacheFile string, out io.Writer, skipRefresh bool, home helmpath.Home) (*repo.Entry, error) { - fmt.Fprintf(out, "Adding %s repo with URL: %s \n", stableRepository, stableRepositoryURL) - c := repo.Entry{ - Name: stableRepository, - URL: stableRepositoryURL, - Cache: cacheFile, - } - r, err := repo.NewChartRepository(&c, getter.All(settings)) - if err != nil { - return nil, err - } - - if skipRefresh { - return &c, nil - } - - // In this case, the cacheFile is always absolute. So passing empty string - // is safe. - if err := r.DownloadIndexFile(""); err != nil { - return nil, fmt.Errorf("Looks like %q is not a valid chart repository or cannot be reached: %s", stableRepositoryURL, err.Error()) - } - - return &c, nil -} - -func initLocalRepo(indexFile, cacheFile string, out io.Writer, home helmpath.Home) (*repo.Entry, error) { - if fi, err := os.Stat(indexFile); err != nil { - fmt.Fprintf(out, "Adding %s repo with URL: %s \n", localRepository, localRepositoryURL) - i := repo.NewIndexFile() - if err := i.WriteFile(indexFile, 0644); err != nil { - return nil, err - } - - //TODO: take this out and replace with helm update functionality - if err := createLink(indexFile, cacheFile, home); err != nil { - return nil, err - } - } else if fi.IsDir() { - return nil, fmt.Errorf("%s must be a file, not a directory", indexFile) - } - - return &repo.Entry{ - Name: localRepository, - URL: localRepositoryURL, - Cache: cacheFile, - }, nil -} - -func ensureRepoFileFormat(file string, out io.Writer) error { - r, err := repo.LoadRepositoriesFile(file) - if err == repo.ErrRepoOutOfDate { - fmt.Fprintln(out, "Updating repository file format...") - if err := r.WriteFile(file, 0644); err != nil { - return err - } - } - - return nil -} - // watchTillerUntilReady waits for the tiller pod to become available. This is useful in situations where we // want to wait before we call New(). // diff --git a/cmd/helm/init_test.go b/cmd/helm/init_test.go index fd6ef97c4..b58303f42 100644 --- a/cmd/helm/init_test.go +++ b/cmd/helm/init_test.go @@ -28,7 +28,7 @@ import ( "github.com/ghodss/yaml" - "k8s.io/api/core/v1" + v1 "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" @@ -179,51 +179,6 @@ func TestInitCmd_dryRun(t *testing.T) { } } -func TestEnsureHome(t *testing.T) { - home, err := ioutil.TempDir("", "helm_home") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(home) - - b := bytes.NewBuffer(nil) - hh := helmpath.Home(home) - settings.Home = hh - if err := ensureDirectories(hh, b); err != nil { - t.Error(err) - } - if err := ensureDefaultRepos(hh, b, false); err != nil { - t.Error(err) - } - if err := ensureDefaultRepos(hh, b, true); err != nil { - t.Error(err) - } - if err := ensureRepoFileFormat(hh.RepositoryFile(), b); err != nil { - t.Error(err) - } - - expectedDirs := []string{hh.String(), hh.Repository(), hh.Cache(), hh.LocalRepository()} - for _, dir := range expectedDirs { - if fi, err := os.Stat(dir); err != nil { - t.Errorf("%s", err) - } else if !fi.IsDir() { - t.Errorf("%s is not a directory", fi) - } - } - - if fi, err := os.Stat(hh.RepositoryFile()); err != nil { - t.Error(err) - } else if fi.IsDir() { - t.Errorf("%s should not be a directory", fi) - } - - if fi, err := os.Stat(hh.LocalRepository(localRepositoryIndexFile)); err != nil { - t.Errorf("%s", err) - } else if fi.IsDir() { - t.Errorf("%s should not be a directory", fi) - } -} - func TestInitCmd_tlsOptions(t *testing.T) { const testDir = "../../testdata" diff --git a/cmd/helm/installer/init.go b/cmd/helm/installer/init.go new file mode 100644 index 000000000..9edfc0797 --- /dev/null +++ b/cmd/helm/installer/init.go @@ -0,0 +1,166 @@ +/* +Copyright The Helm Authors. + +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/cmd/helm/installer" + +import ( + "fmt" + "io" + "os" + + "k8s.io/helm/pkg/getter" + helm_env "k8s.io/helm/pkg/helm/environment" + "k8s.io/helm/pkg/helm/helmpath" + "k8s.io/helm/pkg/repo" +) + +const ( + stableRepository = "stable" + + // LocalRepository is the standard name of the local repository + LocalRepository = "local" + + // LocalRepositoryIndexFile is the standard name of the local repository index file + LocalRepositoryIndexFile = "index.yaml" +) + +// Initialize initializes local config +// +// Returns an error if the command failed. +func Initialize(home helmpath.Home, out io.Writer, skipRefresh bool, settings helm_env.EnvSettings, stableRepositoryURL, localRepositoryURL string) error { + if err := ensureDirectories(home, out); err != nil { + return err + } + if err := ensureDefaultRepos(home, out, skipRefresh, settings, stableRepositoryURL, localRepositoryURL); err != nil { + return err + } + if err := ensureRepoFileFormat(home.RepositoryFile(), out); err != nil { + return err + } + + return nil +} + +// ensureDirectories checks to see if $HELM_HOME exists. +// +// If $HELM_HOME does not exist, this function will create it. +func ensureDirectories(home helmpath.Home, out io.Writer) error { + configDirectories := []string{ + home.String(), + home.Repository(), + home.Cache(), + home.LocalRepository(), + home.Plugins(), + home.Starters(), + home.Archive(), + } + for _, p := range configDirectories { + if fi, err := os.Stat(p); err != nil { + fmt.Fprintf(out, "Creating %s \n", p) + if err := os.MkdirAll(p, 0755); err != nil { + return fmt.Errorf("Could not create %s: %s", p, err) + } + } else if !fi.IsDir() { + return fmt.Errorf("%s must be a directory", p) + } + } + + return nil +} + +func ensureDefaultRepos(home helmpath.Home, out io.Writer, skipRefresh bool, settings helm_env.EnvSettings, stableRepositoryURL, localRepositoryURL string) error { + repoFile := home.RepositoryFile() + if fi, err := os.Stat(repoFile); err != nil { + fmt.Fprintf(out, "Creating %s \n", repoFile) + f := repo.NewRepoFile() + sr, err := initStableRepo(home.CacheIndex(stableRepository), home, out, skipRefresh, settings, stableRepositoryURL) + if err != nil { + return err + } + lr, err := initLocalRepo(home.LocalRepository(LocalRepositoryIndexFile), home.CacheIndex("local"), home, out, settings, localRepositoryURL) + if err != nil { + return err + } + f.Add(sr) + f.Add(lr) + if err := f.WriteFile(repoFile, 0644); err != nil { + return err + } + } else if fi.IsDir() { + return fmt.Errorf("%s must be a file, not a directory", repoFile) + } + return nil +} + +func initStableRepo(cacheFile string, home helmpath.Home, out io.Writer, skipRefresh bool, settings helm_env.EnvSettings, stableRepositoryURL string) (*repo.Entry, error) { + fmt.Fprintf(out, "Adding %s repo with URL: %s \n", stableRepository, stableRepositoryURL) + c := repo.Entry{ + Name: stableRepository, + URL: stableRepositoryURL, + Cache: cacheFile, + } + r, err := repo.NewChartRepository(&c, getter.All(settings)) + if err != nil { + return nil, err + } + + if skipRefresh { + return &c, nil + } + + // In this case, the cacheFile is always absolute. So passing empty string + // is safe. + if err := r.DownloadIndexFile(""); err != nil { + return nil, fmt.Errorf("Looks like %q is not a valid chart repository or cannot be reached: %s", stableRepositoryURL, err.Error()) + } + + return &c, nil +} + +func initLocalRepo(indexFile, cacheFile string, home helmpath.Home, out io.Writer, settings helm_env.EnvSettings, localRepositoryURL string) (*repo.Entry, error) { + if fi, err := os.Stat(indexFile); err != nil { + fmt.Fprintf(out, "Adding %s repo with URL: %s \n", LocalRepository, localRepositoryURL) + i := repo.NewIndexFile() + if err := i.WriteFile(indexFile, 0644); err != nil { + return nil, err + } + + //TODO: take this out and replace with helm update functionality + if err := createLink(indexFile, cacheFile, home); err != nil { + return nil, err + } + } else if fi.IsDir() { + return nil, fmt.Errorf("%s must be a file, not a directory", indexFile) + } + + return &repo.Entry{ + Name: LocalRepository, + URL: localRepositoryURL, + Cache: cacheFile, + }, nil +} + +func ensureRepoFileFormat(file string, out io.Writer) error { + r, err := repo.LoadRepositoriesFile(file) + if err == repo.ErrRepoOutOfDate { + fmt.Fprintln(out, "Updating repository file format...") + if err := r.WriteFile(file, 0644); err != nil { + return err + } + } + + return nil +} diff --git a/cmd/helm/installer/init_test.go b/cmd/helm/installer/init_test.go new file mode 100644 index 000000000..1d53687e6 --- /dev/null +++ b/cmd/helm/installer/init_test.go @@ -0,0 +1,120 @@ +/* +Copyright The Helm Authors. + +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/cmd/helm/installer" + +import ( + "bytes" + "io/ioutil" + "os" + "testing" + + helm_env "k8s.io/helm/pkg/helm/environment" + "k8s.io/helm/pkg/helm/helmpath" +) + +func TestInitialize(t *testing.T) { + home, err := ioutil.TempDir("", "helm_home") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(home) + + b := bytes.NewBuffer(nil) + hh := helmpath.Home(home) + + settings := helm_env.EnvSettings{ + Home: hh, + } + stableRepositoryURL := "https://kubernetes-charts.storage.googleapis.com" + localRepositoryURL := "http://127.0.0.1:8879/charts" + + if err := Initialize(hh, b, false, settings, stableRepositoryURL, localRepositoryURL); err != nil { + t.Error(err) + } + + expectedDirs := []string{hh.String(), hh.Repository(), hh.Cache(), hh.LocalRepository()} + for _, dir := range expectedDirs { + if fi, err := os.Stat(dir); err != nil { + t.Errorf("%s", err) + } else if !fi.IsDir() { + t.Errorf("%s is not a directory", fi) + } + } + + if fi, err := os.Stat(hh.RepositoryFile()); err != nil { + t.Error(err) + } else if fi.IsDir() { + t.Errorf("%s should not be a directory", fi) + } + + if fi, err := os.Stat(hh.LocalRepository(LocalRepositoryIndexFile)); err != nil { + t.Errorf("%s", err) + } else if fi.IsDir() { + t.Errorf("%s should not be a directory", fi) + } +} + +func TestEnsureHome(t *testing.T) { + home, err := ioutil.TempDir("", "helm_home") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(home) + + b := bytes.NewBuffer(nil) + hh := helmpath.Home(home) + + settings := helm_env.EnvSettings{ + Home: hh, + } + stableRepositoryURL := "https://kubernetes-charts.storage.googleapis.com" + localRepositoryURL := "http://127.0.0.1:8879/charts" + + if err := ensureDirectories(hh, b); err != nil { + t.Error(err) + } + if err := ensureDefaultRepos(hh, b, false, settings, stableRepositoryURL, localRepositoryURL); err != nil { + t.Error(err) + } + if err := ensureDefaultRepos(hh, b, true, settings, stableRepositoryURL, localRepositoryURL); err != nil { + t.Error(err) + } + if err := ensureRepoFileFormat(hh.RepositoryFile(), b); err != nil { + t.Error(err) + } + + expectedDirs := []string{hh.String(), hh.Repository(), hh.Cache(), hh.LocalRepository()} + for _, dir := range expectedDirs { + if fi, err := os.Stat(dir); err != nil { + t.Errorf("%s", err) + } else if !fi.IsDir() { + t.Errorf("%s is not a directory", fi) + } + } + + if fi, err := os.Stat(hh.RepositoryFile()); err != nil { + t.Error(err) + } else if fi.IsDir() { + t.Errorf("%s should not be a directory", fi) + } + + if fi, err := os.Stat(hh.LocalRepository(LocalRepositoryIndexFile)); err != nil { + t.Errorf("%s", err) + } else if fi.IsDir() { + t.Errorf("%s should not be a directory", fi) + } +} diff --git a/cmd/helm/init_unix.go b/cmd/helm/installer/init_unix.go similarity index 92% rename from cmd/helm/init_unix.go rename to cmd/helm/installer/init_unix.go index bf61f1925..d7f15a1c2 100644 --- a/cmd/helm/init_unix.go +++ b/cmd/helm/installer/init_unix.go @@ -16,7 +16,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package main +package installer // import "k8s.io/helm/cmd/helm/installer" import ( "os" diff --git a/cmd/helm/init_windows.go b/cmd/helm/installer/init_windows.go similarity index 92% rename from cmd/helm/init_windows.go rename to cmd/helm/installer/init_windows.go index 447044bba..48c56e288 100644 --- a/cmd/helm/init_windows.go +++ b/cmd/helm/installer/init_windows.go @@ -16,7 +16,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package main +package installer // import "k8s.io/helm/cmd/helm/installer" import ( "os" diff --git a/cmd/helm/repo_update.go b/cmd/helm/repo_update.go index 42d242b83..2628b7f2f 100644 --- a/cmd/helm/repo_update.go +++ b/cmd/helm/repo_update.go @@ -24,6 +24,7 @@ import ( "github.com/spf13/cobra" + "k8s.io/helm/cmd/helm/installer" "k8s.io/helm/pkg/getter" "k8s.io/helm/pkg/helm/helmpath" "k8s.io/helm/pkg/repo" @@ -99,7 +100,7 @@ func updateCharts(repos []*repo.ChartRepository, out io.Writer, home helmpath.Ho wg.Add(1) go func(re *repo.ChartRepository) { defer wg.Done() - if re.Config.Name == localRepository { + if re.Config.Name == installer.LocalRepository { mu.Lock() fmt.Fprintf(out, "...Skip %s chart repository\n", re.Config.Name) mu.Unlock() From ea1bd7e1637b2573a2f418ef607fd3a671293cd9 Mon Sep 17 00:00:00 2001 From: Martin Hickey Date: Wed, 6 Mar 2019 17:27:15 +0000 Subject: [PATCH 132/146] Update dependency build doc to improve understanding (#5379) Signed-off-by: Martin Hickey --- cmd/helm/dependency_build.go | 8 ++++---- docs/helm/helm_dependency_build.md | 9 ++++----- docs/man/man1/helm_dependency_build.1 | 9 ++++----- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/cmd/helm/dependency_build.go b/cmd/helm/dependency_build.go index 3af3c1243..64a80f3bd 100644 --- a/cmd/helm/dependency_build.go +++ b/cmd/helm/dependency_build.go @@ -29,11 +29,11 @@ const dependencyBuildDesc = ` Build out the charts/ directory from the requirements.lock file. Build is used to reconstruct a chart's dependencies to the state specified in -the lock file. This will not re-negotiate dependencies, as 'helm dependency update' -does. +the lock file. -If no lock file is found, 'helm dependency build' will mirror the behavior -of 'helm dependency update'. +If no lock file is found, 'helm dependency build' will mirror the behavior of +the 'helm dependency update' command. This means it will update the on-disk +dependencies to mirror the requirements.yaml file and generate a lock file. ` type dependencyBuildCmd struct { diff --git a/docs/helm/helm_dependency_build.md b/docs/helm/helm_dependency_build.md index fba70f2ec..1df32d9ab 100644 --- a/docs/helm/helm_dependency_build.md +++ b/docs/helm/helm_dependency_build.md @@ -8,12 +8,11 @@ rebuild the charts/ directory based on the requirements.lock file Build out the charts/ directory from the requirements.lock file. Build is used to reconstruct a chart's dependencies to the state specified in -the lock file. This will not re-negotiate dependencies, as 'helm dependency update' -does. - -If no lock file is found, 'helm dependency build' will mirror the behavior -of 'helm dependency update'. +the lock file. +If no lock file is found, 'helm dependency build' will mirror the behavior of +the 'helm dependency update' command. This means it will update the on-disk +dependencies to mirror the requirements.yaml file and generate a lock file. ``` helm dependency build [flags] CHART diff --git a/docs/man/man1/helm_dependency_build.1 b/docs/man/man1/helm_dependency_build.1 index adc225a81..ef92e8959 100644 --- a/docs/man/man1/helm_dependency_build.1 +++ b/docs/man/man1/helm_dependency_build.1 @@ -19,13 +19,12 @@ Build out the charts/ directory from the requirements.lock file. .PP Build is used to reconstruct a chart's dependencies to the state specified in -the lock file. This will not re\-negotiate dependencies, as 'helm dependency update' -does. +the lock file. .PP -If no lock file is found, 'helm dependency build' will mirror the behavior -of 'helm dependency update'. - +If no lock file is found, 'helm dependency build' will mirror the behavior of +the 'helm dependency update' command. This means it will update the on-disk +dependencies to mirror the requirements.yaml file and generate a lock file. .SH OPTIONS .PP From 3c86f112e246f3dcf8e5f550c78edbb297d24073 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Wed, 6 Mar 2019 17:39:51 -0800 Subject: [PATCH 133/146] restore klog flags (#5411) Signed-off-by: Matthew Fisher --- cmd/tiller/tiller.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmd/tiller/tiller.go b/cmd/tiller/tiller.go index 478ca92f4..a1141b591 100644 --- a/cmd/tiller/tiller.go +++ b/cmd/tiller/tiller.go @@ -36,6 +36,7 @@ import ( "google.golang.org/grpc/health" healthpb "google.golang.org/grpc/health/grpc_health_v1" "google.golang.org/grpc/keepalive" + "k8s.io/klog" // Import to initialize client auth plugins. _ "k8s.io/client-go/plugin/pkg/client/auth" @@ -100,6 +101,7 @@ var ( ) func main() { + klog.InitFlags(nil) // TODO: use spf13/cobra for tiller instead of flags flag.Parse() From 29264c5765dd77e7270d4c41ce2e48e43b9408c4 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Wed, 6 Mar 2019 17:43:56 -0800 Subject: [PATCH 134/146] disable AppVeyor for branches other than master This should disable AppVeyor from running against dev-v3 PRs. Signed-off-by: Matthew Fisher --- .appveyor.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.appveyor.yml b/.appveyor.yml index 40d02927d..4fe8ae6e5 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,4 +1,7 @@ version: "{build}" +branches: + only: + - master clone_folder: c:\go\src\k8s.io\helm environment: GOPATH: c:\go From 367b6fc12122536633ff16c67bdd2304192100f5 Mon Sep 17 00:00:00 2001 From: Matt Butcher Date: Thu, 7 Mar 2019 16:58:12 -0700 Subject: [PATCH 135/146] chore: Update sprig to 2.19.0 (#5390) Update to the latest Sprig version, which is a reversion of some of the functions added in 2.18. Signed-off-by: Matt Butcher --- glide.lock | 6 +++--- glide.yaml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/glide.lock b/glide.lock index 792ef28cd..764424e94 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: 70f4fe304d0034fd077f122570adc6bb5f40ceee5f4f53d8930ba5ad700a911d -updated: 2019-02-12T13:10:08.039408-07:00 +hash: 3a24b27ab669b7bd977526dd455c5739fc2e2c14eace7dab92060ff1a39fd804 +updated: 2019-03-02T10:15:45.243405-07:00 imports: - name: cloud.google.com/go version: 3b1ae45394a234c385be014e9a488f2bb6eef821 @@ -184,7 +184,7 @@ imports: - name: github.com/Masterminds/semver version: 517734cc7d6470c0d07130e40fd40bdeb9bcd3fd - name: github.com/Masterminds/sprig - version: b1fe2752acccf8c3d7f8a1e7c75c7ae7d83a1975 + version: 9f8fceff796fb9f4e992cd2bece016be0121ab74 - name: github.com/Masterminds/vcs version: 3084677c2c188840777bff30054f2b553729d329 - name: github.com/mattn/go-runewidth diff --git a/glide.yaml b/glide.yaml index e482e23c2..c7d823196 100644 --- a/glide.yaml +++ b/glide.yaml @@ -21,7 +21,7 @@ import: - package: github.com/imdario/mergo version: v0.3.5 - package: github.com/Masterminds/sprig - version: ^2.18.0 + version: ^2.19.0 - package: github.com/ghodss/yaml - package: github.com/Masterminds/semver version: ~1.3.1 From a9c10fe104302f19e0eda5cec5b2ca314991cff0 Mon Sep 17 00:00:00 2001 From: Joe Lanford Date: Fri, 8 Mar 2019 17:46:30 -0500 Subject: [PATCH 136/146] pkg/chartutil: fix SaveDir for nested templates directories Signed-off-by: Joe Lanford --- pkg/chartutil/save.go | 6 ++++++ pkg/chartutil/save_test.go | 15 +++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/pkg/chartutil/save.go b/pkg/chartutil/save.go index 400b85e91..0482b1eb9 100644 --- a/pkg/chartutil/save.go +++ b/pkg/chartutil/save.go @@ -63,6 +63,12 @@ func SaveDir(c *chart.Chart, dest string) error { // Save templates for _, f := range c.Templates { n := filepath.Join(outdir, f.Name) + + d := filepath.Dir(n) + if err := os.MkdirAll(d, 0755); err != nil { + return err + } + if err := ioutil.WriteFile(n, f.Data, 0644); err != nil { return err } diff --git a/pkg/chartutil/save_test.go b/pkg/chartutil/save_test.go index 0ec305e78..9952fbbb0 100644 --- a/pkg/chartutil/save_test.go +++ b/pkg/chartutil/save_test.go @@ -48,6 +48,9 @@ func TestSave(t *testing.T) { Files: []*any.Any{ {TypeUrl: "scheherazade/shahryar.txt", Value: []byte("1,001 Nights")}, }, + Templates: []*chart.Template{ + {Name: "templates/scheherazade/shahryar.txt.tmpl", Data: []byte("{{ \"1,001 Nights\" }}")}, + }, } where, err := Save(c, tmp) @@ -75,6 +78,9 @@ func TestSave(t *testing.T) { if len(c2.Files) != 1 || c2.Files[0].TypeUrl != "scheherazade/shahryar.txt" { t.Fatal("Files data did not match") } + if len(c2.Templates) != 1 || c2.Templates[0].Name != "templates/scheherazade/shahryar.txt.tmpl" { + t.Fatal("Templates data did not match") + } } func TestSavePreservesTimestamps(t *testing.T) { @@ -100,6 +106,9 @@ func TestSavePreservesTimestamps(t *testing.T) { Files: []*any.Any{ {TypeUrl: "scheherazade/shahryar.txt", Value: []byte("1,001 Nights")}, }, + Templates: []*chart.Template{ + {Name: "templates/scheherazade/shahryar.txt.tmpl", Data: []byte("{{ \"1,001 Nights\" }}")}, + }, } where, err := Save(c, tmp) @@ -171,6 +180,9 @@ func TestSaveDir(t *testing.T) { Files: []*any.Any{ {TypeUrl: "scheherazade/shahryar.txt", Value: []byte("1,001 Nights")}, }, + Templates: []*chart.Template{ + {Name: "templates/scheherazade/shahryar.txt.tmpl", Data: []byte("{{ \"1,001 Nights\" }}")}, + }, } if err := SaveDir(c, tmp); err != nil { @@ -191,4 +203,7 @@ func TestSaveDir(t *testing.T) { if len(c2.Files) != 1 || c2.Files[0].TypeUrl != "scheherazade/shahryar.txt" { t.Fatal("Files data did not match") } + if len(c2.Templates) != 1 || c2.Templates[0].Name != "templates/scheherazade/shahryar.txt.tmpl" { + t.Fatal("Templates data did not match") + } } From 4fec4b67661b7cc48b8ed1f1c5827a255c74db75 Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Sat, 9 Mar 2019 22:28:36 -0500 Subject: [PATCH 137/146] Fix debug printouts for zsh completion Cobra provides some out-of-the-box debugging for bash completion. To use it, one must set the variable BASH_COMP_DEBUG_FILE to some file where the debug output will be written. Many of the debug printouts indicate the current method name; they do so by using bash's ${FUNCNAME[0]} variable. This variable is different in zsh. To obtain the current method name in zsh we must use ${funcstack[1]}. This commit adds the proper sed modification to convert from bash to zsh. Signed-off-by: Marc Khouzam --- cmd/helm/completion.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/helm/completion.go b/cmd/helm/completion.go index 3c0318941..962f06e3b 100644 --- a/cmd/helm/completion.go +++ b/cmd/helm/completion.go @@ -213,6 +213,7 @@ __helm_convert_bash_to_zsh() { -e "s/${LWORD}declare${RWORD}/__helm_declare/g" \ -e "s/\\\$(type${RWORD}/\$(__helm_type/g" \ -e 's/aliashash\["\(.\{1,\}\)"\]/aliashash[\1]/g' \ + -e 's/FUNCNAME\[0\]/funcstack[1]/g' \ <<'BASH_COMPLETION_EOF' ` out.Write([]byte(zshInitialization)) From 9cc6902875135a26c5edb2fecb08f39d9eeb2dd6 Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Sun, 10 Mar 2019 00:22:08 -0500 Subject: [PATCH 138/146] Must use index 0 for funcstack Normally zsh arrays start at index 1 but when emulating other shells this may change. During completion, we run the command emulate -L sh which affects the indexing of zsh arrays to make it start at 0. Consequently, when replacing FUNCNAME by funcstack, we should not change the index. Signed-off-by: Marc Khouzam --- cmd/helm/completion.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/helm/completion.go b/cmd/helm/completion.go index 962f06e3b..039dcbe5f 100644 --- a/cmd/helm/completion.go +++ b/cmd/helm/completion.go @@ -213,7 +213,7 @@ __helm_convert_bash_to_zsh() { -e "s/${LWORD}declare${RWORD}/__helm_declare/g" \ -e "s/\\\$(type${RWORD}/\$(__helm_type/g" \ -e 's/aliashash\["\(.\{1,\}\)"\]/aliashash[\1]/g' \ - -e 's/FUNCNAME\[0\]/funcstack[1]/g' \ + -e 's/FUNCNAME/funcstack/g' \ <<'BASH_COMPLETION_EOF' ` out.Write([]byte(zshInitialization)) From 528dc95521674baeb1a61d43d9a1c5378ddba80f Mon Sep 17 00:00:00 2001 From: tariqibrahim Date: Sun, 10 Mar 2019 03:11:30 -0700 Subject: [PATCH 139/146] update docker version and golang image version in helm Signed-off-by: tariqibrahim --- .circleci/config.yml | 4 ++-- Makefile | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 96f53ee40..c83ee10cf 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -4,13 +4,13 @@ jobs: working_directory: /go/src/k8s.io/helm parallelism: 3 docker: - - image: golang:1.11 + - image: golang:1.12 environment: PROJECT_NAME: "kubernetes-helm" steps: - checkout - setup_remote_docker: - version: 17.09.0-ce + version: 18.06.0-ce - restore_cache: keys: - glide-{{ checksum "glide.yaml" }}-{{ checksum "glide.lock" }} diff --git a/Makefile b/Makefile index 0677cafe4..ea7dd5fb7 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ DOCKER_REGISTRY ?= gcr.io IMAGE_PREFIX ?= kubernetes-helm -DEV_IMAGE ?= golang:1.11 +DEV_IMAGE ?= golang:1.12 SHORT_NAME ?= tiller SHORT_NAME_RUDDER ?= rudder TARGETS ?= darwin/amd64 linux/amd64 linux/386 linux/arm linux/arm64 linux/ppc64le linux/s390x windows/amd64 From b480badd05ad01006363763c92b5394cdc5fc9c4 Mon Sep 17 00:00:00 2001 From: Jens Frank Date: Tue, 12 Mar 2019 00:11:26 +0100 Subject: [PATCH 140/146] Fix "helm init" parameters In the quickstart guide, --max-history is recommended as parameter for helm init. The actual name of the parameter is --history-max. Signed-off-by: Jens Frank --- docs/quickstart.md | 4 ++-- docs/rbac.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/quickstart.md b/docs/quickstart.md index d7f2e3b91..6e760ced8 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -54,10 +54,10 @@ Once you have Helm ready, you can initialize the local CLI and also install Tiller into your Kubernetes cluster in one step: ```console -$ helm init --max-history 200 +$ helm init --history-max 200 ``` -**TIP:** Setting `--max-history` on helm init is recommended as configmaps and other objects in helm history can grow large in number if not purged by max limit. Without a max history set the history is kept indefinitely, leaving a large number of records for helm and tiller to maintain. +**TIP:** Setting `--history-max` on helm init is recommended as configmaps and other objects in helm history can grow large in number if not purged by max limit. Without a max history set the history is kept indefinitely, leaving a large number of records for helm and tiller to maintain. This will install Tiller into the Kubernetes cluster you saw with `kubectl config current-context`. diff --git a/docs/rbac.md b/docs/rbac.md index 45371cda8..d53edda49 100644 --- a/docs/rbac.md +++ b/docs/rbac.md @@ -43,7 +43,7 @@ _Note: The cluster-admin role is created by default in a Kubernetes cluster, so $ kubectl create -f rbac-config.yaml serviceaccount "tiller" created clusterrolebinding "tiller" created -$ helm init --service-account tiller --max-history 200 +$ helm init --service-account tiller --history-max 200 ``` ### Example: Deploy Tiller in a namespace, restricted to deploying resources only in that namespace From f2a83630efdd289a8d45581364d6a27e81b93ad1 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Tue, 12 Mar 2019 08:05:23 -0700 Subject: [PATCH 141/146] remove appveyor Signed-off-by: Matthew Fisher --- .appveyor.yml | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 .appveyor.yml diff --git a/.appveyor.yml b/.appveyor.yml deleted file mode 100644 index 4fe8ae6e5..000000000 --- a/.appveyor.yml +++ /dev/null @@ -1,20 +0,0 @@ -version: "{build}" -branches: - only: - - master -clone_folder: c:\go\src\k8s.io\helm -environment: - GOPATH: c:\go - PATH: c:\ProgramData\bin;$(PATH) -install: - - ps: iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/fishworks/gofish/master/scripts/install.ps1')) - - gofish init - - gofish install glide - - glide install --strip-vendor -cache: - - vendor -> glide.lock -build: "off" -deploy: "off" -test_script: - - go build .\cmd\... - - go test .\... From a52b4b915df10f24b11774830738094cfbeacdd9 Mon Sep 17 00:00:00 2001 From: robertavram Date: Fri, 15 Mar 2019 12:19:36 -0400 Subject: [PATCH 142/146] update outdated docs image for google storage permissions Signed-off-by: robertavram --- docs/images/make-bucket-public.png | Bin 15768 -> 54186 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/images/make-bucket-public.png b/docs/images/make-bucket-public.png index f8a5e17f02b62f312325975638ea9bcaa2d7cb9e..e457e34b23adcb6f974c9035db63c1f2cc7f4293 100644 GIT binary patch literal 54186 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

^&-}$oN({|79XZP$L-fF5VQIa!|6A%zkswgXJ z6A)Zzz`qw=x`=;1_fHojARwo=Q&7-UQBYvjbOYMhIa(7CD8G%1C)Ly)X6Wc^9A|V& z$Y~w$U1tR?KK7xFv!;))Yu0}3sC=L3>SIOX>++BE?lai)zTu<`2_o7HA|}M#~>^p+p?tc5s;sSy9-Q@2o796ao(2@(1Z_~&L z-aUCPcvr;kJ%T!S^V7wv6D92^kg3tr$mh1b!{Vp#XRm|_n_~=kW#|bk`7?zFMvb$t zl+sy9GjoK6Z%Ds_j`s6fF})2d(SP)4hGG0p5#45j1S$}6b5lu;F7k*J*3>mjZOz`! zv2~OA8R^9sS{9lX+ngtEr+vU}*}J!8R?Uu}DFout^i$PHvFL#yvTO2E(SFSY%->@! z2ni8V^jpdiXO_uvzadT@`rbWMN!0x<+v)g*vj=zU74bIZFrFxAR@?obgJMMHtLjC- z?f6p=$D4p<4ZfS=0^5FybEgHR*9jMVt`LA0HPkjK2WI36_^*@>?k_HnjcpQj57$4r za7~Vm^A6hK!Uc08-e5i#V&`Ux{ZQ%>k`nm`%5sOj1f%9u-!G6%u|6c~l&5`2!q9xv z<%&lT#T0qX73a{~_sN-q$?j8{hLDsH>$6_^Du4YAxr&_IN1<%8n{qZEMdmJf%fU4- zUBBXbn>qHPwSsR3QT`3?@WPBI3#9oJbwub_VHu=9?>!)G43_!I`T6po`OW7f$k#pQ zk|Rue;bN`E4{!E{xKCejxoLbMEo^+6XT!L^ZH$B|$R;bMU$X!8f}6*MIwo{D zJTg^LAic?)^M>6!_I9G#2(oq;!JD6@o^j<~84RlpyV>^aMSRI~UM5I{NL!t`LP_b! z>d2!NS4W;IQptBIU-@TT9+D-q_mX2@znIo`^{#nQGg#AAa~1VqO*-{eLM!7`%0`A4 zvka+O1n{fb*QhDm4Ibj#Awn%7Q;(;ptFA^|s(j`AmFepPi`SgbblD8Ap1dvnCjCvw zl46r#Q*e{-t)e#Tml!`~!EAK4(15`J<-ong3kI)>}^@(lhA*Nn#&g(dKk1eXw(440SX`JY~ zwO2k=woy*~*uX9>@HnO{*77OlX-bR_C*@NI|_Qd+yKX3%eV5 zO_2Jc`c;a1(JRTf^m+~XpA;*um7yrYI9oql?c;p0BS<%wgE5&KoP%IUF@Wp3v_#k4 zt{c*(a$ckDxt?|X>2+UP`q;TxskpMZ#5iVdn%JJ$thgv{9FG7bzmT|KMQ2g-iykci zq}QYEr0-w!M5|ousXj!jKJSB`m`;?AY_Uu>p~DRaMF-uNsQy18NlI6G$LB)RIbYO|`sRQDlV{eyaVFOLZuS`)2McT#7z^KN%$*M66IF>;}P5xW3h zZW8=?-<(nR21+>lhQ!S^p_K=IPT6+X?L59Nzy%Q_gI;N_uuWSU9U8bwBC)KUc!U+ffsK2?r$GRCMfg1$0>6fbyZLcjb;{$>{XD+inW0VO%^UJn?#! zh*u)55~#!M-B<4$D7$jo=f6NR`8uk4J=@jM{K&NmG>@;eFWf)rL})OiHgt40$j!y` zJNSmjb=S)-ykNhj?5S@cdrw0bQO}7r)NF{WD_DF^XpMWe)6>br#6=i1K8?hxd*a*$ zz=87_(=E7#y;ss`DJox?iTs97)upWzUbQ|^rWz)xpc1eHM*K@)N<%_Yt4%^243^qKUx=IAM=mTHB23YL!~6kIccGe8-U zNw>t9MjtTQ+={0ctug?)&(9|r-K+ivtgX>=;c-|#aCzpX>7}#J5l;^ZtGqGIpmnpf z*`_S2%*@SEoGrOl8S;JR`xj0~{!G3>F)i*sn177D?tza?*i9YgZ3!e>6}P8&FHfQA(@eK zRniyCwbqFiX&m!Z*f;fbJke%BLL1M(Jf=o!$5BJuzPQ zF5l*pzVTxPP%Q)k8G&B04gcRL<&p;_h zzZn_q=}PE6DU2mo*4Vq^NO0culqQ2CMms;h{orqNT;66%KgCy8f1 zyK2)$Z>x9L-%afD`v}OGs6IC|=nWLuginW#hMz{sv)Jkj$xO?{`RkvdPTEeoW)ZIt zhuPD5MU3-pmZ1TOeAmEGzdZCB?DQO6noCq(CPzI6C zXsNRnyt{w%<}hzo6JHP|<=OYiyKJ35%^T^yL_LqeK_EbDf@aW#jW11gb#8v3UEvuP zEh>Tq6;oVTtK-RB<9)t*Vb06OtoSOG1q`MsQ6@U005q`V~XuTIt;7OY-Qj?V59Ueb4dwUEHS zpOXddu>NY|;UInIxtb=c0?^HxRfPWm|NT2Mbsi$Ul!Hwh#~q2B;{?>v|EcqDhl)S)X)la$p817GEW5#`c;;=xVVNMda&} zT>o_EPEUg3)g9O+ZN&&(E~3D=JFMCyLvIEitrHSuTvUFftlVhaWpcXh&)-yATZ?WS zN7t`(uVB3!*KEL^ox8M$!FgO0W0_yMC z1cX3#Fc0JFe=b3;xl8b$^RRwYAtai3wx%yi{&yaz<${6|Ui@<&Io22=;)X9MsN?m2 z@D)TrDA4iGd4lBF@yrU>8jW)PO)%%I6PbSa=R5?#&&a7aY}~5LwEiwE{3?kXZe92n z>C1K2sh&A!>#ToC5ii(_{~`(f{|j~@=}AaiBz^tCHnzU5PGWdqAi7t5Yz4a`&xh1xBO1(ATaMS4kDV->3$hSylmjPBn)7L} zf^Zv1B=V3?f181%USGbaq%xB^+);dIb$r-tq+cG!e*A~J4{*vI@EKufI+I@GI55># zDLLBo8w_Sm0Vl^@rj0&=mx*1zueq8-Z`7Ef;U|}W$z^~W-=`i!%M=rwN=FT-~E7L)%zWa1YqwkuF=w@wGbGF{i3uBbm|8lqciy%(Q+Ge&n#|~y-B~4u>9@u%UQhRn zhHjA^m2aFr!&X1=tyOnwhVXExUUtn7n{8%UIac^JJu8MNcAT?%k-9j3mK9?*+-)UW zNhkn_B{$Rh%3&n)MSQm8_Ak}c6#sEXwS zRkuyHw!vpdlV^3f$-v3?jAFh1n~`Q7jlQ_v1F6XZoxHm037@Xr^~uTA>dAoO++237 z$C9e3G<#SO4Tam>Yn))2AR-<1;NzWhd zE)P40CMG5xAAyht9ZprFHqJx&T5ow1xW1qCM+MAn`;0qPvx%nVtg*~@nOt!Omu%%) zo^SV4O8(Q$sKAFQFY$dC#q0*M8#vm0*J?X7#C&#MRu7x{)>^cNT^+iH!b+Q}N;B6> zn6>p%qf0DJ9(2aJy$8O0>0+DeovYI_|CK_Zn{k8RsH*#93DC4P=)dNk=5BVnm0*%4 z;`iWwgYUFguJ(`z;mCJ4kIG&kysR(mnyQUu1(!nIpPU8 zjys&#^VSY?pYL{sz~DX!WjfszCWhuD9I8&uMoS5nQ_aDtzWW=~0iS{5qABd$yR5b{ z_V8^cv$hX7QU}^&ou3j`->I8&HX-}{JyGgn0mu6r-U0n~UhmJX`J+^@W#F0P;Q}zk z-VHqAZJQUFtt!y45#oD#fIV5>?vtHt#7+3F;Wuq>-Rbn+W&f~{z*s6sp5MzODY8~2 zX76u}2lGklv?S*k)52>fq1H4V#(21H*z#6q!@~Z8X$o&_1k;$zqN7YwZ&-?2A2w%| z3RO36({a1?0}%)WVp0;ic#i6W7SNEE^F)I;{PhI5 z>Bt0Epy6M*;AUBSuJb|tgD{fXJ#%G1MTNrZaaAgb2gcfM^~v#Y9-k&L#y|yg%z<{9Y*%^S<{9NP>fAaB4&pPA>q+iiq0zX zmf4>Q-H?Rg>a-ao6&6K(G-$GhWk@T5PwM{IIMK+&$k zBst>QHMp)*a4(G+9;#A&UR7tGz#e@ZzytT%x`+<61PyZ>6jVHSX`Ci<(m16qwW@n5 zIMB4vux;WzsqB7m{X%BsSLQR?l_jD@H8HeRqzm_Y<5njR{L!N>EzGMX94af)ks-!3AK+2&s=j)+CYV~%oP|+>t4go+hlWL~ zY~7`wbfcrk{fk4y?IGydDA|c&mx8IH#O!rEe*xNvZkf$*G!}4Xuc_esBho7+t;ZF0 zA(;YG0QeTIY!ovrb3Q>ep5=^vAGZn&9GAu$TEG{H+A-|quJN64qh_hL$v(t$y%BeKyeMd; zTE`8Ww^MbKIoTO(_1-bjomQCD3vHb6Sw2_{*eg#vFf=-2-_xk9B(IP?T(}!pX*LO@ z@C4m{no{^(5vrgrx%xo1+9yNbR0Z!2tikbk)cV7t>uq#9 zq{yb}>C%uYA802}D3RGVJ39z~wc`U|q$xZRnJR>k_>4*E9-s==wJSWH1v-k@#_k?v zZ8rrN&HR|pN**c4i1UQEok;ouw?_lGK_jC+`WP&^4{dXM4F9*YU0C4zs5Nb@K9h~= z!keLs4NFcM1w$FDQN8m~>Ul~u2JY6#9f{?la#S^Z7wW<+VpR1gf=Cw~MXM3G-^$|G6O?%PGDY>!dE7z7tV*f?(Lu(M zOwDgO{q^;e%INa`n8E%Y_n4;S=%Tfn)G^8=% zhhT&rpq2@Y>TeqMlUykY9bA9>z)lMDZJ=wjO14fY`xxmt*A{9TH>$gsOCiTiW6-JE zQ|zQ+pY&i^HS)@qc39OW16`u5j7deoJN1t~K{XPJnzkb3%6hEGA6==i+?Y}ki-TjV z?0V9p!m5rfs0}~&o8`iE_1N%RZpvOcn#=kLM|-HMM+X%cLEcp_&UQ6={@5b#!oZkW zvz<BFVmSRtp)uknQrZ!8 znmhhFWgW)(i*6M<;+1PZqii0uO)d+Qlp(VZ^JGs7sIn0j@yLSa=W3~yX?#@um`w&e zOnk4CgHP7>wkw$onJL1vx2x;{t70mApLiFm4VL?X!C?}8Q8$I#W%i))MKnCS#7<3< z5-`Xf0P7UjwNsyo^zT3AE+R>{e^-qU{+j%f%oISn3~Gk5m~W{9)uXO@tC;GAQrn&+ zy>bV>XS=l_rfeoFrFO?}E+0R2YG#yvJJNzeWUPv*!Ds;RgUmrYe~Gt?%pWD!8wREE zUi4IBaG_b#DWRCX(6b}n_O*kW`}Ax2L)pgO1VosHZpraEIyuSzyy;A6CRLI(a-VcB%oG-_0lY2ZQ2F=(BkZf{JkD zZz9$D*K2wpEM$lW`JT^lxN+%IrCYAAfRz~xp)WOhMOhT^!A?2@u_|AE%U5T*g;vwdN15gbg_2G0td1{@{vHf$1ykC4U}6V(BG9&H+GVo~^lg3`? zd|3inl|Ed^YMp-(*O`Qb@a)#fp6*P+jh`+F8sKcW(h<@oV`19SuBRoSj0 zc6p_eo8dv)>Chu=&Flw?w8RY4cmysY@qtndv?HuD!BA%OX#eMY<>nr|{5Iy>8W*X) z!vUXFYw*CEf)YFQ-A$vUx9mq7tt}M2&Dh%)%km5K4n95wQ%z}!3Z(nX)>(c3i z`n2cTN9%@WU2%&IzyrwP7~}4BMm261$i?R(sj~~DhRXWz>Md0kD=zm-s}_nh9<9~;m-{*-LK4lE=j`<6`+XFvL4|v| zjSfqn%sOLI+r0KhZI9IRb&JDfC;c+x!R4mMUo9T;j*XOtkY;7u;-|-L6 zZ_^YV+is6O?0gF;P6jw(#3b7vRG1I9b1mo%Y~E;821<+C=GeKP2k}y|s!U506zG_Y z4`ef4{VGqX*a6xdA`+$c()Q!U*qVY_E)p^OnIc)*bi`;+z|kret3~aYLc4#pMHUoI z1EsCn+{|!_dS8vhJK#xaOx~zUd+rr_O=#lEYw-AncLi@8aMO$t=fLui*)O88VJgBexCisk#{?&<_(KeQkh^{zAb+0_sPe7*6#)?!UCCsnW%#Dr zhhEsYp2uX-T2|wHqJv+~tJEKi8WMd<6uX;!yQW=wXV>GeuM`&DFiG>z&1mO&UJ?mA zWYRtu;Ex{j+nf|)1a@U6*VuP?BXk4GU+^-ojCnbfzLYP<^J;L($9MdRUe`u>+DXx* zt_evuf}~nTw|aZ;`$v&sW8ntXypAsmGEyRD`WfPh?8LbD-(uz~ZA9zDT0<5VJnRF! zTS(~l6DJqEO!JiF2%m99@v8RGRn6-LXYGVw)2922`?U*E&BdjA_aGcqzSS1W@Zuv+YctiWC#FWaKTq}!fw zQ`wW;DSz4dHR_3n@2`{LJ$X5iLVLsu6^sbP746o==Tsppi^ZQlZUs*I<6aN?+7q$wn1lQJZd1%E!@=tY;`dE7M&TN?bO_M z@D#EexF>7MA>5Of+M~Mx5Su{i_S@*fhmJ>6`yk#!C_NJ_#2jwkLX$jSYF*qg7w&4x%GJJGfGF2yGz4mY`<=O@@mvjASx z_T_sDMV^?hLPS7uYt0;bry@JDBA$u_>8Yi2(wOgv`@xa6zm-blqUWa= za~=okuZeUNQDz-AXu}Y9dhH#uyi4$QPD}0s)k{%JsPhe@?PPY(Fk&pa zpN+LOqOnc_Oj?k9$9tQE_e=M6(~CnAd_WxMCukKqP8_(kswZB@{$Mqjl=+f?X5r*@ z2YK7BVa?zoiFj@87`@$iSh_ZJ%VTpO#9UT>B`tu|Ll7V><=~TolZ1?Ff6G?rfGK4ho3YlB8?aE36hkiF=nUSqD7BQWt>Zain|n7pV)-gi+Xdw;KEESe4RXG zRt2{XVL!@Eawbn(ya8=Qir-Eh3XTZzuB3Y_X=k{*#m^FguDP{-^*ltGX#$$~1N#th zS`{`T5=}nZ$QKK-*HML2#eE=tz{b(C+1Xei-AUdgYf1vh_e<}hXd^$$u%|=~W~Ucy z(MPCHS&TN#I@nRZQ+dBE(KJb;ddb*lF~`C{qv>uuP)$KxuwJCm^Rlkb4N8|Rm^+4t zVd{w)Hc^ysR@TeT~9nndx#9i)1{Y3+?61JJ2HF?K+}(m`bmfv zro#?AW`@Wbl8?bvGBN_|`^ph%_D|wep{h+U&Wu1AqT4sxqExz`tE zEPL|Yo8GTGDvJv;VnoOL(0T#O#p@M`?2s>k0BylRPiybEWOhX3gYg#KUQG^u5jK9z z93;l7beqQ*$iK@BBCyeLCt%ty;KCUoH&g??bZo>ODNh% zxSY1KZ?$vWYV#}mru&5eBi0E+=*mFLU|>rzu}VUqh`+(U>r}_>Qd?@FUuBgbxvS?w zaTiS8vcqBq@4y+JjfI}Ca+gi#|4A%KNl7Q_KjR*;g*~*|efaX_%Z(1N^@)O$y2Imb zs^6mO1jY{U@a2cONuJj_*0lj4%u-$@!%4!n9|nVU`2cT5dY2mRj13LV&G#f>qYi>E zkg{XD<<)=7n)6Z6mJulaMPcQ!>H+jkOe^>2igoViO4Y@d_>_2YRTYxYq;BX8wEWfJ z1`!$E4M|VO(OO7BfvW_WMv^FW#k!Q>eAj}PsL%6uqm1}L93Rnr)DB+bY|8N%q={KI zZHY@jK2?AFLmPY3puwv&Nj4A;fk52(`1n%#ny+8Vel7=S1C>=kW-*Qtf7Q8o!@Pgj zxfJE-RXd_s*25?n_4nv>0(g=>l4L8VOLhUd##R(kIUH1!VOZ~TicjxPmb76b+UMgHIBa{nVGbI2}gOCq$l!9%%LRZ!{N zUc_Eq5%4&e>)_H~0EB;gUP+W@082YsTT?*kw|vw!2sY&j(H-TzUhPRzpNB3Hs9vF-#b-Kz7GVw%bq8pJKx5D2J8N?B8&Nc*pq{)Unv4MllDgs_$+xjVmL>ObXu6`B(L{2ejf1L>Htpz1A;xxc3W z4c|ZT2B0z_IY;>qcI48n@Ms&o`1$HT$*lj?&HZDN#kYQe=*L^ZDHDgE(YLpP)qxi>2Kg;owl3wl___c+d z)Lt{Y7s2bopkgq!6>}5rzL=-iB4rG-PtFATL^p-%In`yNVfnj99*O0&JjwODrG~iE z1{<;bK!NJBE1@Qn>NfSe{f6M4rue$bCpcFCljPX$Y(kZeE&Fc`NzWtRzq!U`5dXWX z9xwNl+R@Z+-IB%8UOp>q&y!Q=an(c-g%ZfWs?Q*l4#=ylC;yn&pu4`r z0I0cH9$%j~>F6TqG&I=<>ofI%^#|sT&1~M4c$<7;{6|5WAlQvKV*iJLt;p{Revq6i z(YjxS)MZZ*>|`3${e4%Y(G##bdI)teFog1+`-n_K%CwlDAjXS%1PqZg>J9TWVh4vL zYhbXznxDn9;6MDcHAThAwS-1aI()E!m!TYv47EE~=1F0MEcq%;GxT|_rmVdJ9WK59 zM5L!J+ntJWTE-ML6GpX!E*5uJ)6^+qt*LFR&A3oIVf>D3@XoJMGz;;UPYT?+!_SBO z`GSa?oW-lSxOEFiv6i>0+I+P0?upn*E4%F3oAh=Ntnadi!o?~PyS0)j^H)UUTms1Y zD7q?rOtElo)VOsFp|d%?WObQ!ui3!NynvnO(`6&ntMtXKEpwxZ)N&MGzLTf^)8mPb zE_C-4d}`i2ho-~xm@DyqFvgU)Ag1db!kb6_cmWl2XXMK+vGd(x_84eFWth8H%iwpEyK^4=sjQM9H;rA zIh@D3k>=78eYRpN*xsYw?=FUDnj)u^`usMSLrTAY3elpM1n6v9X5{SPJw?j=+gxEF zXsvAhy;~A&T=4S;^$v&M2#CLX(VT>oR)XU#BiQ-c$ia{}8(#rrTiU00>9K&BNUf?p zk(6B*p|cgW7x$E2&w4EVGD^&o8D;V1aOEfKn`C-2&2Y*kO#Bekg_3Eu!zBO_&FnoY z)#S)1F7+AMUq<_wv_4UGLR?=h?O3Es;VzQ}*BNQrSt+cv(oZp5gQOCvWGvBV5;(I^ zqOY%(MZ3ZMvC_Ockh=a!H7;mvNXegKB6)FPE zY;YdUmT{&ZnVI=j_XEem9ESFNEvk=n16h=jVo(>Kl|DkrD_25gg!hd!A@(iBM3~4A zw-&1mVQH{R>22ieHCch-@$A(wdQ|Ph%bvrx5FNu_A8sPYC&PVL;$8P zr>`sdoG0Dq4{drRfvCwv)5({0$ER!-C6L}?ei{30BPSQ2*m8^w_$y)?tt4-L^FxAazhbAmZ7{|rnqC_>LG12_nrwB2nhbF|DF^ex?$=J|COv}9} zxc<5)MWR^DZ#KUt5;WRaIYpI8pIc%l$(paH!Hpp1npxIKW3bD{WmJm(MQ`%siO&dl zr#^0S;zZYo13*qkyTZLFUSoT!AyG%}h6eegG=E4-6mlDMCXg?!R|3hNX3=0+y-4d# z1xpj}XoAbD!4k!JMzcN`PF8wafz~^Z9sGxHiH(ugANswY@@}DL65&q9rS*Xusts^A z&Ah&SFDbw+u&!e-_M|!ak5x_H5*;9|H_Tnrkg;w;>>|sx|uC8@WI}MTRP!`cb2JAQgKHGA+^t z(3WDBtH(N1xG!&+93CS|<3RT+amY{!56zq@cRy;EJr5tuN$y4}Ms2uY6Sue&V0uyj zUb2u6H#z~xPVjmRA9T`f7!}>Cr!RN>gQ}TzO^t`u+dJEmhhn`bu5#`Cs?47DNdV z`lliTR}prkm%%h!#QufT4aaacc-S`Fb{VB*c57xRvfRf4S#D2H+>^Q<;PYi%AfK%= zdu&!R&C!A1X;zGq$N}^$hjqJjk#Y?x-j%{kW~G9=zN{sOPMK+`mKYt__NCpB-7roW zw@s2~@`;0Q|FAwSrwEz&T-o^NP0t16Ak#!iF-!7ul@Dg7^9l?o*Le>esF`jIO^qK9 z>D@2na1y`261!A9r6p6B23Y)P5>^4fbZX``Yzf9(c#1k^<6A?dlg@?qCM~ClGpd(t zz4i$?9rJ_+mxiph3Vgw?Q4y)5Iga}1m(WzjiIYxh;aNS!Ecm!Z8t3_9!z%|9aBvc; zKSH`T6dyGkf?b=~ae-1z?B1Gi2b#_GQl-)t5gfm3;(Z6a_-8cB8YOpn?Q!bO8-M5t zm;yyZT?atR3wHx+ z;|H(RitHcxQi9GXC7QLjUt*?<#_34P7ho^Sq&$!B;XW_;gi$W7BFTvkz#$B?b?HwI zzB$Nj;#ekyyx#%i{dbrZ(2?t+bqNzrTL(2Wr)=th{r3`Hgd7_Vyh!H7bQ%@Aic0?h zC57_oa-T98MAMvp-C)SC2ns2~hED0J5TcpIeM~>hYxNDG#RiNIN*8yhJ7gtYY9#%t zs}fC*%x5d@QENsOGJ^n(J4-CJV8C+2rqYWL+fz?Jbr{hCrM{@EzOW^)Vf+bc~V%r_o%=rdeAq6whl5Y zKa<+>;*he?&KyM9xv|3VHr`xFSF#O*iv7S^Akupc zMphC-#)08fOPF>j-EvE(=pE4^;h=<}%9{3c&~9SZ;l7-ZsLCjC7jm@Lsl*DU8#?@O zDV6V*M&f*iUK*dq@}Z zJEX&q=x!URYINB1Lz_~c6?(7o0uytggT<*m8XC?#T~B@;G13R{fpgr%g(8;o(cTgO z@^#9xzO(-hf-b!xG8VnU<@IOKi09~h=#OmpSe|!Pt%~FiO!)1__4Csvj8*jx`N%`|xWI z{&*N%(`-Y5&P->->{>!&+c-pjd=1R8a#LF?~BI!k|2DjM|ex- zUsv3fVR*6+j!FD?KJ(8dQggD(H5(CxNBy~qKL-2XrT_OxedBDMW#Kd1?QieT|1n18 MvASaMBlD2|15`@6hX4Qo From 83d66b643c591e8ba9a63f2173115e30c6619bbd Mon Sep 17 00:00:00 2001 From: tariqibrahim Date: Sun, 17 Mar 2019 20:53:54 -0700 Subject: [PATCH 143/146] update kubernetes deps to latest patch releases Signed-off-by: tariqibrahim --- glide.lock | 20 ++++++++++---------- glide.yaml | 12 ++++++------ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/glide.lock b/glide.lock index 764424e94..824e30041 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: 3a24b27ab669b7bd977526dd455c5739fc2e2c14eace7dab92060ff1a39fd804 -updated: 2019-03-02T10:15:45.243405-07:00 +hash: f86919aea9f9b6df70967eb0b00d8a3807a2f5e924d7bd82d317f7969fddb3ef +updated: 2019-03-17T20:36:59.222397-07:00 imports: - name: cloud.google.com/go version: 3b1ae45394a234c385be014e9a488f2bb6eef821 @@ -85,7 +85,7 @@ imports: subpackages: - spdy - name: github.com/evanphx/json-patch - version: 36442dbdb585210f8d5a1b45e67aa323c197d5c4 + version: 5858425f75500d40c52783dce87d085a483ce135 - name: github.com/exponent-io/jsonpath version: d6023ce2651d8eafb5c75bb0c7167536102ec9f5 - name: github.com/fatih/camelcase @@ -370,7 +370,7 @@ imports: - name: gopkg.in/yaml.v2 version: 670d4cfef0544295bc27a114dbac37980d83185a - name: k8s.io/api - version: 05914d821849570fba9eacfb29466f2d8d3cd229 + version: 5cb15d34447165a97c76ed5a60e4e99c8a01ecfe subpackages: - admission/v1beta1 - admissionregistration/v1alpha1 @@ -407,11 +407,11 @@ imports: - storage/v1alpha1 - storage/v1beta1 - name: k8s.io/apiextensions-apiserver - version: 0fe22c71c47604641d9aa352c785b7912c200562 + version: d002e88f6236312f0289d9d1deab106751718ff0 subpackages: - pkg/features - name: k8s.io/apimachinery - version: 2b1284ed4c93a43499e781493253e2ac5959c4fd + version: 86fb29eff6288413d76bd8506874fddd9fccdff0 subpackages: - pkg/api/equality - pkg/api/errors @@ -467,7 +467,7 @@ imports: - third_party/forked/golang/netutil - third_party/forked/golang/reflect - name: k8s.io/apiserver - version: 3ccfe8365421eb08e334b195786a2973460741d8 + version: 79427f02047f9189a75b8cdaadccaf65a126853e subpackages: - pkg/authentication/authenticator - pkg/authentication/serviceaccount @@ -475,13 +475,13 @@ imports: - pkg/features - pkg/util/feature - name: k8s.io/cli-runtime - version: 835b10687cb6556f6b113099ef925146a56d5981 + version: a9e421a7932607ce4623ff45add8274499cca193 subpackages: - pkg/genericclioptions - pkg/genericclioptions/printers - pkg/genericclioptions/resource - name: k8s.io/client-go - version: 8d9ed539ba3134352c586810e749e58df4e94e4f + version: b40b2a5939e43f7ffe0028ad67586b7ce50bb675 subpackages: - discovery - discovery/fake @@ -611,7 +611,7 @@ imports: - pkg/util/proto/testing - pkg/util/proto/validation - name: k8s.io/kubernetes - version: c6d339953bd4fd8c021a6b5fb46d7952b30be9f9 + version: f2c8f1cadf1808ec28476682e49a3cce2b09efbf subpackages: - pkg/api/legacyscheme - pkg/api/service diff --git a/glide.yaml b/glide.yaml index c7d823196..23a3cdaf4 100644 --- a/glide.yaml +++ b/glide.yaml @@ -53,17 +53,17 @@ import: - package: k8s.io/kubernetes version: release-1.13 - package: k8s.io/client-go - version: kubernetes-1.13.1 + version: kubernetes-1.13.4 - package: k8s.io/api - version: kubernetes-1.13.1 + version: kubernetes-1.13.4 - package: k8s.io/apimachinery - version: kubernetes-1.13.1 + version: kubernetes-1.13.4 - package: k8s.io/apiserver - version: kubernetes-1.13.1 + version: kubernetes-1.13.4 - package: k8s.io/cli-runtime - version: kubernetes-1.13.1 + version: kubernetes-1.13.4 - package: k8s.io/apiextensions-apiserver - version: kubernetes-1.13.1 + version: kubernetes-1.13.4 - package: github.com/cyphar/filepath-securejoin version: ^0.2.1 From 63ef73d4168980e650bc95c225f9be1b63b7b37c Mon Sep 17 00:00:00 2001 From: Mikhail Kirpichev Date: Mon, 18 Mar 2019 18:54:53 +0300 Subject: [PATCH 144/146] fix(tiller): fixed a typo in tiller and unit test There was a typo in a tiller error with "released named" message, I've changed it to "a release named". Also fix a unit-test for it. Signed-off-by: Mikhail Kirpichev --- pkg/tiller/release_server.go | 2 +- pkg/tiller/release_update_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/tiller/release_server.go b/pkg/tiller/release_server.go index eb3e876d0..d32fd82f6 100644 --- a/pkg/tiller/release_server.go +++ b/pkg/tiller/release_server.go @@ -195,7 +195,7 @@ func (s *ReleaseServer) uniqName(start string, reuse bool) (string, error) { s.Log("name %s exists but is not in use, reusing name", start) return start, nil } else if reuse { - return "", fmt.Errorf("a released named %s is in use, cannot re-use a name that is still in use", start) + return "", fmt.Errorf("a release named %s is in use, cannot re-use a name that is still in use", start) } return "", fmt.Errorf("a release named %s already exists.\nRun: helm ls --all %s; to check the status of the release\nOr run: helm del --purge %s; to delete it", start, start, start) diff --git a/pkg/tiller/release_update_test.go b/pkg/tiller/release_update_test.go index ea1c88f62..e47e526d6 100644 --- a/pkg/tiller/release_update_test.go +++ b/pkg/tiller/release_update_test.go @@ -604,7 +604,7 @@ func TestUpdateReleasePendingInstall_Force(t *testing.T) { t.Error("Expected failed update") } - expectedError := "a released named forceful-luke is in use, cannot re-use a name that is still in use" + expectedError := "a release named forceful-luke is in use, cannot re-use a name that is still in use" got := err.Error() if err.Error() != expectedError { t.Errorf("Expected error %q, got %q", expectedError, got) From ab9cc982a0616e28d6e308d69033534cb7e62025 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Tue, 19 Mar 2019 21:00:12 -0700 Subject: [PATCH 145/146] fix(scripts): use a more precise method of grepping Github recently changed the output of the releases page. grepping for the exact tag fixes the issue where the wrong tag was being filtered. Signed-off-by: Matthew Fisher --- scripts/get | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/get b/scripts/get index 9c93e1e84..bc13039e2 100755 --- a/scripts/get +++ b/scripts/get @@ -80,9 +80,9 @@ checkDesiredVersion() { # Use the GitHub releases webpage for the project to find the desired version for this project. local release_url="https://github.com/helm/helm/releases/${DESIRED_VERSION:-latest}" if type "curl" > /dev/null; then - TAG=$(curl -SsL $release_url | awk '/\/tag\//' | grep -v no-underline | head -n 1 | cut -d '"' -f 2 | awk '{n=split($NF,a,"/");print a[n]}' | awk 'a !~ $0{print}; {a=$0}') + TAG=$(curl -SsL $release_url | awk '/\/tag\//' | grep -v no-underline | grep " /dev/null; then - TAG=$(wget -q -O - $release_url | awk '/\/tag\//' | grep -v no-underline | head -n 1 | cut -d '"' -f 2 | awk '{n=split($NF,a,"/");print a[n]}' | awk 'a !~ $0{print}; {a=$0}') + TAG=$(wget -q -O - $release_url | awk '/\/tag\//' | grep -v no-underline | grep " Date: Wed, 20 Mar 2019 10:52:00 -0700 Subject: [PATCH 146/146] style: fix golint error in init.go for redundant err!=nil check Signed-off-by: tariqibrahim --- cmd/helm/installer/init.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/cmd/helm/installer/init.go b/cmd/helm/installer/init.go index 9edfc0797..7731a4a98 100644 --- a/cmd/helm/installer/init.go +++ b/cmd/helm/installer/init.go @@ -47,11 +47,8 @@ func Initialize(home helmpath.Home, out io.Writer, skipRefresh bool, settings he if err := ensureDefaultRepos(home, out, skipRefresh, settings, stableRepositoryURL, localRepositoryURL); err != nil { return err } - if err := ensureRepoFileFormat(home.RepositoryFile(), out); err != nil { - return err - } - return nil + return ensureRepoFileFormat(home.RepositoryFile(), out) } // ensureDirectories checks to see if $HELM_HOME exists.