From 1c64d8fb8164406e63bf91e263b11485d43a8324 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Tue, 29 Oct 2019 13:46:36 -0700 Subject: [PATCH 01/65] fix(version): lift "unreleased" status Signed-off-by: Matthew Fisher --- cmd/helm/testdata/output/version-short.txt | 2 +- cmd/helm/testdata/output/version-template.txt | 2 +- cmd/helm/testdata/output/version.txt | 2 +- internal/version/version.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/helm/testdata/output/version-short.txt b/cmd/helm/testdata/output/version-short.txt index 5e7749489..d9fb9c736 100644 --- a/cmd/helm/testdata/output/version-short.txt +++ b/cmd/helm/testdata/output/version-short.txt @@ -1 +1 @@ -v3.0+unreleased +v3.0 diff --git a/cmd/helm/testdata/output/version-template.txt b/cmd/helm/testdata/output/version-template.txt index c12e29c2d..776c1919b 100644 --- a/cmd/helm/testdata/output/version-template.txt +++ b/cmd/helm/testdata/output/version-template.txt @@ -1 +1 @@ -Version: v3.0+unreleased \ No newline at end of file +Version: v3.0 \ No newline at end of file diff --git a/cmd/helm/testdata/output/version.txt b/cmd/helm/testdata/output/version.txt index 0d9b536e6..4b493d31c 100644 --- a/cmd/helm/testdata/output/version.txt +++ b/cmd/helm/testdata/output/version.txt @@ -1 +1 @@ -version.BuildInfo{Version:"v3.0+unreleased", GitCommit:"", GitTreeState:"", GoVersion:""} +version.BuildInfo{Version:"v3.0", GitCommit:"", GitTreeState:"", GoVersion:""} diff --git a/internal/version/version.go b/internal/version/version.go index 131a2b130..22439d11b 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -33,7 +33,7 @@ var ( version = "v3.0" // metadata is extra build time data - metadata = "unreleased" + metadata = "" // gitCommit is the git sha1 gitCommit = "" // gitTreeState is the state of the git tree From 432fd9c110bf75de46cfc8db4748ad0a0fdc28fd Mon Sep 17 00:00:00 2001 From: Taylor Thomas Date: Thu, 31 Oct 2019 09:26:22 -0600 Subject: [PATCH 02/65] fix(cmd): Updates description for template validation flag This is a follow up to discussion in #6663 that clarifies exactly what the validate flag is doing. It isn't meant to be a generic schema validator, but rather validates the manifests against the current cluster as if it was going to be installing them. Signed-off-by: Taylor Thomas --- cmd/helm/template.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/helm/template.go b/cmd/helm/template.go index 1c6d88ee8..5312d798f 100644 --- a/cmd/helm/template.go +++ b/cmd/helm/template.go @@ -119,7 +119,7 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { addInstallFlags(f, client, valueOpts) f.StringArrayVarP(&showFiles, "show-only", "s", []string{}, "only show manifests rendered from the given templates") f.StringVar(&client.OutputDir, "output-dir", "", "writes the executed templates to files in output-dir instead of stdout") - f.BoolVar(&validate, "validate", false, "establish a connection to Kubernetes for schema validation") + f.BoolVar(&validate, "validate", false, "validate your manifests against the Kubernetes cluster you are currently pointing at. This is the same validation performed on an install") f.StringArrayVarP(&extraAPIs, "api-versions", "a", []string{}, "Kubernetes api versions used for Capabilities.APIVersions") return cmd From 668f51bfdf8171bfaf8d369752ff938ed630d655 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Fri, 1 Nov 2019 14:44:26 -0700 Subject: [PATCH 03/65] fix(chart): add JSON tags to chart object Go capitalizes field names by default. Signed-off-by: Matthew Fisher --- pkg/chart/chart.go | 12 ++++++------ pkg/chart/file.go | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pkg/chart/chart.go b/pkg/chart/chart.go index f36cf8236..2b667d456 100644 --- a/pkg/chart/chart.go +++ b/pkg/chart/chart.go @@ -27,18 +27,18 @@ const APIVersionV2 = "v2" // optionally parameterizable templates, and zero or more charts (dependencies). type Chart struct { // Metadata is the contents of the Chartfile. - Metadata *Metadata + Metadata *Metadata `json:"metadata"` // LocK is the contents of Chart.lock. - Lock *Lock + Lock *Lock `json:"lock"` // Templates for this chart. - Templates []*File + Templates []*File `json:"templates"` // Values are default config for this template. - Values map[string]interface{} + Values map[string]interface{} `json:"values"` // Schema is an optional JSON schema for imposing structure on Values - Schema []byte + Schema []byte `json:"schema"` // Files are miscellaneous files in a chart archive, // e.g. README, LICENSE, etc. - Files []*File + Files []*File `json:"files"` parent *Chart dependencies []*Chart diff --git a/pkg/chart/file.go b/pkg/chart/file.go index 45f64efe8..9dd7c08d5 100644 --- a/pkg/chart/file.go +++ b/pkg/chart/file.go @@ -21,7 +21,7 @@ package chart // base directory. type File struct { // Name is the path-like name of the template. - Name string + Name string `json:"name"` // Data is the template as byte data. - Data []byte + Data []byte `json:"data"` } From c9b127c3ee2fd6832c02c645600fc0caff7827c2 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Thu, 31 Oct 2019 12:05:41 -0700 Subject: [PATCH 04/65] fix(getter): set up TLS options during .Get() Signed-off-by: Matthew Fisher --- internal/tlsutil/tlsutil_test.go | 2 +- pkg/getter/httpgetter.go | 33 ++++--- pkg/getter/httpgetter_test.go | 86 +++++++++++----- .../testdata/output/httpgetter-servername.txt | 1 - testdata/ca.pem | 35 ------- testdata/crt.pem | 98 ++++++++++++++----- testdata/generate.sh | 4 + testdata/key.pem | 74 +++++--------- testdata/openssl.conf | 42 ++++++++ testdata/rootca.crt | 19 ++++ testdata/rootca.key | 27 +++++ 11 files changed, 268 insertions(+), 153 deletions(-) delete mode 100644 pkg/getter/testdata/output/httpgetter-servername.txt delete mode 100644 testdata/ca.pem create mode 100755 testdata/generate.sh create mode 100644 testdata/openssl.conf create mode 100644 testdata/rootca.crt create mode 100644 testdata/rootca.key diff --git a/internal/tlsutil/tlsutil_test.go b/internal/tlsutil/tlsutil_test.go index a4b3c9c22..c2a477272 100644 --- a/internal/tlsutil/tlsutil_test.go +++ b/internal/tlsutil/tlsutil_test.go @@ -25,7 +25,7 @@ import ( const tlsTestDir = "../../testdata" const ( - testCaCertFile = "ca.pem" + testCaCertFile = "rootca.crt" testCertFile = "crt.pem" testKeyFile = "key.pem" ) diff --git a/pkg/getter/httpgetter.go b/pkg/getter/httpgetter.go index 320013541..a36ab0321 100644 --- a/pkg/getter/httpgetter.go +++ b/pkg/getter/httpgetter.go @@ -29,8 +29,7 @@ import ( // HTTPGetter is the efault HTTP(/S) backend handler type HTTPGetter struct { - client *http.Client - opts options + opts options } //Get performs a Get from repo.Getter and returns the body. @@ -60,7 +59,12 @@ func (g *HTTPGetter) get(href string) (*bytes.Buffer, error) { req.SetBasicAuth(g.opts.username, g.opts.password) } - resp, err := g.client.Do(req) + client, err := g.httpClient() + if err != nil { + return nil, err + } + + resp, err := client.Do(req) if err != nil { return buf, err } @@ -81,28 +85,31 @@ func NewHTTPGetter(options ...Option) (Getter, error) { opt(&client.opts) } - if client.opts.certFile != "" && client.opts.keyFile != "" { - tlsConf, err := tlsutil.NewClientTLS(client.opts.certFile, client.opts.keyFile, client.opts.caFile) + return &client, nil +} + +func (g *HTTPGetter) httpClient() (*http.Client, error) { + if g.opts.certFile != "" && g.opts.keyFile != "" { + tlsConf, err := tlsutil.NewClientTLS(g.opts.certFile, g.opts.keyFile, g.opts.caFile) if err != nil { - return &client, errors.Wrap(err, "can't create TLS config for client") + return nil, errors.Wrap(err, "can't create TLS config for client") } tlsConf.BuildNameToCertificate() - sni, err := urlutil.ExtractHostname(client.opts.url) + sni, err := urlutil.ExtractHostname(g.opts.url) if err != nil { - return &client, err + return nil, err } tlsConf.ServerName = sni - client.client = &http.Client{ + client := &http.Client{ Transport: &http.Transport{ TLSClientConfig: tlsConf, Proxy: http.ProxyFromEnvironment, }, } - } else { - client.client = http.DefaultClient - } - return &client, nil + return client, nil + } + return http.DefaultClient, nil } diff --git a/pkg/getter/httpgetter_test.go b/pkg/getter/httpgetter_test.go index 93bfd96b1..0c2c55ea3 100644 --- a/pkg/getter/httpgetter_test.go +++ b/pkg/getter/httpgetter_test.go @@ -24,7 +24,9 @@ import ( "strings" "testing" - "helm.sh/helm/v3/internal/test" + "github.com/pkg/errors" + + "helm.sh/helm/v3/internal/tlsutil" "helm.sh/helm/v3/internal/version" "helm.sh/helm/v3/pkg/cli" ) @@ -35,46 +37,25 @@ func TestHTTPGetter(t *testing.T) { t.Fatal(err) } - if hg, ok := g.(*HTTPGetter); !ok { + if _, ok := g.(*HTTPGetter); !ok { t.Fatal("Expected NewHTTPGetter to produce an *HTTPGetter") - } else if hg.client != http.DefaultClient { - t.Fatal("Expected NewHTTPGetter to return a default HTTP client.") } - // Test with SSL: cd := "../../testdata" join := filepath.Join - ca, pub, priv := join(cd, "ca.pem"), join(cd, "crt.pem"), join(cd, "key.pem") - g, err = NewHTTPGetter( - WithURL("http://example.com"), - WithTLSClientConfig(pub, priv, ca), - ) - if err != nil { - t.Fatal(err) - } - - hg, ok := g.(*HTTPGetter) - if !ok { - t.Fatal("Expected NewHTTPGetter to produce an *HTTPGetter") - } + ca, pub, priv := join(cd, "rootca.crt"), join(cd, "crt.pem"), join(cd, "key.pem") - transport, ok := hg.client.Transport.(*http.Transport) - if !ok { - t.Errorf("Expected NewHTTPGetter to set up an HTTP transport") - } - - test.AssertGoldenString(t, transport.TLSClientConfig.ServerName, "output/httpgetter-servername.txt") - - // Test other options + // Test with options g, err = NewHTTPGetter( WithBasicAuth("I", "Am"), WithUserAgent("Groot"), + WithTLSClientConfig(pub, priv, ca), ) if err != nil { t.Fatal(err) } - hg, ok = g.(*HTTPGetter) + hg, ok := g.(*HTTPGetter) if !ok { t.Fatal("expected NewHTTPGetter to produce an *HTTPGetter") } @@ -90,6 +71,18 @@ func TestHTTPGetter(t *testing.T) { if hg.opts.userAgent != "Groot" { t.Errorf("Expected NewHTTPGetter to contain %q as the user agent, got %q", "Groot", hg.opts.userAgent) } + + if hg.opts.certFile != pub { + t.Errorf("Expected NewHTTPGetter to contain %q as the public key file, got %q", pub, hg.opts.certFile) + } + + if hg.opts.keyFile != priv { + t.Errorf("Expected NewHTTPGetter to contain %q as the private key file, got %q", priv, hg.opts.keyFile) + } + + if hg.opts.caFile != ca { + t.Errorf("Expected NewHTTPGetter to contain %q as the CA file, got %q", ca, hg.opts.caFile) + } } func TestDownload(t *testing.T) { @@ -149,3 +142,42 @@ func TestDownload(t *testing.T) { t.Errorf("Expected %q, got %q", expect, got.String()) } } + +func TestDownloadTLS(t *testing.T) { + cd := "../../testdata" + ca, pub, priv := filepath.Join(cd, "rootca.crt"), filepath.Join(cd, "crt.pem"), filepath.Join(cd, "key.pem") + + tlsSrv := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})) + tlsConf, err := tlsutil.NewClientTLS(pub, priv, ca) + if err != nil { + t.Fatal(errors.Wrap(err, "can't create TLS config for client")) + } + tlsConf.BuildNameToCertificate() + tlsConf.ServerName = "helm.sh" + tlsSrv.TLS = tlsConf + tlsSrv.StartTLS() + defer tlsSrv.Close() + + u, _ := url.ParseRequestURI(tlsSrv.URL) + g, err := NewHTTPGetter( + WithURL(u.String()), + WithTLSClientConfig(pub, priv, ca), + ) + if err != nil { + t.Fatal(err) + } + + if _, err := g.Get(u.String()); err != nil { + t.Error(err) + } + + // now test with TLS config being passed along in .Get (see #6635) + g, err = NewHTTPGetter() + if err != nil { + t.Fatal(err) + } + + if _, err := g.Get(u.String(), WithURL(u.String()), WithTLSClientConfig(pub, priv, ca)); err != nil { + t.Error(err) + } +} diff --git a/pkg/getter/testdata/output/httpgetter-servername.txt b/pkg/getter/testdata/output/httpgetter-servername.txt deleted file mode 100644 index caa12a8fb..000000000 --- a/pkg/getter/testdata/output/httpgetter-servername.txt +++ /dev/null @@ -1 +0,0 @@ -example.com \ No newline at end of file diff --git a/testdata/ca.pem b/testdata/ca.pem deleted file mode 100644 index 79d854a8d..000000000 --- a/testdata/ca.pem +++ /dev/null @@ -1,35 +0,0 @@ ------BEGIN CERTIFICATE----- -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 -mlK3dw== ------END CERTIFICATE----- diff --git a/testdata/crt.pem b/testdata/crt.pem index 226b3a71b..715cd0f65 100644 --- a/testdata/crt.pem +++ b/testdata/crt.pem @@ -1,29 +1,73 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 55:31:53:9b:41:72:05:dc:90:49:bd:48:13:7c:59:9e:5a:53:5e:86 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=CO, L=Boulder, O=Helm, CN=helm.sh + Validity + Not Before: Nov 1 22:51:49 2019 GMT + Not After : Oct 29 22:51:49 2029 GMT + Subject: C=US, ST=CO, L=Boulder, O=Helm, CN=helm.sh + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:c8:89:55:0d:0b:f1:da:e6:c0:70:7d:d3:27:cd: + b8:a8:81:8b:7c:a4:89:e5:d1:b1:78:01:1d:df:44: + 88:0b:fc:d6:81:35:3d:d1:3b:5e:8f:bb:93:b3:7e: + 28:db:ed:ff:a0:13:3a:70:a3:fe:94:6b:0b:fe:fb: + 63:00:b0:cb:dc:81:cd:80:dc:d0:2f:bf:b2:4f:9a: + 81:d4:22:dc:97:c8:8f:27:86:59:91:fa:92:05:75: + c4:cc:6b:f5:a9:6b:74:1e:f5:db:a9:f8:bf:8c:a2: + 25:fd:a0:cc:79:f4:25:57:74:a9:23:9b:e2:b7:22: + 7a:14:7a:3d:ea:f1:7e:32:6b:57:6c:2e:c6:4f:75: + 54:f9:6b:54:d2:ca:eb:54:1c:af:39:15:9b:d0:7c: + 0f:f8:55:51:04:ea:da:fa:7b:8b:63:0f:ac:39:b1: + f6:4b:8e:4e:f6:ea:e9:7b:e6:ba:5e:5a:8e:91:ef: + dc:b1:7d:52:3f:73:83:52:46:83:48:49:ff:f2:2d: + ca:54:f2:36:bb:49:cc:59:99:c0:9e:cf:8e:78:55: + 6c:ed:7d:7e:83:b8:59:2c:7d:f8:1a:81:f0:7d:f5: + 27:f2:db:ae:d4:31:54:38:fe:47:b2:ee:16:20:0f: + f1:db:2d:28:bf:6f:38:eb:11:bb:9a:d4:b2:5a:3a: + 4a:7f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:helm.sh, IP Address:127.0.0.1 + Signature Algorithm: sha256WithRSAEncryption + 4e:17:27:3d:36:4e:6c:2b:f7:d4:28:33:7e:05:26:7a:42:a0: + 2c:44:57:04:a0:de:df:40:fb:af:70:27:e6:55:20:f1:f8:c0: + 50:63:ab:b8:f1:31:5d:1e:f4:ca:8d:65:0b:d4:5e:5b:77:2f: + 2a:af:74:5f:18:2d:92:29:7f:2d:97:fb:ec:aa:e3:1e:db:b3: + 8d:01:aa:82:1a:f6:28:a8:b3:ee:15:9f:9a:f5:76:37:30:f2: + 3b:38:13:b2:d4:14:94:c6:38:fa:f9:6e:94:e8:1f:11:0b:b0: + 69:1a:b3:f9:f1:27:b4:d2:f5:64:54:7c:8f:e7:83:31:f6:0d: + a7:0e:0e:66:d8:33:2f:e0:a1:93:56:92:58:bf:50:da:56:8e: + db:42:22:f5:0c:6f:f8:4c:ef:f5:7c:2d:a6:b8:60:e4:bb:df: + a3:6c:c2:6b:99:0b:d3:0a:ad:7c:f4:74:72:9a:52:5e:81:d9: + a2:a2:dd:68:38:fb:b7:54:7f:f6:aa:ee:53:de:3d:3a:0e:86: + 53:ad:af:72:db:fb:6b:18:ce:ac:e4:64:70:13:68:da:be:e1: + 6b:46:dd:a0:72:96:9b:3f:ba:cf:11:6e:98:03:0a:69:83:9e: + 37:25:c9:36:b9:68:4f:73:ca:c6:32:5c:be:46:64:bb:a8:cc: + 71:25:8f:be -----BEGIN CERTIFICATE----- -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 +g543Jck2uWhPc8rGMly+RmS7qMxxJY++ -----END CERTIFICATE----- diff --git a/testdata/generate.sh b/testdata/generate.sh new file mode 100755 index 000000000..9751ef304 --- /dev/null +++ b/testdata/generate.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +openssl req -new -config openssl.conf -key key.pem -out key.csr +openssl ca -config openssl.conf -create_serial -batch -in key.csr -out crt.pem -key rootca.key -cert rootca.crt diff --git a/testdata/key.pem b/testdata/key.pem index 8b2cde82e..691e55087 100644 --- a/testdata/key.pem +++ b/testdata/key.pem @@ -1,51 +1,27 @@ -----BEGIN RSA PRIVATE KEY----- -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 -----END RSA PRIVATE KEY----- diff --git a/testdata/openssl.conf b/testdata/openssl.conf new file mode 100644 index 000000000..9b27e445b --- /dev/null +++ b/testdata/openssl.conf @@ -0,0 +1,42 @@ +[ca] +default_ca = CA_default + +[CA_default] +dir = ./ +database = $dir/index.txt +new_certs_dir = ./ +serial = $dir/serial +private_key = ./rootca.key +certificate = ./rootca.crt +default_days = 3650 +default_md = sha256 +policy = policy_anything +copy_extensions = copyall + +[policy_anything] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +[ req ] +default_bits = 2048 +distinguished_name = req_distinguished_name +req_extensions = v3_req + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +stateOrProvinceName = State or Province Name (full name) +localityName = Locality Name (eg, city) +organizationName = Organization Name (eg, company) +commonName = Common Name (e.g. server FQDN or YOUR name) + +[ v3_req ] +subjectAltName = @alternate_names + +[alternate_names] +DNS.1 = helm.sh +IP.1 = 127.0.0.1 diff --git a/testdata/rootca.crt b/testdata/rootca.crt new file mode 100644 index 000000000..892104365 --- /dev/null +++ b/testdata/rootca.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDITCCAgkCFAasUT/De3J4aee7b1VEESf+3ndyMA0GCSqGSIb3DQEBCwUAME0x +CzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDTzEQMA4GA1UEBwwHQm91bGRlcjENMAsG +A1UECgwESGVsbTEQMA4GA1UEAwwHaGVsbS5zaDAeFw0xOTExMDEyMjM2MzZaFw0y +MjA4MjEyMjM2MzZaME0xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDTzEQMA4GA1UE +BwwHQm91bGRlcjENMAsGA1UECgwESGVsbTEQMA4GA1UEAwwHaGVsbS5zaDCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMinBcDJwiG3OVb1bCWQqTAOS3s6 +QwWkEXkoYyFFpCNvqEzQPtp+OkfD6gczc0ByGQibDLBApEQhq17inqtAxIUrTgXP +ym3l+0/U7ejuTka3ue84slkw2lVobfVEvJWGro+93GzbxvVNNYGJcD2BKJqmCCxD +I6tdTEL855kzgQUAvGITzDUxABU9+f06CW/9AlZlmBIuwrzRVjFNjflBrcm1PIUG +upMCu8zaWat8o1TnLCDKizw1JJzCgCnMxGXfzeAd1MGUG/rOFkBImHf39Jakp/7L +Icq+2FDE+0vNai0lpUpxPVTp8dcug8U3//bL3q0OqROA7Ks4wc0URGH71W8CAwEA +ATANBgkqhkiG9w0BAQsFAAOCAQEAMJqzeg6cBbUkrh9a6+qa66IFR1Mf3wVB1c61 +JN6Z70kjgSdOZ/NexxxSu347fIPyKGkmokbnE1MJVEETPmzhpuTkQDcq7KT4IcQF +S+H4l0lNn09thIlIiAJmpQrNOlrHVtpLCFB4+YnsqqFKPlcO/dGy9U26L4xfn6+n +24/o7pNEu44GnktXPjfcbajaPUSKHxeYibjdftoUEYX/79ROu7E1QnNXj7mXymw0 +rqOgIlyCUGw8WvRR8RzR6m+1lnwOc+nxFKXzTt0LqOQt9sHI1V71WrxgDE+Lck+W +fybfsgodM2Y7VXnH4A4xoKeOHxW1YcqIKt0ribt8602lD1pYBg== +-----END CERTIFICATE----- diff --git a/testdata/rootca.key b/testdata/rootca.key new file mode 100644 index 000000000..e3c1ce51e --- /dev/null +++ b/testdata/rootca.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAyKcFwMnCIbc5VvVsJZCpMA5LezpDBaQReShjIUWkI2+oTNA+ +2n46R8PqBzNzQHIZCJsMsECkRCGrXuKeq0DEhStOBc/KbeX7T9Tt6O5ORre57ziy +WTDaVWht9US8lYauj73cbNvG9U01gYlwPYEomqYILEMjq11MQvznmTOBBQC8YhPM +NTEAFT35/ToJb/0CVmWYEi7CvNFWMU2N+UGtybU8hQa6kwK7zNpZq3yjVOcsIMqL +PDUknMKAKczEZd/N4B3UwZQb+s4WQEiYd/f0lqSn/sshyr7YUMT7S81qLSWlSnE9 +VOnx1y6DxTf/9sverQ6pE4DsqzjBzRREYfvVbwIDAQABAoIBAHwyTbBP8baWx4oY +rNDvoplZL8VdgaCbNimNIxa0GW3Jrh2lhFIPcZl8HX5JjVvlg7M87XSm/kYhpQY9 +NUMA+uMGs+uK+1xcztpSDNRxtMe27wKwUEw+ndXhprX6ztOqop/cP/StcI/jM2wz +muKm8HAQttxWzlxCinKoQd4k8AYcnqc728FSODP7EsdDgiU6BhBZDqjgmqggye0y +niog+JBPDgwTgGodJWtSYuP/G2iJDUvm7bGU2gftXTJstrATLftGKX8XOgJMmDx9 +8OgDtU21LzggarOQ/iwUKX2MEfYnP8kgGLgu5nNonJCHWYGeCZoxIn70rs3WoBsU +5+FzmHkCgYEA7MFYixlTSxXfen1MwctuZ9YiwoneSLfjmBb+LP0Pfa2r0CVMPaXM +OexroIY14h64nunb7y3YifGk01RXzCBpEF5KhsZuYXAl3lGxbjbTjncU5/11Dim+ +W9g+T4zDimlK2tuweAjMfWz6XG2inZ3xvK73mGkEsUnqhWQKXBRf7VsCgYEA2PZp +KAwbpRFSYFwcZoRm81fLijZ5NbmOJtND6oG1LZVaVSYuvljvjQzeVfL4+Iju6FzT +zbnEfVsatu0cTs6jMy0yJUl6wRbHlH/G6Ra8UxSvUUEFe1Xap33RmjkK+atzALQi +pZPCIfLr+f9qQWrPMdZwzRnws0u2pKepSdXR0H0CgYB9chDdWyTkIwnPmDakdIri +X/b5Bx4Nf8oLGxvAcLHVkMD5v9l+zKvCgT+hxZslXcvK//S17Z/Pr4b7JrSChyXE +M4HfmaKA5HBcNQMDd+9ujDA6n/R29a1UcubJNbeiThoIjuEZKOhZCPY7JShFxZuB +s1+jlPmUiqrF1PUcRvtxAwKBgQDGpuelmWB+hRutyujeHQC+cnaU+EeHH3y+o9Wd +lGG1ePia2jkWZAwCU/QHMk8wEQDelJAB38O/G3mcYAH5Tk4zf4BYj6zrutXGbDBO +H1kToO7dMPG5+eQYU6Vk1jHsZEUKMeU/QckQmIHkBy7c8tT/Rt9FjCjNodd7b2Ab +kMFpaQKBgQDggmgsPFSZmo+yYDZucueXqfc8cbSWd9K1UruKMaPOsyoUWJNYARHA +cpHTpaIjDth8MUp2zLIZnPUSDkSgEAOcRH4C5CxmgSkmeJdlEEzWMF2yugczlYGO +l9SOX07w4/WJCZFeRWTqRGWs7X6iL8um0P9yFelw3SZt33ON+1fRPg== +-----END RSA PRIVATE KEY----- From 444d006fe27bdea5ade0333fdb78c2141de2f175 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Fri, 1 Nov 2019 16:01:02 -0700 Subject: [PATCH 05/65] fix(version): implement `helm version -c`, mark as hidden Signed-off-by: Matthew Fisher --- cmd/helm/testdata/output/version-client-shorthand.txt | 1 + cmd/helm/testdata/output/version-client.txt | 1 + cmd/helm/version.go | 2 ++ cmd/helm/version_test.go | 8 ++++++++ 4 files changed, 12 insertions(+) create mode 100644 cmd/helm/testdata/output/version-client-shorthand.txt create mode 100644 cmd/helm/testdata/output/version-client.txt diff --git a/cmd/helm/testdata/output/version-client-shorthand.txt b/cmd/helm/testdata/output/version-client-shorthand.txt new file mode 100644 index 000000000..0d9b536e6 --- /dev/null +++ b/cmd/helm/testdata/output/version-client-shorthand.txt @@ -0,0 +1 @@ +version.BuildInfo{Version:"v3.0+unreleased", GitCommit:"", GitTreeState:"", GoVersion:""} diff --git a/cmd/helm/testdata/output/version-client.txt b/cmd/helm/testdata/output/version-client.txt new file mode 100644 index 000000000..0d9b536e6 --- /dev/null +++ b/cmd/helm/testdata/output/version-client.txt @@ -0,0 +1 @@ +version.BuildInfo{Version:"v3.0+unreleased", GitCommit:"", GitTreeState:"", GoVersion:""} diff --git a/cmd/helm/version.go b/cmd/helm/version.go index 8c0c11484..3067f7289 100644 --- a/cmd/helm/version.go +++ b/cmd/helm/version.go @@ -61,6 +61,8 @@ func newVersionCmd(out io.Writer) *cobra.Command { f := cmd.Flags() f.BoolVar(&o.short, "short", false, "print the version number") f.StringVar(&o.template, "template", "", "template for version string format") + f.BoolP("client", "c", true, "display client version information") + f.MarkHidden("client") return cmd } diff --git a/cmd/helm/version_test.go b/cmd/helm/version_test.go index 89b89093e..134401948 100644 --- a/cmd/helm/version_test.go +++ b/cmd/helm/version_test.go @@ -32,6 +32,14 @@ func TestVersion(t *testing.T) { name: "template", cmd: "version --template='Version: {{.Version}}'", golden: "output/version-template.txt", + }, { + name: "client", + cmd: "version --client", + golden: "output/version-client.txt", + }, { + name: "client shorthand", + cmd: "version -c", + golden: "output/version-client-shorthand.txt", }} runTestCmd(t, tests) } From 7f7e90b4078d412e2ff36d8220409ff8497c93a1 Mon Sep 17 00:00:00 2001 From: Fabian Ruff Date: Sat, 2 Nov 2019 00:18:21 +0100 Subject: [PATCH 06/65] Consider namespace when comparing resources Fixes #6857 Signed-off-by: Fabian Ruff --- pkg/action/upgrade.go | 2 +- pkg/kube/client.go | 2 +- pkg/kube/resource.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/action/upgrade.go b/pkg/action/upgrade.go index 31fcc1471..d0495a864 100644 --- a/pkg/action/upgrade.go +++ b/pkg/action/upgrade.go @@ -415,5 +415,5 @@ func recreate(cfg *Configuration, resources kube.ResourceList) error { func objectKey(r *resource.Info) string { gvk := r.Object.GetObjectKind().GroupVersionKind() - return fmt.Sprintf("%s/%s/%s", gvk.GroupVersion().String(), gvk.Kind, r.Name) + return fmt.Sprintf("%s/%s/%s/%s", gvk.GroupVersion().String(), gvk.Kind, r.Namespace, r.Name) } diff --git a/pkg/kube/client.go b/pkg/kube/client.go index 2a5661306..ab1f600ff 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -167,7 +167,7 @@ func (c *Client) Update(original, target ResourceList, force bool) (*Result, err } kind := info.Mapping.GroupVersionKind.Kind - c.Log("Created a new %s called %q\n", kind, info.Name) + c.Log("Created a new %s called %q in %s\n", kind, info.Name, info.Namespace) return nil } diff --git a/pkg/kube/resource.go b/pkg/kube/resource.go index 0f2d94f3a..ee8f83a25 100644 --- a/pkg/kube/resource.go +++ b/pkg/kube/resource.go @@ -81,5 +81,5 @@ func (r ResourceList) Intersect(rs ResourceList) ResourceList { // isMatchingInfo returns true if infos match on Name and GroupVersionKind. func isMatchingInfo(a, b *resource.Info) bool { - return a.Name == b.Name && a.Mapping.GroupVersionKind.Kind == b.Mapping.GroupVersionKind.Kind + return a.Name == b.Name && a.Namespace == b.Namespace && a.Mapping.GroupVersionKind.Kind == b.Mapping.GroupVersionKind.Kind } From 4226c45dfd7419874583a37b79124afdd55129ec Mon Sep 17 00:00:00 2001 From: Taylor Thomas Date: Mon, 4 Nov 2019 15:19:48 -0700 Subject: [PATCH 07/65] fix(cmd): Standardizes all output to use lower snake_case names After discussing similar changes in #6866, we decided to make sure all JSON and YAML output uses lower snake case names as is generally standard Signed-off-by: Taylor Thomas --- cmd/helm/list.go | 14 +++++++------- cmd/helm/repo_list.go | 4 ++-- cmd/helm/search_hub.go | 8 ++++---- cmd/helm/search_repo.go | 8 ++++---- cmd/helm/testdata/output/search-output-json.txt | 2 +- cmd/helm/testdata/output/search-output-yaml.txt | 8 ++++---- 6 files changed, 22 insertions(+), 22 deletions(-) diff --git a/cmd/helm/list.go b/cmd/helm/list.go index 7e04e64a9..32501530d 100644 --- a/cmd/helm/list.go +++ b/cmd/helm/list.go @@ -110,13 +110,13 @@ func newListCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { } type releaseElement struct { - Name string - Namespace string - Revision string - Updated string - Status string - Chart string - AppVersion string + Name string `json:"name"` + Namespace string `json:"namespace"` + Revision string `json:"revision"` + Updated string `json:"updated"` + Status string `json:"status"` + Chart string `json:"chart"` + AppVersion string `json:"app_version"` } type releaseListWriter struct { diff --git a/cmd/helm/repo_list.go b/cmd/helm/repo_list.go index 10d8976fe..2ff6162d1 100644 --- a/cmd/helm/repo_list.go +++ b/cmd/helm/repo_list.go @@ -51,8 +51,8 @@ func newRepoListCmd(out io.Writer) *cobra.Command { } type repositoryElement struct { - Name string - URL string + Name string `json:"name"` + URL string `json:"url"` } type repoListWriter struct { diff --git a/cmd/helm/search_hub.go b/cmd/helm/search_hub.go index e4c149f4a..89139ec16 100644 --- a/cmd/helm/search_hub.go +++ b/cmd/helm/search_hub.go @@ -84,10 +84,10 @@ func (o *searchHubOptions) run(out io.Writer, args []string) error { } type hubChartElement struct { - URL string - Version string - AppVersion string - Description string + URL string `json:"url"` + Version string `json:"version"` + AppVersion string `json:"app_version"` + Description string `json:"description"` } type hubSearchWriter struct { diff --git a/cmd/helm/search_repo.go b/cmd/helm/search_repo.go index 68d0135c7..063a72a27 100644 --- a/cmd/helm/search_repo.go +++ b/cmd/helm/search_repo.go @@ -191,10 +191,10 @@ func (o *searchRepoOptions) buildIndex(out io.Writer) (*search.Index, error) { } type repoChartElement struct { - Name string - Version string - AppVersion string - Description string + Name string `json:"name"` + Version string `json:"version"` + AppVersion string `json:"app_version"` + Description string `json:"description"` } type repoSearchWriter struct { diff --git a/cmd/helm/testdata/output/search-output-json.txt b/cmd/helm/testdata/output/search-output-json.txt index d462a12c1..9b211e1b5 100644 --- a/cmd/helm/testdata/output/search-output-json.txt +++ b/cmd/helm/testdata/output/search-output-json.txt @@ -1 +1 @@ -[{"Name":"testing/mariadb","Version":"0.3.0","AppVersion":"","Description":"Chart for MariaDB"}] +[{"name":"testing/mariadb","version":"0.3.0","app_version":"","description":"Chart for MariaDB"}] diff --git a/cmd/helm/testdata/output/search-output-yaml.txt b/cmd/helm/testdata/output/search-output-yaml.txt index 5034d8ce0..122b7f345 100644 --- a/cmd/helm/testdata/output/search-output-yaml.txt +++ b/cmd/helm/testdata/output/search-output-yaml.txt @@ -1,4 +1,4 @@ -- AppVersion: 2.3.4 - Description: Deploy a basic Alpine Linux pod - Name: testing/alpine - Version: 0.2.0 +- app_version: 2.3.4 + description: Deploy a basic Alpine Linux pod + name: testing/alpine + version: 0.2.0 From d683a431e241a37c40042ad168f04460e9306eaf Mon Sep 17 00:00:00 2001 From: yuxiaobo Date: Tue, 5 Nov 2019 09:55:48 +0800 Subject: [PATCH 08/65] Correct spelling mistakes Signed-off-by: yuxiaobo --- cmd/helm/create.go | 2 +- cmd/helm/root.go | 2 +- cmd/helm/search/search.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/helm/create.go b/cmd/helm/create.go index e9f71d0a7..e8ff757cf 100644 --- a/cmd/helm/create.go +++ b/cmd/helm/create.go @@ -91,7 +91,7 @@ func (o *createOptions) run(out io.Writer) error { if o.starter != "" { // Create from the starter lstarter := filepath.Join(o.starterDir, o.starter) - // If path is absolute, we dont want to prefix it with helm starters folder + // If path is absolute, we don't want to prefix it with helm starters folder if filepath.IsAbs(o.starter) { lstarter = o.starter } diff --git a/cmd/helm/root.go b/cmd/helm/root.go index fac0dc062..f0a034d45 100644 --- a/cmd/helm/root.go +++ b/cmd/helm/root.go @@ -175,7 +175,7 @@ __helm_list_charts() # 1- There are other completions found (if there are no completions, # the shell will do file completion itself) # 2- If there is some input from the user (or else we will end up - # lising the entire content of the current directory which will + # listing the entire content of the current directory which will # be too many choices for the user to find the real repos) if [ $wantFiles -eq 1 ] && [ -n "${out[*]}" ] && [ -n "${cur}" ]; then for file in $(\ls); do diff --git a/cmd/helm/search/search.go b/cmd/helm/search/search.go index 855da4a3d..fc7f30596 100644 --- a/cmd/helm/search/search.go +++ b/cmd/helm/search/search.go @@ -51,7 +51,7 @@ type Index struct { const sep = "\v" -// NewIndex creats a new Index. +// NewIndex creates a new Index. func NewIndex() *Index { return &Index{lines: map[string]string{}, charts: map[string]*repo.ChartVersion{}} } From bd1f4a443e95ea4eda88affad96577b63c0d6622 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Wed, 30 Oct 2019 14:22:26 -0700 Subject: [PATCH 09/65] fix(show): restore comments from raw values Signed-off-by: Matthew Fisher --- pkg/action/show.go | 9 +++++---- pkg/chart/chart.go | 7 ++++++- pkg/chart/chart_test.go | 25 +++++++++++++++++++++++++ pkg/chart/loader/load.go | 1 + pkg/chart/loader/load_test.go | 4 ++++ 5 files changed, 41 insertions(+), 5 deletions(-) diff --git a/pkg/action/show.go b/pkg/action/show.go index 3733b28fd..b29107d4e 100644 --- a/pkg/action/show.go +++ b/pkg/action/show.go @@ -24,6 +24,7 @@ import ( "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chart/loader" + "helm.sh/helm/v3/pkg/chartutil" ) type ShowOutputFormat string @@ -76,11 +77,11 @@ func (s *Show) Run(chartpath string) (string, error) { if s.OutputFormat == ShowAll { fmt.Fprintln(&out, "---") } - b, err := yaml.Marshal(chrt.Values) - if err != nil { - return "", err + for _, f := range chrt.Raw { + if f.Name == chartutil.ValuesfileName { + fmt.Fprintln(&out, string(f.Data)) + } } - fmt.Fprintf(&out, "%s\n", b) } if s.OutputFormat == ShowReadme || s.OutputFormat == ShowAll { diff --git a/pkg/chart/chart.go b/pkg/chart/chart.go index 2b667d456..c3e99eae6 100644 --- a/pkg/chart/chart.go +++ b/pkg/chart/chart.go @@ -26,13 +26,18 @@ const APIVersionV2 = "v2" // Chart is a helm package that contains metadata, a default config, zero or more // optionally parameterizable templates, and zero or more charts (dependencies). type Chart struct { + // Raw contains the raw contents of the files originally contained in the chart archive. + // + // This should not be used except in special cases like `helm show values`, + // where we want to display the raw values, comments and all. + Raw []*File `json:"-"` // Metadata is the contents of the Chartfile. Metadata *Metadata `json:"metadata"` // LocK is the contents of Chart.lock. Lock *Lock `json:"lock"` // Templates for this chart. Templates []*File `json:"templates"` - // Values are default config for this template. + // Values are default config for this chart. Values map[string]interface{} `json:"values"` // Schema is an optional JSON schema for imposing structure on Values Schema []byte `json:"schema"` diff --git a/pkg/chart/chart_test.go b/pkg/chart/chart_test.go index 8b656d393..724e52933 100644 --- a/pkg/chart/chart_test.go +++ b/pkg/chart/chart_test.go @@ -16,6 +16,7 @@ limitations under the License. package chart import ( + "encoding/json" "testing" "github.com/stretchr/testify/assert" @@ -49,3 +50,27 @@ func TestCRDs(t *testing.T) { is.Equal("crds/foo.yaml", crds[0].Name) is.Equal("crds/foo/bar/baz.yaml", crds[1].Name) } + +func TestSaveChartNoRawData(t *testing.T) { + chrt := Chart{ + Raw: []*File{ + { + Name: "fhqwhgads.yaml", + Data: []byte("Everybody to the Limit"), + }, + }, + } + + is := assert.New(t) + data, err := json.Marshal(chrt) + if err != nil { + t.Fatal(err) + } + + res := &Chart{} + if err := json.Unmarshal(data, res); err != nil { + t.Fatal(err) + } + + is.Equal([]*File(nil), res.Raw) +} diff --git a/pkg/chart/loader/load.go b/pkg/chart/loader/load.go index f04c0e9b3..3c38519bc 100644 --- a/pkg/chart/loader/load.go +++ b/pkg/chart/loader/load.go @@ -74,6 +74,7 @@ func LoadFiles(files []*BufferedFile) (*chart.Chart, error) { subcharts := make(map[string][]*BufferedFile) for _, f := range files { + c.Raw = append(c.Raw, &chart.File{Name: f.Name, Data: f.Data}) switch { case f.Name == "Chart.yaml": if c.Metadata == nil { diff --git a/pkg/chart/loader/load_test.go b/pkg/chart/loader/load_test.go index 96b4dc608..6576002eb 100644 --- a/pkg/chart/loader/load_test.go +++ b/pkg/chart/loader/load_test.go @@ -179,6 +179,10 @@ icon: https://example.com/64x64.png t.Error("Expected chart values to be populated with default values") } + if len(c.Raw) != 5 { + t.Errorf("Expected %d files, got %d", 5, len(c.Raw)) + } + if !bytes.Equal(c.Schema, []byte("type: Values")) { t.Error("Expected chart schema to be populated with default values") } From 3e09e2fa2831ab0b51678171b7934cf9e6b4f8a7 Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Wed, 6 Nov 2019 09:36:29 -0500 Subject: [PATCH 10/65] fix(cli): Sort output of helm env Before this change, running 'helm env' multiple times would generate a different order for the output each time. This is because Go purposely loops over hash maps in a random order. This commit sorts the environment variables by alphabetical order before generating the output. Signed-off-by: Marc Khouzam --- cmd/helm/env.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/cmd/helm/env.go b/cmd/helm/env.go index 1b9cb4012..2687272ba 100644 --- a/cmd/helm/env.go +++ b/cmd/helm/env.go @@ -19,6 +19,7 @@ package main import ( "fmt" "io" + "sort" "helm.sh/helm/v3/pkg/cli" @@ -55,8 +56,18 @@ type envOptions struct { } func (o *envOptions) run(out io.Writer) error { - for k, v := range o.settings.EnvVars() { - fmt.Printf("%s=\"%s\"\n", k, v) + envVars := o.settings.EnvVars() + + // Sort the variables by alphabetical order. + // This allows for a constant output across calls to 'helm env'. + var keys []string + for k := range envVars { + keys = append(keys, k) + } + sort.Strings(keys) + + for _, k := range keys { + fmt.Printf("%s=\"%s\"\n", k, envVars[k]) } return nil } From 865c46c014cdb7622f97ae287ee92fb8a280f3a9 Mon Sep 17 00:00:00 2001 From: Matt Butcher Date: Thu, 7 Nov 2019 16:16:36 -0700 Subject: [PATCH 11/65] fix: stop discovery errors from halting chart rendering. (#6908) This blocks a particular error (caused by upstream discovery client), printing a warning instead of failing. It's not a great solution, but is a stop-gap until Client-Go gets fixed. Closes #6361 Signed-off-by: Matt Butcher --- pkg/action/action.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/pkg/action/action.go b/pkg/action/action.go index 48d6bf742..f74a25e41 100644 --- a/pkg/action/action.go +++ b/pkg/action/action.go @@ -109,9 +109,19 @@ func (c *Configuration) getCapabilities() (*chartutil.Capabilities, error) { if err != nil { return nil, errors.Wrap(err, "could not get server version from Kubernetes") } + // Issue #6361: + // Client-Go emits an error when an API service is registered but unimplemented. + // We trap that error here and print a warning. But since the discovery client continues + // building the API object, it is correctly populated with all valid APIs. + // See https://github.com/kubernetes/kubernetes/issues/72051#issuecomment-521157642 apiVersions, err := GetVersionSet(dc) if err != nil { - return nil, errors.Wrap(err, "could not get apiVersions from Kubernetes") + if discovery.IsGroupDiscoveryFailedError(err) { + c.Log("WARNING: The Kubernetes server has an orphaned API service. Server reports: %s", err) + c.Log("WARNING: To fix this, kubectl delete apiservice ") + } else { + return nil, errors.Wrap(err, "could not get apiVersions from Kubernetes") + } } c.Capabilities = &chartutil.Capabilities{ From aa6104e442ef8b574ae88efd8b5c41004437ac88 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Fri, 8 Nov 2019 07:32:50 -0800 Subject: [PATCH 12/65] fix(tlsutil): accept only a CA certificate for validation Signed-off-by: Matthew Fisher --- internal/tlsutil/tls.go | 16 ++++++---- internal/tlsutil/tlsutil_test.go | 51 ++++++++++++++++++++++++++++++++ pkg/getter/httpgetter.go | 2 +- pkg/getter/httpgetter_test.go | 10 +++++++ 4 files changed, 72 insertions(+), 7 deletions(-) diff --git a/internal/tlsutil/tls.go b/internal/tlsutil/tls.go index dc123e1e5..ed7795dbe 100644 --- a/internal/tlsutil/tls.go +++ b/internal/tlsutil/tls.go @@ -26,13 +26,16 @@ import ( // NewClientTLS returns tls.Config appropriate for client auth. func NewClientTLS(certFile, keyFile, caFile string) (*tls.Config, error) { - cert, err := CertFromFilePair(certFile, keyFile) - if err != nil { - return nil, err - } - config := tls.Config{ - Certificates: []tls.Certificate{*cert}, + config := tls.Config{} + + if certFile != "" && keyFile != "" { + cert, err := CertFromFilePair(certFile, keyFile) + if err != nil { + return nil, err + } + config.Certificates = []tls.Certificate{*cert} } + if caFile != "" { cp, err := CertPoolFromFile(caFile) if err != nil { @@ -40,6 +43,7 @@ func NewClientTLS(certFile, keyFile, caFile string) (*tls.Config, error) { } config.RootCAs = cp } + return &config, nil } diff --git a/internal/tlsutil/tlsutil_test.go b/internal/tlsutil/tlsutil_test.go index c2a477272..a737226fd 100644 --- a/internal/tlsutil/tlsutil_test.go +++ b/internal/tlsutil/tlsutil_test.go @@ -81,3 +81,54 @@ func testfile(t *testing.T, file string) (path string) { } return path } + +func TestNewClientTLS(t *testing.T) { + certFile := testfile(t, testCertFile) + keyFile := testfile(t, testKeyFile) + caCertFile := testfile(t, testCaCertFile) + + cfg, err := NewClientTLS(certFile, keyFile, caCertFile) + if err != nil { + t.Error(err) + } + + if got := len(cfg.Certificates); got != 1 { + t.Fatalf("expecting 1 client certificates, got %d", got) + } + if cfg.InsecureSkipVerify { + t.Fatalf("insecure skip verify mistmatch, expecting false") + } + if cfg.RootCAs == nil { + t.Fatalf("mismatch tls RootCAs, expecting non-nil") + } + + cfg, err = NewClientTLS("", "", caCertFile) + if err != nil { + t.Error(err) + } + + if got := len(cfg.Certificates); got != 0 { + t.Fatalf("expecting 0 client certificates, got %d", got) + } + if cfg.InsecureSkipVerify { + t.Fatalf("insecure skip verify mistmatch, expecting false") + } + if cfg.RootCAs == nil { + t.Fatalf("mismatch tls RootCAs, expecting non-nil") + } + + cfg, err = NewClientTLS(certFile, keyFile, "") + if err != nil { + t.Error(err) + } + + if got := len(cfg.Certificates); got != 1 { + t.Fatalf("expecting 1 client certificates, got %d", got) + } + if cfg.InsecureSkipVerify { + t.Fatalf("insecure skip verify mistmatch, expecting false") + } + if cfg.RootCAs != nil { + t.Fatalf("mismatch tls RootCAs, expecting nil") + } +} diff --git a/pkg/getter/httpgetter.go b/pkg/getter/httpgetter.go index a36ab0321..89abfb1cf 100644 --- a/pkg/getter/httpgetter.go +++ b/pkg/getter/httpgetter.go @@ -89,7 +89,7 @@ func NewHTTPGetter(options ...Option) (Getter, error) { } func (g *HTTPGetter) httpClient() (*http.Client, error) { - if g.opts.certFile != "" && g.opts.keyFile != "" { + if (g.opts.certFile != "" && g.opts.keyFile != "") || g.opts.caFile != "" { tlsConf, err := tlsutil.NewClientTLS(g.opts.certFile, g.opts.keyFile, g.opts.caFile) if err != nil { return nil, errors.Wrap(err, "can't create TLS config for client") diff --git a/pkg/getter/httpgetter_test.go b/pkg/getter/httpgetter_test.go index 0c2c55ea3..b20085574 100644 --- a/pkg/getter/httpgetter_test.go +++ b/pkg/getter/httpgetter_test.go @@ -180,4 +180,14 @@ func TestDownloadTLS(t *testing.T) { if _, err := g.Get(u.String(), WithURL(u.String()), WithTLSClientConfig(pub, priv, ca)); err != nil { t.Error(err) } + + // test with only the CA file (see also #6635) + g, err = NewHTTPGetter() + if err != nil { + t.Fatal(err) + } + + if _, err := g.Get(u.String(), WithURL(u.String()), WithTLSClientConfig("", "", ca)); err != nil { + t.Error(err) + } } From 9ed2a28eded7678ccc26f2079fa815eefb489683 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Fri, 8 Nov 2019 07:39:57 -0800 Subject: [PATCH 13/65] ref(tlsutil): remove ServerConfig dead code from Tiller days Signed-off-by: Matthew Fisher --- internal/tlsutil/cfg.go | 29 ++--------------------------- internal/tlsutil/tlsutil_test.go | 21 --------------------- 2 files changed, 2 insertions(+), 48 deletions(-) diff --git a/internal/tlsutil/cfg.go b/internal/tlsutil/cfg.go index f40258739..8b9d4329f 100644 --- a/internal/tlsutil/cfg.go +++ b/internal/tlsutil/cfg.go @@ -27,18 +27,14 @@ import ( // Options represents configurable options used to create client and server TLS configurations. type Options struct { CaCertFile string - // If either the KeyFile or CertFile is empty, ClientConfig() will not load them, - // preventing Helm from authenticating to Tiller. They are required to be non-empty - // when calling ServerConfig, otherwise an error is returned. + // If either the KeyFile or CertFile is empty, ClientConfig() will not load them. KeyFile string CertFile string // Client-only options InsecureSkipVerify bool - // Server-only options - 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 @@ -60,24 +56,3 @@ func ClientConfig(opts Options) (cfg *tls.Config, err error) { cfg = &tls.Config{InsecureSkipVerify: opts.InsecureSkipVerify, Certificates: []tls.Certificate{*cert}, RootCAs: pool} return cfg, nil } - -// ServerConfig returns a TLS configuration for use by the Tiller server. -func ServerConfig(opts Options) (cfg *tls.Config, err error) { - var cert *tls.Certificate - var pool *x509.CertPool - - if cert, err = CertFromFilePair(opts.CertFile, opts.KeyFile); err != nil { - if os.IsNotExist(err) { - return nil, errors.Wrapf(err, "could not load x509 key pair (cert: %q, key: %q)", opts.CertFile, opts.KeyFile) - } - return nil, errors.Wrapf(err, "could not read x509 key pair (cert: %q, key: %q)", opts.CertFile, opts.KeyFile) - } - if opts.ClientAuth >= tls.VerifyClientCertIfGiven && opts.CaCertFile != "" { - if pool, err = CertPoolFromFile(opts.CaCertFile); err != nil { - return nil, err - } - } - - cfg = &tls.Config{MinVersion: tls.VersionTLS12, ClientAuth: opts.ClientAuth, Certificates: []tls.Certificate{*cert}, ClientCAs: pool} - return cfg, nil -} diff --git a/internal/tlsutil/tlsutil_test.go b/internal/tlsutil/tlsutil_test.go index c2a477272..811d64aa0 100644 --- a/internal/tlsutil/tlsutil_test.go +++ b/internal/tlsutil/tlsutil_test.go @@ -17,7 +17,6 @@ limitations under the License. package tlsutil import ( - "crypto/tls" "path/filepath" "testing" ) @@ -54,26 +53,6 @@ func TestClientConfig(t *testing.T) { } } -func TestServerConfig(t *testing.T) { - opts := Options{ - CaCertFile: testfile(t, testCaCertFile), - CertFile: testfile(t, testCertFile), - KeyFile: testfile(t, testKeyFile), - ClientAuth: tls.RequireAndVerifyClientCert, - } - - cfg, err := ServerConfig(opts) - if err != nil { - t.Fatalf("error building tls server config: %v", err) - } - if got := cfg.MinVersion; got != tls.VersionTLS12 { - t.Errorf("expecting TLS version 1.2, got %d", got) - } - if got := cfg.ClientCAs; got == nil { - t.Errorf("expecting non-nil CA pool") - } -} - func testfile(t *testing.T, file string) (path string) { var err error if path, err = filepath.Abs(filepath.Join(tlsTestDir, file)); err != nil { From 30e8ed2f3df9e776b5a5937d92e8ff45c54f984f Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Fri, 8 Nov 2019 17:22:47 -0500 Subject: [PATCH 14/65] fix(cli): helm list was ignoring some errors If the cluster is not reachable, helm list would not report that error. Signed-off-by: Marc Khouzam --- cmd/helm/list.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cmd/helm/list.go b/cmd/helm/list.go index 32501530d..83edfe156 100644 --- a/cmd/helm/list.go +++ b/cmd/helm/list.go @@ -77,12 +77,15 @@ func newListCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { client.SetStateMask() results, err := client.Run() + if err != nil { + return err + } if client.Short { for _, res := range results { fmt.Fprintln(out, res.Name) } - return err + return nil } return outfmt.Write(out, newReleaseListWriter(results)) From 693bce93a073d1086f86cb119f96b306bbb2bc80 Mon Sep 17 00:00:00 2001 From: sayboras Date: Sat, 9 Nov 2019 19:56:45 +1100 Subject: [PATCH 15/65] Used timeout instead of deadline Signed-off-by: sayboras --- .golangci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.golangci.yml b/.golangci.yml index 601d98661..2c3b6234d 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,5 +1,5 @@ run: - deadline: 2m + timeout: 2m linters: disable-all: true From 4d1c11f05bf732bf914d5529493fc77d5134d1c9 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Tue, 12 Nov 2019 09:36:08 -0800 Subject: [PATCH 16/65] fix(ci): pin golangci-lint to v1.21.0 Signed-off-by: Matthew Fisher --- .circleci/bootstrap.sh | 20 ++++++++++++++++++++ .circleci/config.yml | 4 ++++ Makefile | 8 ++------ 3 files changed, 26 insertions(+), 6 deletions(-) create mode 100755 .circleci/bootstrap.sh diff --git a/.circleci/bootstrap.sh b/.circleci/bootstrap.sh new file mode 100755 index 000000000..79d194077 --- /dev/null +++ b/.circleci/bootstrap.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +# 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. +set -euo pipefail + +curl -sSL https://github.com/golangci/golangci-lint/releases/download/v$GOLANGCI_LINT_VERSION/golangci-lint-$GOLANGCI_LINT_VERSION-linux-amd64.tar.gz | tar xz +sudo mv golangci-lint-$GOLANGCI_LINT_VERSION-linux-amd64/golangci-lint /usr/local/bin/golangci-lint +rm -rf golangci-lint-$GOLANGCI_LINT_VERSION-linux-amd64 diff --git a/.circleci/config.yml b/.circleci/config.yml index db7182adb..ef19b8ee7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -9,9 +9,13 @@ jobs: environment: GOCACHE: "/tmp/go/cache" + GOLANGCI_LINT_VERSION: "1.21.0" steps: - checkout + - run: + name: install test dependencies + command: .circleci/bootstrap.sh - run: name: test style command: make test-style diff --git a/Makefile b/Makefile index b52464ba9..e48a20fd5 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,6 @@ GOPATH = $(shell go env GOPATH) DEP = $(GOPATH)/bin/dep GOX = $(GOPATH)/bin/gox GOIMPORTS = $(GOPATH)/bin/goimports -GOLANGCI_LINT = $(GOPATH)/bin/golangci-lint ACCEPTANCE_DIR:=$(GOPATH)/src/helm.sh/acceptance-testing # To specify the subset of acceptance tests to run. '.' means all tests @@ -81,8 +80,8 @@ test-coverage: @ ./scripts/coverage.sh .PHONY: test-style -test-style: $(GOLANGCI_LINT) - GO111MODULE=on $(GOLANGCI_LINT) run +test-style: + GO111MODULE=on golangci-lint run @scripts/validate-license.sh .PHONY: test-acceptance @@ -118,9 +117,6 @@ format: $(GOIMPORTS) $(GOX): (cd /; GO111MODULE=on go get -u github.com/mitchellh/gox) -$(GOLANGCI_LINT): - (cd /; GO111MODULE=on go get -u github.com/golangci/golangci-lint/cmd/golangci-lint) - $(GOIMPORTS): (cd /; GO111MODULE=on go get -u golang.org/x/tools/cmd/goimports) From b30467c2e52ffebd0b4708ca318d34251ab5a692 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Tue, 12 Nov 2019 08:34:58 -0800 Subject: [PATCH 17/65] fix(strvals): port #3912, #4142, #4682, and #5151 to Helm 3 Signed-off-by: Matthew Fisher --- pkg/strvals/parser.go | 30 ++++++++++-- pkg/strvals/parser_test.go | 95 +++++++++++++++++++++++++++++++++++++- 2 files changed, 119 insertions(+), 6 deletions(-) diff --git a/pkg/strvals/parser.go b/pkg/strvals/parser.go index eaadbfb07..03adbd3cb 100644 --- a/pkg/strvals/parser.go +++ b/pkg/strvals/parser.go @@ -84,7 +84,7 @@ func ParseFile(s string, reader RunesValueReader) (map[string]interface{}, error return vals, err } -// ParseIntoString parses a strvals line nad merges the result into dest. +// ParseIntoString parses a strvals line and merges the result into dest. // // This method always returns a string as the value. func ParseIntoString(s string, dest map[string]interface{}) error { @@ -108,6 +108,9 @@ type RunesValueReader func([]rune) (interface{}, error) // parser is a simple parser that takes a strvals line and parses it into a // map representation. +// +// where sc is the source of the original data being parsed +// where data is the final parsed data from the parses with correct types type parser struct { sc *bytes.Buffer data map[string]interface{} @@ -285,7 +288,13 @@ func (t *parser) listItem(list []interface{}, i int) ([]interface{}, error) { // We have a nested object. Send to t.key inner := map[string]interface{}{} if len(list) > i { - inner = list[i].(map[string]interface{}) + var ok bool + inner, ok = list[i].(map[string]interface{}) + if !ok { + // We have indices out of order. Initialize empty value. + list[i] = map[string]interface{}{} + inner = list[i].(map[string]interface{}) + } } // Recurse @@ -367,6 +376,11 @@ func inMap(k rune, m map[rune]bool) bool { func typedVal(v []rune, st bool) interface{} { val := string(v) + + if st { + return val + } + if strings.EqualFold(val, "true") { return true } @@ -375,8 +389,16 @@ func typedVal(v []rune, st bool) interface{} { return false } - // If this value does not start with zero, and not returnString, try parsing it to an int - if !st && len(val) != 0 && val[0] != '0' { + if strings.EqualFold(val, "null") { + 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 { return iv } diff --git a/pkg/strvals/parser_test.go b/pkg/strvals/parser_test.go index ff8d58587..7f38efa52 100644 --- a/pkg/strvals/parser_test.go +++ b/pkg/strvals/parser_test.go @@ -75,12 +75,32 @@ func TestParseSet(t *testing.T) { expect: map[string]interface{}{"long_int_string": "1234567890"}, err: false, }, + { + str: "boolean=true", + expect: map[string]interface{}{"boolean": "true"}, + err: false, + }, + { + str: "is_null=null", + expect: map[string]interface{}{"is_null": "null"}, + err: false, + }, + { + str: "zero=0", + expect: map[string]interface{}{"zero": "0"}, + err: false, + }, } tests := []struct { str string expect map[string]interface{} err bool }{ + { + "name1=null,f=false,t=true", + map[string]interface{}{"name1": nil, "f": false, "t": true}, + false, + }, { "name1=value1", map[string]interface{}{"name1": "value1"}, @@ -108,10 +128,23 @@ 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}, }, + { + str: "boolean=true", + expect: map[string]interface{}{"boolean": true}, + }, + { + str: "is_null=null", + expect: map[string]interface{}{"is_null": nil}, + err: false, + }, { str: "name1,name2=", err: true, @@ -270,6 +303,30 @@ func TestParseSet(t *testing.T) { str: "nested[1][1]=1", expect: map[string]interface{}{"nested": []interface{}{nil, []interface{}{nil, 1}}}, }, + { + str: "name1.name2[0].foo=bar,name1.name2[1].foo=bar", + expect: map[string]interface{}{ + "name1": map[string]interface{}{ + "name2": []map[string]interface{}{{"foo": "bar"}, {"foo": "bar"}}, + }, + }, + }, + { + str: "name1.name2[1].foo=bar,name1.name2[0].foo=bar", + expect: map[string]interface{}{ + "name1": map[string]interface{}{ + "name2": []map[string]interface{}{{"foo": "bar"}, {"foo": "bar"}}, + }, + }, + }, + { + str: "name1.name2[1].foo=bar", + expect: map[string]interface{}{ + "name1": map[string]interface{}{ + "name2": []map[string]interface{}{nil, {"foo": "bar"}}, + }, + }, + }, } for _, tt := range tests { @@ -331,12 +388,13 @@ func TestParseInto(t *testing.T) { "inner2": "value2", }, } - input := "outer.inner1=value1,outer.inner3=value3" + input := "outer.inner1=value1,outer.inner3=value3,outer.inner4=4" expect := map[string]interface{}{ "outer": map[string]interface{}{ "inner1": "value1", "inner2": "value2", "inner3": "value3", + "inner4": 4, }, } @@ -357,6 +415,39 @@ func TestParseInto(t *testing.T) { t.Errorf("%s: Expected:\n%s\nGot:\n%s", input, y1, y2) } } +func TestParseIntoString(t *testing.T) { + got := map[string]interface{}{ + "outer": map[string]interface{}{ + "inner1": "overwrite", + "inner2": "value2", + }, + } + input := "outer.inner1=1,outer.inner3=3" + expect := map[string]interface{}{ + "outer": map[string]interface{}{ + "inner1": "1", + "inner2": "value2", + "inner3": "3", + }, + } + + if err := ParseIntoString(input, got); err != nil { + t.Fatal(err) + } + + y1, err := yaml.Marshal(expect) + if err != nil { + t.Fatal(err) + } + y2, err := yaml.Marshal(got) + if err != nil { + t.Fatalf("Error serializing parsed value: %s", err) + } + + if string(y1) != string(y2) { + t.Errorf("%s: Expected:\n%s\nGot:\n%s", input, y1, y2) + } +} func TestParseIntoFile(t *testing.T) { got := map[string]interface{}{} @@ -367,7 +458,7 @@ func TestParseIntoFile(t *testing.T) { rs2v := func(rs []rune) (interface{}, error) { v := string(rs) if v != "path1" { - t.Errorf("%s: RunesValueReader: Expected value path1, got %s", input, v) + t.Errorf("%s: runesToVal: Expected value path1, got %s", input, v) return "", nil } return "value1", nil From 17553db485f6165c15aa17c6dfcc7589edb025ee Mon Sep 17 00:00:00 2001 From: Hang Park Date: Wed, 13 Nov 2019 02:33:27 +0900 Subject: [PATCH 18/65] fix(pkg/downloader): add failing test for build with repo alias Signed-off-by: Hang Park --- pkg/downloader/manager_test.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pkg/downloader/manager_test.go b/pkg/downloader/manager_test.go index 0c5c08615..d6cae4e51 100644 --- a/pkg/downloader/manager_test.go +++ b/pkg/downloader/manager_test.go @@ -181,7 +181,8 @@ func TestGetRepoNames(t *testing.T) { } } -// This function is the skeleton test code of failing tests for #6416 and bugs due to #5874. +// This function is the skeleton test code of failing tests for #6416 and #6871 and bugs due to #5874. +// // This function is used by below tests that ensures success of build operation // with optional fields, alias, condition, tags, and even with ranged version. // Parent chart includes local-subchart 0.1.0 subchart from a fake repository, by default. @@ -283,3 +284,11 @@ func TestBuild_WithTags(t *testing.T) { Tags: []string{"tag1", "tag2"}, }) } + +// Failing test for #6871 +func TestBuild_WithRepositoryAlias(t *testing.T) { + // Dependency repository is aliased in Chart.yaml + checkBuildWithOptionalFields(t, "with-repository-alias", chart.Dependency{ + Repository: "@test", + }) +} From 0987c6f7b91bffc360a8c604b9dfb87b845cc919 Mon Sep 17 00:00:00 2001 From: Hang Park Date: Wed, 13 Nov 2019 02:35:48 +0900 Subject: [PATCH 19/65] fix(pkg/downloader): resolve repo alias before checking digests on build `Update()` gets repo names before resolving a lock file by calling `resolveRepoNames(req)`. But that method changes aliased repo URLs into the actual URLs. That makes digests from `helm update` and `helm build` be different for each other. To make them in sync, setting actual (resolved) repo URLs into the loaded chart during `helm build` is necessary. Thus, this commit adds an extra step in the `Build()` implementation. For comments, this commit also changes the name of `getRepoNames()` into `resolveRepoNames()` to avoid misunderstanding since getters are expected to not mutate their input data in general. Signed-off-by: Hang Park --- pkg/downloader/manager.go | 12 +++++++++--- pkg/downloader/manager_test.go | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index 407e7ffe4..4e9d691d8 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -79,7 +79,12 @@ func (m *Manager) Build() error { return m.Update() } + // Check that all of the repos we're dependent on actually exist. req := c.Metadata.Dependencies + if _, err := m.resolveRepoNames(req); err != nil { + return err + } + if sum, err := resolver.HashReq(req, lock.Dependencies); err != nil || sum != lock.Digest { return errors.New("Chart.lock is out of sync with Chart.yaml") } @@ -120,7 +125,7 @@ func (m *Manager) Update() error { // Check that all of the repos we're dependent on actually exist and // the repo index names. - repoNames, err := m.getRepoNames(req) + repoNames, err := m.resolveRepoNames(req) if err != nil { return err } @@ -372,8 +377,9 @@ Loop: return nil } -// getRepoNames returns the repo names of the referenced deps which can be used to fetch the cahced index file. -func (m *Manager) getRepoNames(deps []*chart.Dependency) (map[string]string, error) { +// resolveRepoNames returns the repo names of the referenced deps which can be used to fetch the cached index file +// and replaces aliased repository URLs into resolved URLs in dependencies. +func (m *Manager) resolveRepoNames(deps []*chart.Dependency) (map[string]string, error) { rf, err := loadRepoConfig(m.RepositoryConfig) if err != nil { if os.IsNotExist(err) { diff --git a/pkg/downloader/manager_test.go b/pkg/downloader/manager_test.go index d6cae4e51..6e32b3e85 100644 --- a/pkg/downloader/manager_test.go +++ b/pkg/downloader/manager_test.go @@ -161,7 +161,7 @@ func TestGetRepoNames(t *testing.T) { } for _, tt := range tests { - l, err := m.getRepoNames(tt.req) + l, err := m.resolveRepoNames(tt.req) if err != nil { if tt.err { continue From e91feed1a3c34ec15ff2bff4d07ee5e275a6d7b4 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Tue, 12 Nov 2019 13:12:45 -0800 Subject: [PATCH 20/65] fix(install): log the error when recording the release Signed-off-by: Matthew Fisher --- pkg/action/install.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/action/install.go b/pkg/action/install.go index 8f1b5528b..65c10f636 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -301,7 +301,9 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release. // // One possible strategy would be to do a timed retry to see if we can get // this stored in the future. - i.recordRelease(rel) + if err := i.recordRelease(rel); err != nil { + i.cfg.Log("failed to record the release: %s", err) + } return rel, nil } From a9b178758c6c3c3f36f6bbd7a1b4359efae27366 Mon Sep 17 00:00:00 2001 From: flynnduism Date: Tue, 12 Nov 2019 14:27:30 -0800 Subject: [PATCH 21/65] fix(reame): update links to docs Signed-off-by: flynnduism --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9af358e10..fbabf7e44 100644 --- a/README.md +++ b/README.md @@ -44,12 +44,12 @@ If you want to use a package manager: To rapidly get Helm up and running, start with the [Quick Start Guide](https://docs.helm.sh/using_helm/#quickstart-guide). -See the [installation guide](https://docs.helm.sh/using_helm/#installing-helm) for more options, +See the [installation guide](https://helm.sh/docs/intro/install/) for more options, including installing pre-releases. ## Docs -Get started with the [Quick Start guide](https://docs.helm.sh/using_helm/#quickstart-guide) or plunge into the [complete documentation](https://docs.helm.sh) +Get started with the [Quick Start guide](https://helm.sh/docs/intro/quickstart/) or plunge into the [complete documentation](https://helm.sh/docs) ## Roadmap From 06a5eb2272f26fcdb2bd5abf5abe45d7078b5e50 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Tue, 12 Nov 2019 18:11:56 -0800 Subject: [PATCH 22/65] fix(get): install Helm v2.16.1 This is a temporary fix. This prevents the get script from installing Helm 3 as soon as it's released, potentially causing disruption to users that were expecting a Helm 2 release. A `get-helm-3` script is also supplied, which is identical to the previous `get` script. That way, Helm 3 users also have an equivalent way to install Helm 3. Signed-off-by: Matthew Fisher --- scripts/get | 6 +- scripts/get-helm-3 | 245 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 249 insertions(+), 2 deletions(-) create mode 100755 scripts/get-helm-3 diff --git a/scripts/get b/scripts/get index 3f645f807..a264f8f76 100755 --- a/scripts/get +++ b/scripts/get @@ -187,7 +187,7 @@ testVersion() { help () { echo "Accepted cli arguments are:" echo -e "\t[--help|-h ] ->> prints this help" - echo -e "\t[--version|-v ] . When not defined it defaults to latest" + echo -e "\t[--version|-v ]" echo -e "\te.g. --version v2.4.0 or -v latest" echo -e "\t[--no-sudo] ->> install without sudo" } @@ -213,7 +213,9 @@ while [[ $# -gt 0 ]]; do '--version'|-v) shift if [[ $# -ne 0 ]]; then - export DESIRED_VERSION="${1}" + # FIXME(bacongobbler): hard code the desired version for the time being. + # A better fix would be to filter for Helm 2 release pages. + export DESIRED_VERSION="${1:="v2.16.1"}" else echo -e "Please provide the desired version. e.g. --version v2.4.0 or -v latest" exit 0 diff --git a/scripts/get-helm-3 b/scripts/get-helm-3 new file mode 100755 index 000000000..3f645f807 --- /dev/null +++ b/scripts/get-helm-3 @@ -0,0 +1,245 @@ +#!/usr/bin/env bash + +# 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. + +# The install script is based off of the MIT-licensed script from glide, +# the package manager for Go: https://github.com/Masterminds/glide.sh/blob/master/get + +PROJECT_NAME="helm" +TILLER_NAME="tiller" + +: ${USE_SUDO:="true"} +: ${HELM_INSTALL_DIR:="/usr/local/bin"} + +# initArch discovers the architecture for this system. +initArch() { + ARCH=$(uname -m) + case $ARCH in + armv5*) ARCH="armv5";; + armv6*) ARCH="armv6";; + armv7*) ARCH="arm";; + aarch64) ARCH="arm64";; + x86) ARCH="386";; + x86_64) ARCH="amd64";; + i686) ARCH="386";; + i386) ARCH="386";; + esac +} + +# initOS discovers the operating system for this system. +initOS() { + OS=$(echo `uname`|tr '[:upper:]' '[:lower:]') + + case "$OS" in + # Minimalist GNU for Windows + mingw*) OS='windows';; + esac +} + +# runs the given command as root (detects if we are root already) +runAsRoot() { + local CMD="$*" + + if [ $EUID -ne 0 -a $USE_SUDO = "true" ]; then + CMD="sudo $CMD" + fi + + $CMD +} + +# verifySupported checks that the os/arch combination is supported for +# binary builds. +verifySupported() { + local supported="darwin-386\ndarwin-amd64\nlinux-386\nlinux-amd64\nlinux-arm\nlinux-arm64\nlinux-ppc64le\nwindows-386\nwindows-amd64" + if ! echo "${supported}" | grep -q "${OS}-${ARCH}"; then + echo "No prebuilt binary for ${OS}-${ARCH}." + echo "To build from source, go to https://github.com/helm/helm" + exit 1 + fi + + if ! type "curl" > /dev/null && ! type "wget" > /dev/null; then + echo "Either curl or wget is required" + exit 1 + fi +} + +# checkDesiredVersion checks if the desired version is available. +checkDesiredVersion() { + if [ "x$DESIRED_VERSION" == "x" ]; then + # Get tag from release URL + local latest_release_url="https://github.com/helm/helm/releases/latest" + if type "curl" > /dev/null; then + TAG=$(curl -Ls -o /dev/null -w %{url_effective} $latest_release_url | grep -oE "[^/]+$" ) + elif type "wget" > /dev/null; then + TAG=$(wget $latest_release_url --server-response -O /dev/null 2>&1 | awk '/^ Location: /{DEST=$2} END{ print DEST}' | grep -oE "[^/]+$") + fi + else + TAG=$DESIRED_VERSION + fi +} + +# checkHelmInstalledVersion checks which version of helm is installed and +# if it needs to be changed. +checkHelmInstalledVersion() { + if [[ -f "${HELM_INSTALL_DIR}/${PROJECT_NAME}" ]]; then + local version=$("${HELM_INSTALL_DIR}/${PROJECT_NAME}" version -c | grep '^Client' | cut -d'"' -f2) + if [[ "$version" == "$TAG" ]]; then + echo "Helm ${version} is already ${DESIRED_VERSION:-latest}" + return 0 + else + echo "Helm ${TAG} is available. Changing from version ${version}." + return 1 + fi + else + return 1 + fi +} + +# downloadFile downloads the latest binary package and also the checksum +# for that binary. +downloadFile() { + HELM_DIST="helm-$TAG-$OS-$ARCH.tar.gz" + DOWNLOAD_URL="https://get.helm.sh/$HELM_DIST" + CHECKSUM_URL="$DOWNLOAD_URL.sha256" + HELM_TMP_ROOT="$(mktemp -dt helm-installer-XXXXXX)" + HELM_TMP_FILE="$HELM_TMP_ROOT/$HELM_DIST" + HELM_SUM_FILE="$HELM_TMP_ROOT/$HELM_DIST.sha256" + echo "Downloading $DOWNLOAD_URL" + if type "curl" > /dev/null; then + curl -SsL "$CHECKSUM_URL" -o "$HELM_SUM_FILE" + elif type "wget" > /dev/null; then + wget -q -O "$HELM_SUM_FILE" "$CHECKSUM_URL" + fi + if type "curl" > /dev/null; then + curl -SsL "$DOWNLOAD_URL" -o "$HELM_TMP_FILE" + elif type "wget" > /dev/null; then + wget -q -O "$HELM_TMP_FILE" "$DOWNLOAD_URL" + fi +} + +# installFile verifies the SHA256 for the file, then unpacks and +# installs it. +installFile() { + HELM_TMP="$HELM_TMP_ROOT/$PROJECT_NAME" + local sum=$(openssl sha1 -sha256 ${HELM_TMP_FILE} | awk '{print $2}') + local expected_sum=$(cat ${HELM_SUM_FILE}) + if [ "$sum" != "$expected_sum" ]; then + echo "SHA sum of ${HELM_TMP_FILE} does not match. Aborting." + exit 1 + fi + + mkdir -p "$HELM_TMP" + tar xf "$HELM_TMP_FILE" -C "$HELM_TMP" + HELM_TMP_BIN="$HELM_TMP/$OS-$ARCH/$PROJECT_NAME" + TILLER_TMP_BIN="$HELM_TMP/$OS-$ARCH/$TILLER_NAME" + echo "Preparing to install $PROJECT_NAME and $TILLER_NAME into ${HELM_INSTALL_DIR}" + runAsRoot cp "$HELM_TMP_BIN" "$HELM_INSTALL_DIR" + echo "$PROJECT_NAME installed into $HELM_INSTALL_DIR/$PROJECT_NAME" + if [ -x "$TILLER_TMP_BIN" ]; then + runAsRoot cp "$TILLER_TMP_BIN" "$HELM_INSTALL_DIR" + echo "$TILLER_NAME installed into $HELM_INSTALL_DIR/$TILLER_NAME" + else + echo "info: $TILLER_NAME binary was not found in this release; skipping $TILLER_NAME installation" + fi +} + +# fail_trap is executed if an error occurs. +fail_trap() { + result=$? + if [ "$result" != "0" ]; then + if [[ -n "$INPUT_ARGUMENTS" ]]; then + echo "Failed to install $PROJECT_NAME with the arguments provided: $INPUT_ARGUMENTS" + help + else + echo "Failed to install $PROJECT_NAME" + fi + echo -e "\tFor support, go to https://github.com/helm/helm." + fi + cleanup + exit $result +} + +# testVersion tests the installed client to make sure it is working. +testVersion() { + set +e + HELM="$(which $PROJECT_NAME)" + if [ "$?" = "1" ]; then + echo "$PROJECT_NAME not found. Is $HELM_INSTALL_DIR on your "'$PATH?' + exit 1 + fi + set -e + echo "Run '$PROJECT_NAME init' to configure $PROJECT_NAME." +} + +# help provides possible cli installation arguments +help () { + echo "Accepted cli arguments are:" + echo -e "\t[--help|-h ] ->> prints this help" + echo -e "\t[--version|-v ] . When not defined it defaults to latest" + echo -e "\te.g. --version v2.4.0 or -v latest" + echo -e "\t[--no-sudo] ->> install without sudo" +} + +# cleanup temporary files to avoid https://github.com/helm/helm/issues/2977 +cleanup() { + if [[ -d "${HELM_TMP_ROOT:-}" ]]; then + rm -rf "$HELM_TMP_ROOT" + fi +} + +# Execution + +#Stop execution on any error +trap "fail_trap" EXIT +set -e + +# Parsing input arguments (if any) +export INPUT_ARGUMENTS="${@}" +set -u +while [[ $# -gt 0 ]]; do + case $1 in + '--version'|-v) + shift + if [[ $# -ne 0 ]]; then + export DESIRED_VERSION="${1}" + else + echo -e "Please provide the desired version. e.g. --version v2.4.0 or -v latest" + exit 0 + fi + ;; + '--no-sudo') + USE_SUDO="false" + ;; + '--help'|-h) + help + exit 0 + ;; + *) exit 1 + ;; + esac + shift +done +set +u + +initArch +initOS +verifySupported +checkDesiredVersion +if ! checkHelmInstalledVersion; then + downloadFile + installFile +fi +testVersion +cleanup From ecb55c1de7bcc0063b2cf956a0e2172fcd75bc59 Mon Sep 17 00:00:00 2001 From: Taylor Thomas Date: Tue, 12 Nov 2019 19:41:01 -0700 Subject: [PATCH 23/65] fix(wait): Adds support for waiting on v1 apiextensions for CRDs This was a missed update when we updated the k8s libraries. I validated that this works for CRD installs with v1beta1 and v1 Signed-off-by: Taylor Thomas --- pkg/action/install.go | 2 +- pkg/kube/wait.go | 37 ++++++++++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/pkg/action/install.go b/pkg/action/install.go index 8f1b5528b..4019dbc54 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -126,7 +126,7 @@ func (i *Install) installCRDs(crds []*chart.File) error { i.cfg.Log("CRD %s is already present. Skipping.", crdName) continue } - return errors.Wrapf(err, "failed to instal CRD %s", obj.Name) + return errors.Wrapf(err, "failed to install CRD %s", obj.Name) } totalItems = append(totalItems, res...) } diff --git a/pkg/kube/wait.go b/pkg/kube/wait.go index 7198917c4..f0005a61e 100644 --- a/pkg/kube/wait.go +++ b/pkg/kube/wait.go @@ -27,6 +27,7 @@ import ( batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" extensionsv1beta1 "k8s.io/api/extensions/v1beta1" + apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" @@ -114,6 +115,17 @@ func (w *waiter) waitForResources(created ResourceList) error { if err := scheme.Scheme.Convert(v.Object, crd, nil); err != nil { return false, err } + if !w.crdBetaReady(*crd) { + return false, nil + } + case *apiextv1.CustomResourceDefinition: + if err := v.Get(); err != nil { + return false, err + } + crd := &apiextv1.CustomResourceDefinition{} + if err := scheme.Scheme.Convert(v.Object, crd, nil); err != nil { + return false, err + } if !w.crdReady(*crd) { return false, nil } @@ -229,7 +241,10 @@ func (w *waiter) daemonSetReady(ds *appsv1.DaemonSet) bool { return true } -func (w *waiter) crdReady(crd apiextv1beta1.CustomResourceDefinition) bool { +// Because the v1 extensions API is not available on all supported k8s versions +// yet and because Go doesn't support generics, we need to have a duplicate +// function to support the v1beta1 types +func (w *waiter) crdBetaReady(crd apiextv1beta1.CustomResourceDefinition) bool { for _, cond := range crd.Status.Conditions { switch cond.Type { case apiextv1beta1.Established: @@ -249,6 +264,26 @@ func (w *waiter) crdReady(crd apiextv1beta1.CustomResourceDefinition) bool { return false } +func (w *waiter) crdReady(crd apiextv1.CustomResourceDefinition) bool { + for _, cond := range crd.Status.Conditions { + switch cond.Type { + case apiextv1.Established: + if cond.Status == apiextv1.ConditionTrue { + return true + } + case apiextv1.NamesAccepted: + if cond.Status == apiextv1.ConditionFalse { + // This indicates a naming conflict, but it's probably not the + // job of this function to fail because of that. Instead, + // we treat it as a success, since the process should be able to + // continue. + return true + } + } + } + return false +} + func (w *waiter) statefulSetReady(sts *appsv1.StatefulSet) bool { // If the update strategy is not a rolling update, there will be nothing to wait for if sts.Spec.UpdateStrategy.Type != appsv1.RollingUpdateStatefulSetStrategyType { From 3e77ca22c71e182860b0ef9508d229e25d8f4140 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Tue, 12 Nov 2019 19:56:34 -0800 Subject: [PATCH 24/65] fix(get): hard code DESIRED_VERSION when unset Signed-off-by: Matthew Fisher --- scripts/get | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/scripts/get b/scripts/get index a264f8f76..711635ee3 100755 --- a/scripts/get +++ b/scripts/get @@ -78,13 +78,16 @@ verifySupported() { # checkDesiredVersion checks if the desired version is available. checkDesiredVersion() { if [ "x$DESIRED_VERSION" == "x" ]; then + # FIXME(bacongobbler): hard code the desired version for the time being. + # A better fix would be to filter for Helm 2 release pages. + TAG="v2.16.1" # Get tag from release URL - local latest_release_url="https://github.com/helm/helm/releases/latest" - if type "curl" > /dev/null; then - TAG=$(curl -Ls -o /dev/null -w %{url_effective} $latest_release_url | grep -oE "[^/]+$" ) - elif type "wget" > /dev/null; then - TAG=$(wget $latest_release_url --server-response -O /dev/null 2>&1 | awk '/^ Location: /{DEST=$2} END{ print DEST}' | grep -oE "[^/]+$") - fi + # local latest_release_url="https://github.com/helm/helm/releases/latest" + # if type "curl" > /dev/null; then + # TAG=$(curl -Ls -o /dev/null -w %{url_effective} $latest_release_url | grep -oE "[^/]+$" ) + # elif type "wget" > /dev/null; then + # TAG=$(wget $latest_release_url --server-response -O /dev/null 2>&1 | awk '/^ Location: /{DEST=$2} END{ print DEST}' | grep -oE "[^/]+$") + # fi else TAG=$DESIRED_VERSION fi @@ -213,9 +216,7 @@ while [[ $# -gt 0 ]]; do '--version'|-v) shift if [[ $# -ne 0 ]]; then - # FIXME(bacongobbler): hard code the desired version for the time being. - # A better fix would be to filter for Helm 2 release pages. - export DESIRED_VERSION="${1:="v2.16.1"}" + export DESIRED_VERSION="${1}" else echo -e "Please provide the desired version. e.g. --version v2.4.0 or -v latest" exit 0 From c9da1eaae780488ba34c7bb66c5bff518c6c06ee Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Tue, 12 Nov 2019 20:06:09 -0800 Subject: [PATCH 25/65] fix(get-helm-3): remove tiller checks, fixup version check Signed-off-by: Matthew Fisher --- scripts/get-helm-3 | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/scripts/get-helm-3 b/scripts/get-helm-3 index 3f645f807..c1655a68e 100755 --- a/scripts/get-helm-3 +++ b/scripts/get-helm-3 @@ -18,7 +18,6 @@ # the package manager for Go: https://github.com/Masterminds/glide.sh/blob/master/get PROJECT_NAME="helm" -TILLER_NAME="tiller" : ${USE_SUDO:="true"} : ${HELM_INSTALL_DIR:="/usr/local/bin"} @@ -94,7 +93,7 @@ checkDesiredVersion() { # if it needs to be changed. checkHelmInstalledVersion() { if [[ -f "${HELM_INSTALL_DIR}/${PROJECT_NAME}" ]]; then - local version=$("${HELM_INSTALL_DIR}/${PROJECT_NAME}" version -c | grep '^Client' | cut -d'"' -f2) + local version=$("${HELM_INSTALL_DIR}/${PROJECT_NAME}" version --template="{{ .Version }}") if [[ "$version" == "$TAG" ]]; then echo "Helm ${version} is already ${DESIRED_VERSION:-latest}" return 0 @@ -143,16 +142,9 @@ installFile() { mkdir -p "$HELM_TMP" tar xf "$HELM_TMP_FILE" -C "$HELM_TMP" HELM_TMP_BIN="$HELM_TMP/$OS-$ARCH/$PROJECT_NAME" - TILLER_TMP_BIN="$HELM_TMP/$OS-$ARCH/$TILLER_NAME" - echo "Preparing to install $PROJECT_NAME and $TILLER_NAME into ${HELM_INSTALL_DIR}" + echo "Preparing to install $PROJECT_NAME into ${HELM_INSTALL_DIR}" runAsRoot cp "$HELM_TMP_BIN" "$HELM_INSTALL_DIR" echo "$PROJECT_NAME installed into $HELM_INSTALL_DIR/$PROJECT_NAME" - if [ -x "$TILLER_TMP_BIN" ]; then - runAsRoot cp "$TILLER_TMP_BIN" "$HELM_INSTALL_DIR" - echo "$TILLER_NAME installed into $HELM_INSTALL_DIR/$TILLER_NAME" - else - echo "info: $TILLER_NAME binary was not found in this release; skipping $TILLER_NAME installation" - fi } # fail_trap is executed if an error occurs. @@ -180,15 +172,14 @@ testVersion() { exit 1 fi set -e - echo "Run '$PROJECT_NAME init' to configure $PROJECT_NAME." } # help provides possible cli installation arguments help () { echo "Accepted cli arguments are:" echo -e "\t[--help|-h ] ->> prints this help" - echo -e "\t[--version|-v ] . When not defined it defaults to latest" - echo -e "\te.g. --version v2.4.0 or -v latest" + echo -e "\t[--version|-v ] . When not defined it fetches the latest release from GitHub" + echo -e "\te.g. --version v3.0.0 or -v canary" echo -e "\t[--no-sudo] ->> install without sudo" } @@ -215,7 +206,7 @@ while [[ $# -gt 0 ]]; do if [[ $# -ne 0 ]]; then export DESIRED_VERSION="${1}" else - echo -e "Please provide the desired version. e.g. --version v2.4.0 or -v latest" + echo -e "Please provide the desired version. e.g. --version v3.0.0 or -v canary" exit 0 fi ;; From 8889625af63a93d08909af0c2cfdbddbcd7204db Mon Sep 17 00:00:00 2001 From: Daniel Strobusch <1847260+dastrobu@users.noreply.github.com> Date: Wed, 13 Nov 2019 18:29:48 +0100 Subject: [PATCH 26/65] fix: change error message to contain correct field name When reporting an incompatible Kubernetes version, due to a version constraint from the kubeVersion field, the error message should report with the correct field name. Signed-off-by: Daniel Strobusch <1847260+dastrobu@users.noreply.github.com> --- pkg/action/install.go | 2 +- pkg/action/install_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/action/install.go b/pkg/action/install.go index 4019dbc54..11862c57a 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -420,7 +420,7 @@ func (c *Configuration) renderResources(ch *chart.Chart, values chartutil.Values if ch.Metadata.KubeVersion != "" { if !chartutil.IsCompatibleRange(ch.Metadata.KubeVersion, caps.KubeVersion.String()) { - return hs, b, "", errors.Errorf("chart requires kubernetesVersion: %s which is incompatible with Kubernetes %s", ch.Metadata.KubeVersion, caps.KubeVersion.String()) + return hs, b, "", errors.Errorf("chart requires kubeVersion: %s which is incompatible with Kubernetes %s", ch.Metadata.KubeVersion, caps.KubeVersion.String()) } } diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go index bb36b843d..4637a4b10 100644 --- a/pkg/action/install_test.go +++ b/pkg/action/install_test.go @@ -306,7 +306,7 @@ func TestInstallRelease_KubeVersion(t *testing.T) { vals = map[string]interface{}{} _, err = instAction.Run(buildChart(withKube(">=99.0.0")), vals) is.Error(err) - is.Contains(err.Error(), "chart requires kubernetesVersion") + is.Contains(err.Error(), "chart requires kubeVersion") } func TestInstallRelease_Wait(t *testing.T) { From 44f72c4c0a55c8af25a88b363c3567408869aaa0 Mon Sep 17 00:00:00 2001 From: Jonathan Meyers Date: Mon, 18 Nov 2019 13:29:21 +0700 Subject: [PATCH 27/65] homebrew renamed formula to just helm from kubernetes-helm Signed-off-by: Jonathan Meyers --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9af358e10..06a53cf4d 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Unpack the `helm` binary and add it to your PATH and you are good to go! If you want to use a package manager: -- [Homebrew](https://brew.sh/) users can use `brew install kubernetes-helm`. +- [Homebrew](https://brew.sh/) users can use `brew install 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`. From 27c1ea63c70368d92ca101eac2efc569e3717520 Mon Sep 17 00:00:00 2001 From: Jonathan Meyers Date: Mon, 18 Nov 2019 13:34:41 +0700 Subject: [PATCH 28/65] Signed-off-by: Jonathan Meyers --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 06a53cf4d..ff8842962 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Unpack the `helm` binary and add it to your PATH and you are good to go! If you want to use a package manager: -- [Homebrew](https://brew.sh/) users can use `brew install helm`. +- [Homebrew](https://brew.sh/) users can use `brew installhelm`. - [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`. From f65ce9167e08e9677940dce4bc5529db4dcf1665 Mon Sep 17 00:00:00 2001 From: Jonathan Meyers Date: Mon, 18 Nov 2019 13:35:01 +0700 Subject: [PATCH 29/65] Signed-off-by: Jonathan Meyers --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ff8842962..06a53cf4d 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Unpack the `helm` binary and add it to your PATH and you are good to go! If you want to use a package manager: -- [Homebrew](https://brew.sh/) users can use `brew installhelm`. +- [Homebrew](https://brew.sh/) users can use `brew install 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`. From 8a8463e08d8a52b59fd20739ec3aa98be5bf1177 Mon Sep 17 00:00:00 2001 From: Scott Morgan Date: Tue, 19 Nov 2019 17:18:45 -0600 Subject: [PATCH 30/65] fix(lint): Remove requirement that directory name and chart name match Signed-off-by: Scott Morgan --- pkg/lint/rules/chartfile.go | 8 -------- pkg/lint/rules/chartfile_test.go | 18 ------------------ 2 files changed, 26 deletions(-) diff --git a/pkg/lint/rules/chartfile.go b/pkg/lint/rules/chartfile.go index 35bb81571..70cb83bc5 100644 --- a/pkg/lint/rules/chartfile.go +++ b/pkg/lint/rules/chartfile.go @@ -46,7 +46,6 @@ func Chartfile(linter *support.Linter) { } linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartName(chartFile)) - linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartNameDirMatch(linter.ChartDir, chartFile)) // Chart metadata linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartAPIVersion(chartFile)) @@ -82,13 +81,6 @@ func validateChartName(cf *chart.Metadata) error { return nil } -func validateChartNameDirMatch(chartDir string, cf *chart.Metadata) error { - if cf.Name != filepath.Base(chartDir) { - return errors.Errorf("directory name (%s) and chart name (%s) must be the same", filepath.Base(chartDir), cf.Name) - } - return nil -} - func validateChartAPIVersion(cf *chart.Metadata) error { if cf.APIVersion == "" { return errors.New("apiVersion is required. The value must be either \"v1\" or \"v2\"") diff --git a/pkg/lint/rules/chartfile_test.go b/pkg/lint/rules/chartfile_test.go index ff2a63583..f99299737 100644 --- a/pkg/lint/rules/chartfile_test.go +++ b/pkg/lint/rules/chartfile_test.go @@ -73,24 +73,6 @@ func TestValidateChartName(t *testing.T) { } } -func TestValidateChartNameDirMatch(t *testing.T) { - err := validateChartNameDirMatch(goodChartDir, goodChart) - if err != nil { - t.Errorf("validateChartNameDirMatch to return no error, gor a linter error") - } - // It has not name - err = validateChartNameDirMatch(badChartDir, badChart) - if err == nil { - t.Errorf("validatechartnamedirmatch to return a linter error, got no error") - } - - // Wrong path - err = validateChartNameDirMatch(badChartDir, goodChart) - if err == nil { - t.Errorf("validatechartnamedirmatch to return a linter error, got no error") - } -} - func TestValidateChartVersion(t *testing.T) { var failTest = []struct { Version string From eb833ccead99ecec15f3c192ad41bb041e284953 Mon Sep 17 00:00:00 2001 From: Scott Morgan Date: Wed, 20 Nov 2019 07:35:11 -0600 Subject: [PATCH 31/65] remove unused variable Signed-off-by: Scott Morgan --- pkg/lint/rules/chartfile_test.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pkg/lint/rules/chartfile_test.go b/pkg/lint/rules/chartfile_test.go index f99299737..fe306f653 100644 --- a/pkg/lint/rules/chartfile_test.go +++ b/pkg/lint/rules/chartfile_test.go @@ -30,18 +30,15 @@ import ( ) const ( - badChartDir = "testdata/badchartfile" - goodChartDir = "testdata/goodone" + badChartDir = "testdata/badchartfile" ) var ( badChartFilePath = filepath.Join(badChartDir, "Chart.yaml") - goodChartFilePath = filepath.Join(goodChartDir, "Chart.yaml") nonExistingChartFilePath = filepath.Join(os.TempDir(), "Chart.yaml") ) var badChart, _ = chartutil.LoadChartfile(badChartFilePath) -var goodChart, _ = chartutil.LoadChartfile(goodChartFilePath) // Validation functions Test func TestValidateChartYamlNotDirectory(t *testing.T) { From 32ce016054648f20168a2d7f4ff4b954686e0689 Mon Sep 17 00:00:00 2001 From: Scott Morgan Date: Wed, 20 Nov 2019 08:26:12 -0600 Subject: [PATCH 32/65] fix(lint): Remove requirement that directory name and chart name match Signed-off-by: Scott Morgan --- pkg/lint/lint_test.go | 15 ++++++--------- pkg/lint/rules/chartfile_test.go | 18 +++++++----------- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/pkg/lint/lint_test.go b/pkg/lint/lint_test.go index b770704c6..2a982d088 100644 --- a/pkg/lint/lint_test.go +++ b/pkg/lint/lint_test.go @@ -35,12 +35,12 @@ const goodChartDir = "rules/testdata/goodone" func TestBadChart(t *testing.T) { m := All(badChartDir, values, namespace, strict).Messages - if len(m) != 8 { + if len(m) != 7 { t.Errorf("Number of errors %v", len(m)) t.Errorf("All didn't fail with expected errors, got %#v", m) } // There should be one INFO, 2 WARNINGs and one ERROR messages, check for them - var i, w, e, e2, e3, e4, e5, e6 bool + var i, w, e, e2, e3, e4, e5 bool for _, msg := range m { if msg.Severity == support.InfoSev { if strings.Contains(msg.Err.Error(), "icon is recommended") { @@ -59,24 +59,21 @@ func TestBadChart(t *testing.T) { if strings.Contains(msg.Err.Error(), "name is required") { e2 = true } - if strings.Contains(msg.Err.Error(), "directory name (badchartfile) and chart name () must be the same") { - e3 = true - } if strings.Contains(msg.Err.Error(), "apiVersion is required. The value must be either \"v1\" or \"v2\"") { - e4 = true + e3 = true } if strings.Contains(msg.Err.Error(), "chart type is not valid in apiVersion") { - e5 = true + e4 = true } if strings.Contains(msg.Err.Error(), "dependencies are not valid in the Chart file with apiVersion") { - e6 = true + e5 = true } } } - if !e || !e2 || !e3 || !e4 || !e5 || !e6 || !w || !i { + if !e || !e2 || !e3 || !e4 || !e5 || !w || !i { t.Errorf("Didn't find all the expected errors, got %#v", m) } } diff --git a/pkg/lint/rules/chartfile_test.go b/pkg/lint/rules/chartfile_test.go index fe306f653..d032dd12f 100644 --- a/pkg/lint/rules/chartfile_test.go +++ b/pkg/lint/rules/chartfile_test.go @@ -188,36 +188,32 @@ func TestChartfile(t *testing.T) { Chartfile(&linter) msgs := linter.Messages - if len(msgs) != 7 { - t.Errorf("Expected 7 errors, got %d", len(msgs)) + if len(msgs) != 6 { + t.Errorf("Expected 6 errors, got %d", len(msgs)) } if !strings.Contains(msgs[0].Err.Error(), "name is required") { t.Errorf("Unexpected message 0: %s", msgs[0].Err) } - if !strings.Contains(msgs[1].Err.Error(), "directory name (badchartfile) and chart name () must be the same") { + if !strings.Contains(msgs[1].Err.Error(), "apiVersion is required. The value must be either \"v1\" or \"v2\"") { t.Errorf("Unexpected message 1: %s", msgs[1].Err) } - if !strings.Contains(msgs[2].Err.Error(), "apiVersion is required. The value must be either \"v1\" or \"v2\"") { + if !strings.Contains(msgs[2].Err.Error(), "version '0.0.0.0' is not a valid SemVer") { t.Errorf("Unexpected message 2: %s", msgs[2].Err) } - if !strings.Contains(msgs[3].Err.Error(), "version '0.0.0.0' is not a valid SemVer") { + if !strings.Contains(msgs[3].Err.Error(), "icon is recommended") { t.Errorf("Unexpected message 3: %s", msgs[3].Err) } - if !strings.Contains(msgs[4].Err.Error(), "icon is recommended") { + if !strings.Contains(msgs[4].Err.Error(), "chart type is not valid in apiVersion") { t.Errorf("Unexpected message 4: %s", msgs[4].Err) } - if !strings.Contains(msgs[5].Err.Error(), "chart type is not valid in apiVersion") { + if !strings.Contains(msgs[5].Err.Error(), "dependencies are not valid in the Chart file with apiVersion") { t.Errorf("Unexpected message 5: %s", msgs[5].Err) } - if !strings.Contains(msgs[6].Err.Error(), "dependencies are not valid in the Chart file with apiVersion") { - t.Errorf("Unexpected message 6: %s", msgs[6].Err) - } - } From 6473234f43cbec7603124d684cb630dfdc4b1419 Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Sun, 24 Nov 2019 22:25:10 -0500 Subject: [PATCH 33/65] fix(plugin): Add missing -n known flag Signed-off-by: Marc Khouzam --- cmd/helm/load_plugins.go | 2 +- cmd/helm/plugin_test.go | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/cmd/helm/load_plugins.go b/cmd/helm/load_plugins.go index 53e082e96..d68cf46ee 100644 --- a/cmd/helm/load_plugins.go +++ b/cmd/helm/load_plugins.go @@ -127,7 +127,7 @@ func loadPlugins(baseCmd *cobra.Command, out io.Writer) { func manuallyProcessArgs(args []string) ([]string, []string) { known := []string{} unknown := []string{} - kvargs := []string{"--kube-context", "--namespace", "--kubeconfig", "--registry-config", "--repository-cache", "--repository-config"} + kvargs := []string{"--kube-context", "--namespace", "-n", "--kubeconfig", "--registry-config", "--repository-cache", "--repository-config"} knownArg := func(a string) bool { for _, pre := range kvargs { if strings.HasPrefix(a, pre+"=") { diff --git a/cmd/helm/plugin_test.go b/cmd/helm/plugin_test.go index 7bc8fe70c..3fd3a4197 100644 --- a/cmd/helm/plugin_test.go +++ b/cmd/helm/plugin_test.go @@ -30,14 +30,27 @@ func TestManuallyProcessArgs(t *testing.T) { "--debug", "--foo", "bar", "--kubeconfig=/home/foo", + "--kubeconfig", "/home/foo", + "--kube-context=test1", "--kube-context", "test1", + "-n=test2", "-n", "test2", + "--namespace=test2", + "--namespace", "test2", "--home=/tmp", "command", } expectKnown := []string{ - "--debug", "--kubeconfig=/home/foo", "--kube-context", "test1", "-n", "test2", + "--debug", + "--kubeconfig=/home/foo", + "--kubeconfig", "/home/foo", + "--kube-context=test1", + "--kube-context", "test1", + "-n=test2", + "-n", "test2", + "--namespace=test2", + "--namespace", "test2", } expectUnknown := []string{ From 5179f8d698d30b243fd9aa646fac76224510b28b Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Sun, 24 Nov 2019 22:50:22 -0500 Subject: [PATCH 34/65] fix(plugin): Avoid duplication of flag list Signed-off-by: Marc Khouzam --- cmd/helm/load_plugins.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/cmd/helm/load_plugins.go b/cmd/helm/load_plugins.go index d68cf46ee..ed99a5164 100644 --- a/cmd/helm/load_plugins.go +++ b/cmd/helm/load_plugins.go @@ -136,11 +136,21 @@ func manuallyProcessArgs(args []string) ([]string, []string) { } return false } + + isKnown := func(v string) string { + for _, i := range kvargs { + if i == v { + return v + } + } + return "" + } + for i := 0; i < len(args); i++ { switch a := args[i]; a { case "--debug": known = append(known, a) - case "--kube-context", "--namespace", "-n", "--kubeconfig", "--registry-config", "--repository-cache", "--repository-config": + case isKnown(a): known = append(known, a, args[i+1]) i++ default: From e3f49085ccb7b8f35e988554392d5f7ec5e066ad Mon Sep 17 00:00:00 2001 From: Andreas Stenius Date: Mon, 25 Nov 2019 12:38:57 +0100 Subject: [PATCH 35/65] chart_downloader: add test to verify that http opts are used correctly. (#7055) Signed-off-by: Andreas Stenius --- pkg/downloader/chart_downloader_test.go | 61 +++++++++++++++++++ pkg/downloader/testdata/repositories.yaml | 7 ++- .../repository/testing-ca-file-index.yaml | 14 +++++ 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 pkg/downloader/testdata/repository/testing-ca-file-index.yaml diff --git a/pkg/downloader/chart_downloader_test.go b/pkg/downloader/chart_downloader_test.go index 80249e240..abecf81eb 100644 --- a/pkg/downloader/chart_downloader_test.go +++ b/pkg/downloader/chart_downloader_test.go @@ -80,6 +80,67 @@ func TestResolveChartRef(t *testing.T) { } } +func TestResolveChartOpts(t *testing.T) { + tests := []struct { + name, ref, version string + expect []getter.Option + }{ + { + name: "repo with CA-file", + ref: "testing-ca-file/foo", + expect: []getter.Option{ + getter.WithURL("https://example.com/foo-1.2.3.tgz"), + getter.WithTLSClientConfig("cert", "key", "ca"), + }, + }, + } + + c := ChartDownloader{ + Out: os.Stderr, + RepositoryConfig: repoConfig, + RepositoryCache: repoCache, + Getters: getter.All(&cli.EnvSettings{ + RepositoryConfig: repoConfig, + RepositoryCache: repoCache, + }), + } + + // snapshot options + snapshot_opts := c.Options + + for _, tt := range tests { + // reset chart downloader options for each test case + c.Options = snapshot_opts + + expect, err := getter.NewHTTPGetter(tt.expect...) + if err != nil { + t.Errorf("%s: failed to setup http client: %s", tt.name, err) + continue + } + + u, err := c.ResolveChartVersion(tt.ref, tt.version) + if err != nil { + t.Errorf("%s: failed with error %s", tt.name, err) + continue + } + + got, err := getter.NewHTTPGetter( + append( + c.Options, + getter.WithURL(u.String()), + )... + ) + if err != nil { + t.Errorf("%s: failed to create http client: %s", tt.name, err) + continue + } + + if got != expect { + t.Errorf("%s: expected %s, got %s", tt.name, expect, got) + } + } +} + func TestVerifyChart(t *testing.T) { v, err := VerifyChart("testdata/signtest-0.1.0.tgz", "testdata/helm-test-key.pub") if err != nil { diff --git a/pkg/downloader/testdata/repositories.yaml b/pkg/downloader/testdata/repositories.yaml index 374d95c8a..430865269 100644 --- a/pkg/downloader/testdata/repositories.yaml +++ b/pkg/downloader/testdata/repositories.yaml @@ -15,4 +15,9 @@ repositories: - name: testing-relative url: "http://example.com/helm" - name: testing-relative-trailing-slash - url: "http://example.com/helm/" \ No newline at end of file + url: "http://example.com/helm/" + - name: testing-ca-file + url: "https://example.com" + certFile: "cert" + keyFile: "key" + caFile: "ca" diff --git a/pkg/downloader/testdata/repository/testing-ca-file-index.yaml b/pkg/downloader/testdata/repository/testing-ca-file-index.yaml new file mode 100644 index 000000000..17cdde1c6 --- /dev/null +++ b/pkg/downloader/testdata/repository/testing-ca-file-index.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +entries: + foo: + - name: foo + description: Foo Chart + home: https://helm.sh/helm + keywords: [] + maintainers: [] + sources: + - https://github.com/helm/charts + urls: + - https://example.com/foo-1.2.3.tgz + version: 1.2.3 + checksum: 0e6661f193211d7a5206918d42f5c2a9470b737d From d6c13616fa7beff70931255cce62ab336ce1531d Mon Sep 17 00:00:00 2001 From: Andreas Stenius Date: Mon, 25 Nov 2019 13:10:15 +0100 Subject: [PATCH 36/65] chart_downloader: add TLS client config to options from repo config. (#7055) Signed-off-by: Andreas Stenius --- pkg/downloader/chart_downloader.go | 2 ++ pkg/downloader/chart_downloader_test.go | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/downloader/chart_downloader.go b/pkg/downloader/chart_downloader.go index 8e251bc89..9b9293455 100644 --- a/pkg/downloader/chart_downloader.go +++ b/pkg/downloader/chart_downloader.go @@ -214,6 +214,8 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, er c.Options = append(c.Options, getter.WithBasicAuth(r.Config.Username, r.Config.Password)) } + c.Options = append(c.Options, getter.WithTLSClientConfig(r.Config.CertFile, r.Config.KeyFile, r.Config.CAFile)) + // Next, we need to load the index, and actually look up the chart. idxFile := filepath.Join(c.RepositoryCache, helmpath.CacheIndexFile(r.Config.Name)) i, err := repo.LoadIndexFile(idxFile) diff --git a/pkg/downloader/chart_downloader_test.go b/pkg/downloader/chart_downloader_test.go index abecf81eb..71a56d482 100644 --- a/pkg/downloader/chart_downloader_test.go +++ b/pkg/downloader/chart_downloader_test.go @@ -135,7 +135,7 @@ func TestResolveChartOpts(t *testing.T) { continue } - if got != expect { + if *(got.(*getter.HTTPGetter)) != *(expect.(*getter.HTTPGetter)) { t.Errorf("%s: expected %s, got %s", tt.name, expect, got) } } From d3ad6f9c78113fd4c577b31e41277796220e4c0f Mon Sep 17 00:00:00 2001 From: Andreas Stenius Date: Mon, 25 Nov 2019 13:23:08 +0100 Subject: [PATCH 37/65] cli/pull: pass TLS config to chart downloader from flags. (#7055) Signed-off-by: Andreas Stenius --- pkg/action/pull.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/action/pull.go b/pkg/action/pull.go index aaf63861e..b0a3d2598 100644 --- a/pkg/action/pull.go +++ b/pkg/action/pull.go @@ -63,6 +63,7 @@ func (p *Pull) Run(chartRef string) (string, error) { Getters: getter.All(p.Settings), Options: []getter.Option{ getter.WithBasicAuth(p.Username, p.Password), + getter.WithTLSClientConfig(p.CertFile, p.KeyFile, p.CaFile), }, RepositoryConfig: p.Settings.RepositoryConfig, RepositoryCache: p.Settings.RepositoryCache, From 0f0aa6b43261b3f4b95fd7ee14107de2630dd446 Mon Sep 17 00:00:00 2001 From: Andreas Stenius Date: Mon, 25 Nov 2019 13:37:20 +0100 Subject: [PATCH 38/65] chart_downloader: avoid overriding TLS options from command flags when not setup in repo config. Signed-off-by: Andreas Stenius --- pkg/downloader/chart_downloader.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/downloader/chart_downloader.go b/pkg/downloader/chart_downloader.go index 9b9293455..f3d4321c5 100644 --- a/pkg/downloader/chart_downloader.go +++ b/pkg/downloader/chart_downloader.go @@ -214,7 +214,9 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, er c.Options = append(c.Options, getter.WithBasicAuth(r.Config.Username, r.Config.Password)) } - c.Options = append(c.Options, getter.WithTLSClientConfig(r.Config.CertFile, r.Config.KeyFile, r.Config.CAFile)) + if r.Config.CertFile != "" || r.Config.KeyFile != "" || r.Config.CAFile != "" { + c.Options = append(c.Options, getter.WithTLSClientConfig(r.Config.CertFile, r.Config.KeyFile, r.Config.CAFile)) + } // Next, we need to load the index, and actually look up the chart. idxFile := filepath.Join(c.RepositoryCache, helmpath.CacheIndexFile(r.Config.Name)) From 4c4328398ecc4f6eef07524f4bcddaca153b4570 Mon Sep 17 00:00:00 2001 From: Andreas Stenius Date: Mon, 25 Nov 2019 14:17:24 +0100 Subject: [PATCH 39/65] chart_downloader: fix lint issue. Signed-off-by: Andreas Stenius --- pkg/downloader/chart_downloader_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/downloader/chart_downloader_test.go b/pkg/downloader/chart_downloader_test.go index 71a56d482..e0692c8c8 100644 --- a/pkg/downloader/chart_downloader_test.go +++ b/pkg/downloader/chart_downloader_test.go @@ -87,7 +87,7 @@ func TestResolveChartOpts(t *testing.T) { }{ { name: "repo with CA-file", - ref: "testing-ca-file/foo", + ref: "testing-ca-file/foo", expect: []getter.Option{ getter.WithURL("https://example.com/foo-1.2.3.tgz"), getter.WithTLSClientConfig("cert", "key", "ca"), @@ -106,11 +106,11 @@ func TestResolveChartOpts(t *testing.T) { } // snapshot options - snapshot_opts := c.Options + snapshotOpts := c.Options for _, tt := range tests { // reset chart downloader options for each test case - c.Options = snapshot_opts + c.Options = snapshotOpts expect, err := getter.NewHTTPGetter(tt.expect...) if err != nil { @@ -128,7 +128,7 @@ func TestResolveChartOpts(t *testing.T) { append( c.Options, getter.WithURL(u.String()), - )... + )..., ) if err != nil { t.Errorf("%s: failed to create http client: %s", tt.name, err) From 32b4e2e5e998ee11559d132eae796f2b22fac0f7 Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Sun, 24 Nov 2019 23:08:13 -0500 Subject: [PATCH 40/65] fix(plugin): Avoid crash on missing flag When calling a plugin, if a global flag requiring a parameter was missing the parameter, helm would crash. For example: helm 2to3 --namespace Signed-off-by: Marc Khouzam --- cmd/helm/load_plugins.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cmd/helm/load_plugins.go b/cmd/helm/load_plugins.go index ed99a5164..f2fb5c01d 100644 --- a/cmd/helm/load_plugins.go +++ b/cmd/helm/load_plugins.go @@ -151,8 +151,11 @@ func manuallyProcessArgs(args []string) ([]string, []string) { case "--debug": known = append(known, a) case isKnown(a): - known = append(known, a, args[i+1]) + known = append(known, a) i++ + if i < len(args) { + known = append(known, args[i]) + } default: if knownArg(a) { known = append(known, a) From 48704034a9f37a23eee192b32e15249b299e0767 Mon Sep 17 00:00:00 2001 From: chloel Date: Tue, 26 Nov 2019 16:48:15 -0500 Subject: [PATCH 41/65] fix: ignore pax header files in chart validation Signed-off-by: chloel --- pkg/chart/loader/archive.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkg/chart/loader/archive.go b/pkg/chart/loader/archive.go index 3c50fe379..7e187a170 100644 --- a/pkg/chart/loader/archive.go +++ b/pkg/chart/loader/archive.go @@ -126,6 +126,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 af59e32654f048d62b053afb0860a3bec77444fb Mon Sep 17 00:00:00 2001 From: Remco Haszing Date: Thu, 28 Nov 2019 13:01:20 +0100 Subject: [PATCH 42/65] docs(install): clarify the --replace flag (#7089) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs(install): clarify the --replace flag The description of the `--replace` flag was unclear, as it can’t be used to replace active releases. Signed-off-by: Remco Haszing * docs(install): reword replace flag description Signed-off-by: Remco Haszing --- cmd/helm/install.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/helm/install.go b/cmd/helm/install.go index 40935db17..0c14c013b 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -130,7 +130,7 @@ func newInstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { func addInstallFlags(f *pflag.FlagSet, client *action.Install, valueOpts *values.Options) { f.BoolVar(&client.DryRun, "dry-run", false, "simulate an install") f.BoolVar(&client.DisableHooks, "no-hooks", false, "prevent hooks from running during install") - f.BoolVar(&client.Replace, "replace", false, "re-use the given name, even if that name is already used. This is unsafe in production") + f.BoolVar(&client.Replace, "replace", false, "re-use the given name, only if that name is a deleted release which remains in the history. This is unsafe in production") f.DurationVar(&client.Timeout, "timeout", 300*time.Second, "time to wait for any individual Kubernetes operation (like Jobs for hooks)") f.BoolVar(&client.Wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment, StatefulSet, or ReplicaSet are in a ready state before marking the release as successful. It will wait for as long as --timeout") f.BoolVarP(&client.GenerateName, "generate-name", "g", false, "generate the name (and omit the NAME parameter)") From b8605c8d36960a552cdf74104f02762ef07e2713 Mon Sep 17 00:00:00 2001 From: Geoff Baskwill Date: Wed, 27 Nov 2019 19:46:34 -0500 Subject: [PATCH 43/65] test(pkg): add unit tests for tar file edge cases Adding unit tests for an issue that has come up multiple times where the archive processing code doesn't take into account the `tar.TypeXHeader` / `tar.TypeXGlobalHeader` entries that GitHub adds when creating a release archive for a chart, for example `https://github.com/org/repo/master.tar.gz`. Signed-off-by: Geoff Baskwill --- pkg/chart/loader/archive_test.go | 110 +++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 pkg/chart/loader/archive_test.go diff --git a/pkg/chart/loader/archive_test.go b/pkg/chart/loader/archive_test.go new file mode 100644 index 000000000..7d8c8b51e --- /dev/null +++ b/pkg/chart/loader/archive_test.go @@ -0,0 +1,110 @@ +/* +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 loader + +import ( + "archive/tar" + "bytes" + "compress/gzip" + "testing" +) + +func TestLoadArchiveFiles(t *testing.T) { + tcs := []struct { + name string + generate func(w *tar.Writer) + check func(t *testing.T, files []*BufferedFile, err error) + }{ + { + name: "empty input should return no files", + generate: func(w *tar.Writer) {}, + check: func(t *testing.T, files []*BufferedFile, err error) { + if err.Error() != "no files in chart archive" { + t.Fatalf(`expected "no files in chart archive", got [%#v]`, err) + } + }, + }, + { + name: "should ignore files with XGlobalHeader type", + generate: func(w *tar.Writer) { + // simulate the presence of a `pax_global_header` file like you would get when + // processing a GitHub release archive. + _ = w.WriteHeader(&tar.Header{ + Typeflag: tar.TypeXGlobalHeader, + Name: "pax_global_header", + }) + + // we need to have at least one file, otherwise we'll get the "no files in chart archive" error + _ = w.WriteHeader(&tar.Header{ + Typeflag: tar.TypeReg, + Name: "dir/empty", + }) + }, + check: func(t *testing.T, files []*BufferedFile, err error) { + if err != nil { + t.Fatalf(`got unwanted error [%#v] for tar file with pax_global_header content`, err) + } + + if len(files) != 1 { + t.Fatalf(`expected to get one file but got [%v]`, files) + } + }, + }, + { + name: "should ignore files with TypeXHeader type", + generate: func(w *tar.Writer) { + // simulate the presence of a `pax_header` file like you might get when + // processing a GitHub release archive. + _ = w.WriteHeader(&tar.Header{ + Typeflag: tar.TypeXHeader, + Name: "pax_header", + }) + + // we need to have at least one file, otherwise we'll get the "no files in chart archive" error + _ = w.WriteHeader(&tar.Header{ + Typeflag: tar.TypeReg, + Name: "dir/empty", + }) + }, + check: func(t *testing.T, files []*BufferedFile, err error) { + if err != nil { + t.Fatalf(`got unwanted error [%#v] for tar file with pax_header content`, err) + } + + if len(files) != 1 { + t.Fatalf(`expected to get one file but got [%v]`, files) + } + }, + }, + } + + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + buf := &bytes.Buffer{} + gzw := gzip.NewWriter(buf) + tw := tar.NewWriter(gzw) + + tc.generate(tw) + + _ = tw.Close() + _ = gzw.Close() + + files, err := LoadArchiveFiles(buf) + tc.check(t, files, err) + }) + } +} From 750b870aedd35b69b9ca1e1517635fa70367a309 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=B7=E7=9A=84=E6=BE=9C=E8=89=B2?= <33822635+zwwhdls@users.noreply.github.com> Date: Mon, 2 Dec 2019 22:57:51 +0800 Subject: [PATCH 44/65] fix stack overflow error (#7114) * fixed #7111 Signed-off-by: zwwhdls * update error message Signed-off-by: zwwhdls * add test case Signed-off-by: zwwhdls * fix lint error Signed-off-by: zwwhdls --- pkg/engine/engine.go | 8 ++++++++ pkg/engine/engine_test.go | 15 +++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index dae0b6be7..5a7d54993 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -93,11 +93,19 @@ func warnWrap(warn string) string { // initFunMap creates the Engine's FuncMap and adds context-specific functions. func (e Engine) initFunMap(t *template.Template, referenceTpls map[string]renderable) { funcMap := funcMap() + includedNames := make([]string, 0) // Add the 'include' function here so we can close over t. funcMap["include"] = func(name string, data interface{}) (string, error) { var buf strings.Builder + for _, n := range includedNames { + if n == name { + return "", errors.Wrapf(fmt.Errorf("unable to excute template"), "rendering template has a nested reference name: %s", name) + } + } + includedNames = append(includedNames, name) err := t.ExecuteTemplate(&buf, name, data) + includedNames = includedNames[:len(includedNames)-1] return buf.String(), err } diff --git a/pkg/engine/engine_test.go b/pkg/engine/engine_test.go index 031527dd0..f3609fcbd 100644 --- a/pkg/engine/engine_test.go +++ b/pkg/engine/engine_test.go @@ -460,6 +460,15 @@ func TestAlterFuncMap_include(t *testing.T) { }, } + // Check nested reference in include FuncMap + d := &chart.Chart{ + Metadata: &chart.Metadata{Name: "nested"}, + Templates: []*chart.File{ + {Name: "templates/quote", Data: []byte(`{{include "nested/templates/quote" . | indent 2}} dead.`)}, + {Name: "templates/_partial", Data: []byte(`{{.Release.Name}} - he`)}, + }, + } + v := chartutil.Values{ "Values": "", "Chart": c.Metadata, @@ -477,6 +486,12 @@ func TestAlterFuncMap_include(t *testing.T) { if got := out["conrad/templates/quote"]; got != expect { t.Errorf("Expected %q, got %q (%v)", expect, got, out) } + + _, err = Render(d, v) + expectErrName := "nested/templates/quote" + if err == nil { + t.Errorf("Expected err of nested reference name: %v", expectErrName) + } } func TestAlterFuncMap_require(t *testing.T) { From bf4cc97bbe7ca994894a87df63fdf7da6ee0841a Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Tue, 3 Dec 2019 08:48:44 -0500 Subject: [PATCH 45/65] fix(cli): IsReachable check for "get values" The 'helm get values' has its own Run() method in the action package. So, unlike the other 'get' variants, it needs to check for the reachability of the cluster itself. Signed-off-by: Marc Khouzam --- pkg/action/get_values.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/action/get_values.go b/pkg/action/get_values.go index 5bc3a7005..9c32db213 100644 --- a/pkg/action/get_values.go +++ b/pkg/action/get_values.go @@ -39,6 +39,10 @@ func NewGetValues(cfg *Configuration) *GetValues { // Run executes 'helm get values' against the given release. func (g *GetValues) Run(name string) (map[string]interface{}, error) { + if err := g.cfg.KubeClient.IsReachable(); err != nil { + return nil, err + } + rel, err := g.cfg.releaseContent(name, g.Version) if err != nil { return nil, err From cc33e394c7c464be1940a2f737a1f24887e4ca6f Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Thu, 28 Nov 2019 16:26:55 -0500 Subject: [PATCH 46/65] fix(tests): mapfile is not available on MacOS The mapfile command is not available on a standard MacOS install. To faciliate doing `make test` which runs validate-license.sh, let's use an array instead of mapfile. Signed-off-by: Marc Khouzam --- scripts/validate-license.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/validate-license.sh b/scripts/validate-license.sh index 00bd38ea2..dc247436f 100755 --- a/scripts/validate-license.sh +++ b/scripts/validate-license.sh @@ -27,14 +27,16 @@ find_files() { \( -name '*.go' -o -name '*.sh' \) } -mapfile -t failed_license_header < <(find_files | xargs grep -L 'Licensed under the Apache License, Version 2.0 (the "License")') +# Use "|| :" to ignore the error code when grep returns empty +failed_license_header=($(find_files | xargs grep -L 'Licensed under the Apache License, Version 2.0 (the "License")' || :)) if (( ${#failed_license_header[@]} > 0 )); then echo "Some source files are missing license headers." printf '%s\n' "${failed_license_header[@]}" exit 1 fi -mapfile -t failed_copyright_header < <(find_files | xargs grep -L 'Copyright The Helm Authors.') +# Use "|| :" to ignore the error code when grep returns empty +failed_copyright_header=($(find_files | xargs grep -L 'Copyright The Helm Authors.' || :)) if (( ${#failed_copyright_header[@]} > 0 )); then echo "Some source files are missing the copyright header." printf '%s\n' "${failed_copyright_header[@]}" From 01aa1bd3a299f6a456c5472394fd5138a20b87ce Mon Sep 17 00:00:00 2001 From: Graham Goudeau Date: Tue, 3 Dec 2019 14:06:55 -0500 Subject: [PATCH 47/65] Add a flag to allow template to output CRDs Signed-off-by: Graham Goudeau --- cmd/helm/template.go | 9 +++ cmd/helm/template_test.go | 5 ++ .../testdata/output/template-with-crds.txt | 72 +++++++++++++++++++ .../subpop/charts/subchart1/crds/crdA.yaml | 13 ++++ 4 files changed, 99 insertions(+) create mode 100644 cmd/helm/testdata/output/template-with-crds.txt create mode 100644 pkg/chartutil/testdata/subpop/charts/subchart1/crds/crdA.yaml diff --git a/cmd/helm/template.go b/cmd/helm/template.go index 5312d798f..b660cc69f 100644 --- a/cmd/helm/template.go +++ b/cmd/helm/template.go @@ -44,6 +44,7 @@ faked locally. Additionally, none of the server-side testing of chart validity func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { var validate bool + var includeCrds bool client := action.NewInstall(cfg) valueOpts := &values.Options{} var extraAPIs []string @@ -67,7 +68,14 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { var manifests bytes.Buffer + if includeCrds { + for _, f := range rel.Chart.CRDs() { + fmt.Fprintf(&manifests, "---\n# Source: %s\n%s\n", f.Name, f.Data) + } + } + fmt.Fprintln(&manifests, strings.TrimSpace(rel.Manifest)) + if !client.DisableHooks { for _, m := range rel.Hooks { fmt.Fprintf(&manifests, "---\n# Source: %s\n%s\n", m.Path, m.Manifest) @@ -120,6 +128,7 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { f.StringArrayVarP(&showFiles, "show-only", "s", []string{}, "only show manifests rendered from the given templates") f.StringVar(&client.OutputDir, "output-dir", "", "writes the executed templates to files in output-dir instead of stdout") f.BoolVar(&validate, "validate", false, "validate your manifests against the Kubernetes cluster you are currently pointing at. This is the same validation performed on an install") + f.BoolVar(&includeCrds, "include-crds", false, "include CRDs in the templated output") f.StringArrayVarP(&extraAPIs, "api-versions", "a", []string{}, "Kubernetes api versions used for Capabilities.APIVersions") return cmd diff --git a/cmd/helm/template_test.go b/cmd/helm/template_test.go index 8aa2f6c06..735829432 100644 --- a/cmd/helm/template_test.go +++ b/cmd/helm/template_test.go @@ -79,6 +79,11 @@ func TestTemplateCmd(t *testing.T) { cmd: fmt.Sprintf("template --api-versions helm.k8s.io/test '%s'", chartPath), golden: "output/template-with-api-version.txt", }, + { + name: "template with CRDs", + cmd: fmt.Sprintf("template '%s' --include-crds", chartPath), + golden: "output/template-with-crds.txt", + }, } runTestCmd(t, tests) } diff --git a/cmd/helm/testdata/output/template-with-crds.txt b/cmd/helm/testdata/output/template-with-crds.txt new file mode 100644 index 000000000..9fa1c7e6d --- /dev/null +++ b/cmd/helm/testdata/output/template-with-crds.txt @@ -0,0 +1,72 @@ +--- +# Source: crds/crdA.yaml +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: testCRDs +spec: + group: testCRDGroups + names: + kind: TestCRD + listKind: TestCRDList + plural: TestCRDs + shortNames: + - tc + singular: authconfig + +--- +# Source: subchart1/charts/subcharta/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: subcharta + labels: + helm.sh/chart: "subcharta-0.1.0" +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 80 + protocol: TCP + name: apache + selector: + app.kubernetes.io/name: subcharta +--- +# Source: subchart1/charts/subchartb/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: subchartb + labels: + helm.sh/chart: "subchartb-0.1.0" +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 80 + protocol: TCP + name: nginx + selector: + app.kubernetes.io/name: subchartb +--- +# Source: subchart1/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: subchart1 + labels: + helm.sh/chart: "subchart1-0.1.0" + app.kubernetes.io/instance: "RELEASE-NAME" + kube-version/major: "1" + kube-version/minor: "16" + kube-version/version: "v1.16.0" + kube-api-version/test: v1 +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 80 + protocol: TCP + name: nginx + selector: + app.kubernetes.io/name: subchart1 diff --git a/pkg/chartutil/testdata/subpop/charts/subchart1/crds/crdA.yaml b/pkg/chartutil/testdata/subpop/charts/subchart1/crds/crdA.yaml new file mode 100644 index 000000000..fca77fd4b --- /dev/null +++ b/pkg/chartutil/testdata/subpop/charts/subchart1/crds/crdA.yaml @@ -0,0 +1,13 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: testCRDs +spec: + group: testCRDGroups + names: + kind: TestCRD + listKind: TestCRDList + plural: TestCRDs + shortNames: + - tc + singular: authconfig From e062146db3a9a9bec0e64f5db939416441b1af38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=B7=E7=9A=84=E6=BE=9C=E8=89=B2?= <33822635+zwwhdls@users.noreply.github.com> Date: Wed, 4 Dec 2019 22:25:50 +0800 Subject: [PATCH 48/65] fix "Chart.lock is out of sync with Chart.yaml" (#7119) * fixed #7101 Signed-off-by: zwwhdls * add test case Signed-off-by: zwwhdls * fix lint error Signed-off-by: zwwhdls * rename testcase Signed-off-by: zwwhdls --- pkg/downloader/manager.go | 7 ++++ pkg/downloader/manager_test.go | 68 ++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index 4e9d691d8..81dd53614 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -149,6 +149,13 @@ func (m *Manager) Update() error { return err } + // downloadAll might overwrite dependency version, recalculate lock digest + newDigest, err := resolver.HashReq(req, lock.Dependencies) + if err != nil { + return err + } + lock.Digest = newDigest + // If the lock file hasn't changed, don't write a new one. oldLock := c.Lock if oldLock != nil && oldLock.Digest == lock.Digest { diff --git a/pkg/downloader/manager_test.go b/pkg/downloader/manager_test.go index 6e32b3e85..dd83c3dc2 100644 --- a/pkg/downloader/manager_test.go +++ b/pkg/downloader/manager_test.go @@ -181,6 +181,74 @@ func TestGetRepoNames(t *testing.T) { } } +func TestUpdateBeforeBuild(t *testing.T) { + // Set up a fake repo + srv, err := repotest.NewTempServer("testdata/*.tgz*") + if err != nil { + t.Fatal(err) + } + defer srv.Stop() + if err := srv.LinkIndices(); err != nil { + t.Fatal(err) + } + dir := func(p ...string) string { + return filepath.Join(append([]string{srv.Root()}, p...)...) + } + + // Save dep + d := &chart.Chart{ + Metadata: &chart.Metadata{ + Name: "dep-chart", + Version: "0.1.0", + APIVersion: "v1", + }, + } + if err := chartutil.SaveDir(d, dir()); err != nil { + t.Fatal(err) + } + // Save a chart + c := &chart.Chart{ + Metadata: &chart.Metadata{ + Name: "with-dependency", + Version: "0.1.0", + APIVersion: "v1", + Dependencies: []*chart.Dependency{{ + Name: d.Metadata.Name, + Version: ">=0.1.0", + Repository: "file://../dep-chart", + }}, + }, + } + if err := chartutil.SaveDir(c, dir()); err != nil { + t.Fatal(err) + } + + // Set-up a manager + b := bytes.NewBuffer(nil) + g := getter.Providers{getter.Provider{ + Schemes: []string{"http", "https"}, + New: getter.NewHTTPGetter, + }} + m := &Manager{ + ChartPath: dir(c.Metadata.Name), + Out: b, + Getters: g, + RepositoryConfig: dir("repositories.yaml"), + RepositoryCache: dir(), + } + + // Update before Build. see issue: https://github.com/helm/helm/issues/7101 + err = m.Update() + if err != nil { + t.Fatal(err) + } + + err = m.Build() + if err != nil { + t.Fatal(err) + } +} + // This function is the skeleton test code of failing tests for #6416 and #6871 and bugs due to #5874. // // This function is used by below tests that ensures success of build operation From a61c930de399e64fdafe5337a9c16a8625843758 Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Wed, 4 Dec 2019 10:23:10 -0500 Subject: [PATCH 49/65] Fixing the code of conduct pointer When the v3 branch was started the code of conduct pointed to the Kubernetes one which pointed to the CNCF. Helm moved to be a CNCF project and the v2 code of conduct was pointed directly at the CNCF one. This was missed on the v3 branch. This updates the pointer. Signed-off-by: Matt Farina --- code-of-conduct.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code-of-conduct.md b/code-of-conduct.md index 0d15c00cf..91ccaf035 100644 --- a/code-of-conduct.md +++ b/code-of-conduct.md @@ -1,3 +1,3 @@ -# Kubernetes Community Code of Conduct +# Community Code of Conduct -Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md) +Helm follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). From 2a66e1a0e1f9b820309cd658aecf10896ac65ca5 Mon Sep 17 00:00:00 2001 From: Karuppiah Natarajan Date: Wed, 4 Dec 2019 22:43:42 +0530 Subject: [PATCH 50/65] use sigs.k8s.io/yaml instead of gopkg.in/yaml.v2 this is for consistency as everywhere we use sigs.k8s.io/yaml package Signed-off-by: Karuppiah Natarajan --- cmd/helm/repo_add.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/helm/repo_add.go b/cmd/helm/repo_add.go index 1c84ad8d6..e6afce3d5 100644 --- a/cmd/helm/repo_add.go +++ b/cmd/helm/repo_add.go @@ -29,7 +29,7 @@ import ( "github.com/gofrs/flock" "github.com/pkg/errors" "github.com/spf13/cobra" - "gopkg.in/yaml.v2" + "sigs.k8s.io/yaml" "helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v3/pkg/getter" From a1dcb3c2e453f778456ed600549a384605e1a692 Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Thu, 5 Dec 2019 15:48:02 -0500 Subject: [PATCH 51/65] Restoring fetch-dist and sign Make targets These make targets are used as part of the release process. They had yet to be brought over to the v3 branch from the v2 branch as they were developed after the branching happened. Signed-off-by: Matt Farina --- Makefile | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index e48a20fd5..611222e28 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,8 @@ -BINDIR := $(CURDIR)/bin -DIST_DIRS := find * -type d -exec -TARGETS := darwin/amd64 linux/amd64 linux/386 linux/arm linux/arm64 linux/ppc64le windows/amd64 -BINNAME ?= helm +BINDIR := $(CURDIR)/bin +DIST_DIRS := find * -type d -exec +TARGETS := darwin/amd64 linux/amd64 linux/386 linux/arm linux/arm64 linux/ppc64le 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 windows-amd64.zip windows-amd64.zip.sha256 +BINNAME ?= helm GOPATH = $(shell go env GOPATH) DEP = $(GOPATH)/bin/dep @@ -138,6 +139,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://get.helm.sh/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 \ From 361db773881415398ce05637f9f56bd6f2820c85 Mon Sep 17 00:00:00 2001 From: Robert Brennan Date: Thu, 5 Dec 2019 16:45:53 -0500 Subject: [PATCH 52/65] Fix godoc badge Signed-off-by: Robert Brennan --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bb1e40ca6..73fd189d7 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![CircleCI](https://circleci.com/gh/helm/helm.svg?style=shield)](https://circleci.com/gh/helm/helm) [![Go Report Card](https://goreportcard.com/badge/github.com/helm/helm)](https://goreportcard.com/report/github.com/helm/helm) -[![GoDoc](https://godoc.org/helm.sh/helm?status.svg)](https://godoc.org/helm.sh/helm) +[![GoDoc](https://img.shields.io/static/v1?label=godoc&message=reference&color=blue)](https://pkg.go.dev/helm.sh/helm/v3) [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/3131/badge)](https://bestpractices.coreinfrastructure.org/projects/3131) Helm is a tool for managing Charts. Charts are packages of pre-configured Kubernetes resources. From 36a8001e2adc0e5cf1bc3a06c75777a0b2ee15b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=B7=E7=9A=84=E6=BE=9C=E8=89=B2?= <33822635+zwwhdls@users.noreply.github.com> Date: Fri, 6 Dec 2019 17:32:12 +0800 Subject: [PATCH 53/65] fix this inconsistency in the docs (#7157) Signed-off-by: zwwhdls --- cmd/helm/package.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/cmd/helm/package.go b/cmd/helm/package.go index dd4bb2d17..f82c0950d 100644 --- a/cmd/helm/package.go +++ b/cmd/helm/package.go @@ -36,9 +36,6 @@ This command packages a chart into a versioned chart archive file. If a path is given, this will look at that path for a chart (which must contain a Chart.yaml file) and then package that directory. -If no path is given, this will look in the present working directory for a -Chart.yaml file, and (if found) build the current directory into a chart. - Versioned chart archives are used by Helm package repositories. ` From 0e42a77ae6ae266cfa299de3b3bfd204f35b9f7a Mon Sep 17 00:00:00 2001 From: Matt Butcher Date: Fri, 6 Dec 2019 09:14:39 -0700 Subject: [PATCH 54/65] improved the error message for failed package signing (#6948) Signed-off-by: Matt Butcher --- cmd/helm/package.go | 8 ++++++++ pkg/provenance/sign.go | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/cmd/helm/package.go b/cmd/helm/package.go index f82c0950d..9f7961f95 100644 --- a/cmd/helm/package.go +++ b/cmd/helm/package.go @@ -37,6 +37,14 @@ is given, this will look at that path for a chart (which must contain a Chart.yaml file) and then package that directory. Versioned chart archives are used by Helm package repositories. + +To sign a chart, use the '--sign' flag. In most cases, you should also +provide '--keyring path/to/secret/keys' and '--key keyname'. + + $ helm package --sign ./mychart --key mykey --keyring ~/.gnupg/secring.gpg + +If '--keyring' is not specified, Helm usually defaults to the public keyring +unless your environment is otherwise configured. ` func newPackageCmd(out io.Writer) *cobra.Command { diff --git a/pkg/provenance/sign.go b/pkg/provenance/sign.go index 6032eb063..5d16779f1 100644 --- a/pkg/provenance/sign.go +++ b/pkg/provenance/sign.go @@ -169,7 +169,7 @@ func (s *Signatory) DecryptKey(fn PassphraseFetcher) error { if s.Entity == nil { return errors.New("private key not found") } else if s.Entity.PrivateKey == nil { - return errors.New("provided key is not a private key") + return errors.New("provided key is not a private key. Try providing a keyring with secret keys") } // Nothing else to do if key is not encrypted. @@ -203,7 +203,7 @@ func (s *Signatory) ClearSign(chartpath string) (string, error) { if s.Entity == nil { return "", errors.New("private key not found") } else if s.Entity.PrivateKey == nil { - return "", errors.New("provided key is not a private key") + return "", errors.New("provided key is not a private key. Try providing a keyring with secret keys") } if fi, err := os.Stat(chartpath); err != nil { From e47c67c427e9831d3df20befc7fa139404829ddc Mon Sep 17 00:00:00 2001 From: Matt Butcher Date: Fri, 6 Dec 2019 09:14:51 -0700 Subject: [PATCH 55/65] fix: clarified behavior of 'list --deleted' (#6950) Signed-off-by: Matt Butcher --- cmd/helm/list.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/helm/list.go b/cmd/helm/list.go index 83edfe156..0da0c21d3 100644 --- a/cmd/helm/list.go +++ b/cmd/helm/list.go @@ -97,7 +97,7 @@ func newListCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { f.BoolVarP(&client.ByDate, "date", "d", false, "sort by release date") f.BoolVarP(&client.SortReverse, "reverse", "r", false, "reverse the sort order") f.BoolVarP(&client.All, "all", "a", false, "show all releases, not just the ones marked deployed or failed") - f.BoolVar(&client.Uninstalled, "uninstalled", false, "show uninstalled releases") + f.BoolVar(&client.Uninstalled, "uninstalled", false, "show uninstalled releases (if 'helm uninstall --keep-history' was used)") f.BoolVar(&client.Superseded, "superseded", false, "show superseded releases") f.BoolVar(&client.Uninstalling, "uninstalling", false, "show releases that are currently being uninstalled") f.BoolVar(&client.Deployed, "deployed", false, "show deployed releases. If no other is specified, this will be automatically enabled") From cb81b07125585309d0cf5a17ce57dcd10429d8a1 Mon Sep 17 00:00:00 2001 From: Fabian Ruff Date: Fri, 22 Nov 2019 16:27:08 +0100 Subject: [PATCH 56/65] Reintroduce --is-upgrade to template command This change allows correct rendering of manifests for the upgrade case using `helm template`. Signed-off-by: Fabian Ruff --- cmd/helm/template.go | 1 + pkg/action/install.go | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/cmd/helm/template.go b/cmd/helm/template.go index b660cc69f..a47631c0d 100644 --- a/cmd/helm/template.go +++ b/cmd/helm/template.go @@ -129,6 +129,7 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { f.StringVar(&client.OutputDir, "output-dir", "", "writes the executed templates to files in output-dir instead of stdout") f.BoolVar(&validate, "validate", false, "validate your manifests against the Kubernetes cluster you are currently pointing at. This is the same validation performed on an install") f.BoolVar(&includeCrds, "include-crds", false, "include CRDs in the templated output") + f.BoolVar(&client.IsUpgrade, "is-upgrade", false, "set .Release.IsUpgrade instead of .Release.IsInstall") f.StringArrayVarP(&extraAPIs, "api-versions", "a", []string{}, "Kubernetes api versions used for Capabilities.APIVersions") return cmd diff --git a/pkg/action/install.go b/pkg/action/install.go index 8cd270693..b08f2fb67 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -86,6 +86,8 @@ type Install struct { // APIVersions allows a manual set of supported API Versions to be passed // (for things like templating). These are ignored if ClientOnly is false APIVersions chartutil.VersionSet + // Used by helm template to render charts with .Relase.IsUpgrade. Ignored if Dry-Run is false + IsUpgrade bool } // ChartPathOptions captures common options used for controlling chart paths @@ -197,11 +199,14 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release. return nil, err } + //special case for helm template --is-upgrade + isUpgrade := i.IsUpgrade && i.DryRun options := chartutil.ReleaseOptions{ Name: i.ReleaseName, Namespace: i.Namespace, Revision: 1, - IsInstall: true, + IsInstall: !isUpgrade, + IsUpgrade: isUpgrade, } valuesToRender, err := chartutil.ToRenderValues(chrt, vals, options, caps) if err != nil { @@ -237,7 +242,7 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release. // we'll end up in a state where we will delete those resources upon // deleting the release because the manifest will be pointing at that // resource - if !i.ClientOnly { + if !i.ClientOnly && !isUpgrade { if err := existingResourceConflict(resources); err != nil { return nil, errors.Wrap(err, "rendered manifests contain a resource that already exists. Unable to continue with install") } From 357d265de0e72f02c493701cdbee9ecc6eb0a016 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mat=C3=ADas=20de=20la=20C=C3=A1mara=20Beovide?= Date: Mon, 9 Dec 2019 13:48:31 -0300 Subject: [PATCH 57/65] fix(helm): add --description flag to helm (#7074) * fix(helm): add --description flag to 'helm install', 'helm upgrade', and 'helm uninstall' When added, this flag allow us to add a custom description to the release. E.g. '--description "my custom description"' Closes #7033 Signed-off-by: Juan Matias Kungfu de la Camara Beovide * fix(helm): fixed style issues on top of previous commit (https://github.com/helm/helm/commit/3a43a9a487270b40d42db451d4856dbec30cf72e) Closes #7033 Signed-off-by: Juan Matias Kungfu de la Camara Beovide * fix(helm): fixed wrong test issue on top of previous commit (3a43a9a) Closes #7033 Signed-off-by: Juan Matias Kungfu de la Camara Beovide --- cmd/helm/install.go | 1 + cmd/helm/uninstall.go | 1 + cmd/helm/upgrade.go | 1 + pkg/action/install.go | 7 ++++++- pkg/action/uninstall.go | 7 ++++++- pkg/action/upgrade.go | 13 +++++++++++-- 6 files changed, 26 insertions(+), 4 deletions(-) diff --git a/cmd/helm/install.go b/cmd/helm/install.go index 0c14c013b..176250f84 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -135,6 +135,7 @@ func addInstallFlags(f *pflag.FlagSet, client *action.Install, valueOpts *values f.BoolVar(&client.Wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment, StatefulSet, or ReplicaSet are in a ready state before marking the release as successful. It will wait for as long as --timeout") f.BoolVarP(&client.GenerateName, "generate-name", "g", false, "generate the name (and omit the NAME parameter)") f.StringVar(&client.NameTemplate, "name-template", "", "specify template used to name the release") + f.StringVar(&client.Description, "description", "", "add a custom description") f.BoolVar(&client.Devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored") f.BoolVar(&client.DependencyUpdate, "dependency-update", false, "run helm dependency update before installing the chart") f.BoolVar(&client.Atomic, "atomic", false, "if set, installation process purges chart on fail. The --wait flag will be set automatically if --atomic is used") diff --git a/cmd/helm/uninstall.go b/cmd/helm/uninstall.go index 27b5a8426..7096d7873 100644 --- a/cmd/helm/uninstall.go +++ b/cmd/helm/uninstall.go @@ -69,6 +69,7 @@ func newUninstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { f.BoolVar(&client.DisableHooks, "no-hooks", false, "prevent hooks from running during uninstallation") f.BoolVar(&client.KeepHistory, "keep-history", false, "remove all associated resources and mark the release as deleted, but retain the release history") f.DurationVar(&client.Timeout, "timeout", 300*time.Second, "time to wait for any individual Kubernetes operation (like Jobs for hooks)") + f.StringVar(&client.Description, "description", "", "add a custom description") return cmd } diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go index eadc3b63d..dce8ad74f 100644 --- a/cmd/helm/upgrade.go +++ b/cmd/helm/upgrade.go @@ -156,6 +156,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { f.IntVar(&client.MaxHistory, "history-max", 10, "limit the maximum number of revisions saved per release. Use 0 for no limit") f.BoolVar(&client.CleanupOnFail, "cleanup-on-fail", false, "allow deletion of new resources created in this upgrade when upgrade fails") f.BoolVar(&client.SubNotes, "render-subchart-notes", false, "if set, render subchart notes along with the parent") + f.StringVar(&client.Description, "description", "", "add a custom description") addChartPathOptionsFlags(f, &client.ChartPathOptions) addValueOptionsFlags(f, valueOpts) bindOutputFlag(cmd, &outfmt) diff --git a/pkg/action/install.go b/pkg/action/install.go index b08f2fb67..89a343a6f 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -79,6 +79,7 @@ type Install struct { ReleaseName string GenerateName bool NameTemplate string + Description string OutputDir string Atomic bool SkipCRDs bool @@ -297,7 +298,11 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release. } } - rel.SetStatus(release.StatusDeployed, "Install complete") + if len(i.Description) > 0 { + rel.SetStatus(release.StatusDeployed, i.Description) + } else { + rel.SetStatus(release.StatusDeployed, "Install complete") + } // This is a tricky case. The release has been created, but the result // cannot be recorded. The truest thing to tell the user is that the diff --git a/pkg/action/uninstall.go b/pkg/action/uninstall.go index fb72a845b..dfaa98472 100644 --- a/pkg/action/uninstall.go +++ b/pkg/action/uninstall.go @@ -37,6 +37,7 @@ type Uninstall struct { DryRun bool KeepHistory bool Timeout time.Duration + Description string } // NewUninstall creates a new Uninstall object with the given configuration. @@ -118,7 +119,11 @@ func (u *Uninstall) Run(name string) (*release.UninstallReleaseResponse, error) } rel.Info.Status = release.StatusUninstalled - rel.Info.Description = "Uninstallation complete" + if len(u.Description) > 0 { + rel.Info.Description = u.Description + } else { + rel.Info.Description = "Uninstallation complete" + } if !u.KeepHistory { u.cfg.Log("purge requested for %s", name) diff --git a/pkg/action/upgrade.go b/pkg/action/upgrade.go index d0495a864..cdc40eaaa 100644 --- a/pkg/action/upgrade.go +++ b/pkg/action/upgrade.go @@ -58,6 +58,7 @@ type Upgrade struct { Atomic bool CleanupOnFail bool SubNotes bool + Description string } // NewUpgrade creates a new Upgrade object with the given configuration. @@ -218,7 +219,11 @@ func (u *Upgrade) performUpgrade(originalRelease, upgradedRelease *release.Relea if u.DryRun { u.cfg.Log("dry run for %s", upgradedRelease.Name) - upgradedRelease.Info.Description = "Dry run complete" + if len(u.Description) > 0 { + upgradedRelease.Info.Description = u.Description + } else { + upgradedRelease.Info.Description = "Dry run complete" + } return upgradedRelease, nil } @@ -270,7 +275,11 @@ func (u *Upgrade) performUpgrade(originalRelease, upgradedRelease *release.Relea u.cfg.recordRelease(originalRelease) upgradedRelease.Info.Status = release.StatusDeployed - upgradedRelease.Info.Description = "Upgrade complete" + if len(u.Description) > 0 { + upgradedRelease.Info.Description = u.Description + } else { + upgradedRelease.Info.Description = "Upgrade complete" + } return upgradedRelease, nil } From 735bc652a6618afb7502d8154086a1535c7629ea Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Tue, 10 Dec 2019 15:33:30 -0500 Subject: [PATCH 58/65] fix(tests): Repair tests failures When the unreleased tag was removed, some tests that were added after the PR was created started failing. This fixes them. Signed-off-by: Marc Khouzam --- cmd/helm/testdata/output/version-client-shorthand.txt | 2 +- cmd/helm/testdata/output/version-client.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/helm/testdata/output/version-client-shorthand.txt b/cmd/helm/testdata/output/version-client-shorthand.txt index 0d9b536e6..4b493d31c 100644 --- a/cmd/helm/testdata/output/version-client-shorthand.txt +++ b/cmd/helm/testdata/output/version-client-shorthand.txt @@ -1 +1 @@ -version.BuildInfo{Version:"v3.0+unreleased", GitCommit:"", GitTreeState:"", GoVersion:""} +version.BuildInfo{Version:"v3.0", GitCommit:"", GitTreeState:"", GoVersion:""} diff --git a/cmd/helm/testdata/output/version-client.txt b/cmd/helm/testdata/output/version-client.txt index 0d9b536e6..4b493d31c 100644 --- a/cmd/helm/testdata/output/version-client.txt +++ b/cmd/helm/testdata/output/version-client.txt @@ -1 +1 @@ -version.BuildInfo{Version:"v3.0+unreleased", GitCommit:"", GitTreeState:"", GoVersion:""} +version.BuildInfo{Version:"v3.0", GitCommit:"", GitTreeState:"", GoVersion:""} From 95e74c71d91cb0417db768385f88e148e4533905 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Tue, 10 Dec 2019 13:54:24 -0800 Subject: [PATCH 59/65] chore(testdata): remove stale output These testdata output are never consumed Signed-off-by: Matthew Fisher --- cmd/helm/testdata/output/search-single.txt | 2 -- cmd/helm/testdata/output/status-with-resource.txt | 9 --------- cmd/helm/testdata/output/status.yaml | 10 ---------- 3 files changed, 21 deletions(-) delete mode 100644 cmd/helm/testdata/output/search-single.txt delete mode 100644 cmd/helm/testdata/output/status-with-resource.txt delete mode 100644 cmd/helm/testdata/output/status.yaml diff --git a/cmd/helm/testdata/output/search-single.txt b/cmd/helm/testdata/output/search-single.txt deleted file mode 100644 index 936605ae1..000000000 --- a/cmd/helm/testdata/output/search-single.txt +++ /dev/null @@ -1,2 +0,0 @@ -NAME CHART VERSION APP VERSION DESCRIPTION -testing/mariadb 0.3.0 Chart for MariaDB diff --git a/cmd/helm/testdata/output/status-with-resource.txt b/cmd/helm/testdata/output/status-with-resource.txt deleted file mode 100644 index 5f6f4e663..000000000 --- a/cmd/helm/testdata/output/status-with-resource.txt +++ /dev/null @@ -1,9 +0,0 @@ -NAME: flummoxed-chickadee -LAST DEPLOYED: 2016-01-16 00:00:00 +0000 UTC -NAMESPACE: default -STATUS: deployed - -RESOURCES: -resource A -resource B - diff --git a/cmd/helm/testdata/output/status.yaml b/cmd/helm/testdata/output/status.yaml deleted file mode 100644 index a7bc12276..000000000 --- a/cmd/helm/testdata/output/status.yaml +++ /dev/null @@ -1,10 +0,0 @@ -info: - deleted: "0001-01-01T00:00:00Z" - first_deployed: "0001-01-01T00:00:00Z" - last_deployed: "2016-01-16T00:00:00Z" - resources: | - resource A - resource B - status: deployed -name: flummoxed-chickadee -namespace: default From 9254be9675feb5f24201b55682d78afa7c25f256 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Wed, 11 Dec 2019 08:05:43 -0800 Subject: [PATCH 60/65] add Marc Khouzam as a core maintainer Signed-off-by: Matthew Fisher --- OWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/OWNERS b/OWNERS index 715c8993d..d7dac5514 100644 --- a/OWNERS +++ b/OWNERS @@ -4,6 +4,7 @@ maintainers: - fibonacci1729 - hickeyma - jdolitsky + - marckhouzam - mattfarina - michelleN - prydonius From 0cb0eaca948d55da1c824f201aa78f9313763f69 Mon Sep 17 00:00:00 2001 From: "Paul \"TBBle\" Hampson" Date: Thu, 12 Dec 2019 04:07:05 +1100 Subject: [PATCH 61/65] fix(*): Helm v3 handling of APIVersion v1 charts dependencies (#7009) * Include requirements.* as Files in APIVersionV1 Fixes #6974. This ensures that when reading a Chart marked with APIVersion v1, we maintain the behaviour of Helm v2 and include the requirements.yaml and requirements.lock in the Files collection, and hence produce charts that work correctly with Helm v2. Signed-off-by: Paul "Hampy" Hampson * Write out requirements.lock for APIVersion1 Charts This keeps the on-disk format consistent after `helm dependency update` of an APIVersion1 Chart. Signed-off-by: Paul "Hampy" Hampson * Exclude 'dependencies' from APVersion1 Chart.yaml This fixes `helm lint` against an APIVersion1 chart packaged with Helm v3. Signed-off-by: Paul "Hampy" Hampson * Generate APIVersion v2 charts for dependency tests As the generated chart contains no requirements.yaml in its files list, but has dependencies in its metadata, it is not a valid APIVersion v1 chart. Signed-off-by: Paul "Hampy" Hampson * Generate APIVersion v2 charts for manager tests Specifically for the charts that have dependencies, the generated chart contains no requirements.yaml in its files but has dependencies in its metadata. Hence it is not a valid APIVersion v1 chart. Signed-off-by: Paul "Hampy" Hampson --- cmd/helm/dependency_update_test.go | 2 +- pkg/chart/loader/load.go | 6 ++++++ pkg/chartutil/chartfile.go | 9 +++++++++ pkg/chartutil/save.go | 9 +++++++++ pkg/downloader/manager.go | 10 +++++++--- pkg/downloader/manager_test.go | 4 ++-- 6 files changed, 34 insertions(+), 6 deletions(-) diff --git a/cmd/helm/dependency_update_test.go b/cmd/helm/dependency_update_test.go index 53d67ef59..9afc04f8d 100644 --- a/cmd/helm/dependency_update_test.go +++ b/cmd/helm/dependency_update_test.go @@ -182,7 +182,7 @@ func TestDependencyUpdateCmd_DontDeleteOldChartsOnError(t *testing.T) { func createTestingMetadata(name, baseURL string) *chart.Chart { return &chart.Chart{ Metadata: &chart.Metadata{ - APIVersion: chart.APIVersionV1, + APIVersion: chart.APIVersionV2, Name: name, Version: "1.2.3", Dependencies: []*chart.Dependency{ diff --git a/pkg/chart/loader/load.go b/pkg/chart/loader/load.go index 3c38519bc..dd4fd2dff 100644 --- a/pkg/chart/loader/load.go +++ b/pkg/chart/loader/load.go @@ -114,12 +114,18 @@ func LoadFiles(files []*BufferedFile) (*chart.Chart, error) { if err := yaml.Unmarshal(f.Data, c.Metadata); err != nil { return c, errors.Wrap(err, "cannot load requirements.yaml") } + if c.Metadata.APIVersion == chart.APIVersionV1 { + c.Files = append(c.Files, &chart.File{Name: f.Name, Data: f.Data}) + } // Deprecated: requirements.lock is deprecated use Chart.lock. case f.Name == "requirements.lock": c.Lock = new(chart.Lock) if err := yaml.Unmarshal(f.Data, &c.Lock); err != nil { return c, errors.Wrap(err, "cannot load requirements.lock") } + if c.Metadata.APIVersion == chart.APIVersionV1 { + c.Files = append(c.Files, &chart.File{Name: f.Name, Data: f.Data}) + } case strings.HasPrefix(f.Name, "templates/"): c.Templates = append(c.Templates, &chart.File{Name: f.Name, Data: f.Data}) diff --git a/pkg/chartutil/chartfile.go b/pkg/chartutil/chartfile.go index 68176ed5d..756b87cfb 100644 --- a/pkg/chartutil/chartfile.go +++ b/pkg/chartutil/chartfile.go @@ -42,7 +42,16 @@ func LoadChartfile(filename string) (*chart.Metadata, error) { // // 'filename' should be the complete path and filename ('foo/Chart.yaml') func SaveChartfile(filename string, cf *chart.Metadata) error { + // Pull out the dependencies of a v1 Chart, since there's no way + // to tell the serialiser to skip a field for just this use case + savedDependencies := cf.Dependencies + if cf.APIVersion == chart.APIVersionV1 { + cf.Dependencies = nil + } out, err := yaml.Marshal(cf) + if cf.APIVersion == chart.APIVersionV1 { + cf.Dependencies = savedDependencies + } if err != nil { return err } diff --git a/pkg/chartutil/save.go b/pkg/chartutil/save.go index bc8f5bdd9..e264c4391 100644 --- a/pkg/chartutil/save.go +++ b/pkg/chartutil/save.go @@ -141,8 +141,17 @@ func Save(c *chart.Chart, outDir string) (string, error) { func writeTarContents(out *tar.Writer, c *chart.Chart, prefix string) error { base := filepath.Join(prefix, c.Name()) + // Pull out the dependencies of a v1 Chart, since there's no way + // to tell the serialiser to skip a field for just this use case + savedDependencies := c.Metadata.Dependencies + if c.Metadata.APIVersion == chart.APIVersionV1 { + c.Metadata.Dependencies = nil + } // Save Chart.yaml cdata, err := yaml.Marshal(c.Metadata) + if c.Metadata.APIVersion == chart.APIVersionV1 { + c.Metadata.Dependencies = savedDependencies + } if err != nil { return err } diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index 81dd53614..e46af6944 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -163,7 +163,7 @@ func (m *Manager) Update() error { } // Finally, we need to write the lockfile. - return writeLock(m.ChartPath, lock) + return writeLock(m.ChartPath, lock, c.Metadata.APIVersion == chart.APIVersionV1) } func (m *Manager) loadChartDir() (*chart.Chart, error) { @@ -634,12 +634,16 @@ func (m *Manager) loadChartRepositories() (map[string]*repo.ChartRepository, err } // writeLock writes a lockfile to disk -func writeLock(chartpath string, lock *chart.Lock) error { +func writeLock(chartpath string, lock *chart.Lock, legacyLockfile bool) error { data, err := yaml.Marshal(lock) if err != nil { return err } - dest := filepath.Join(chartpath, "Chart.lock") + lockfileName := "Chart.lock" + if legacyLockfile { + lockfileName = "requirements.lock" + } + dest := filepath.Join(chartpath, lockfileName) return ioutil.WriteFile(dest, data, 0644) } diff --git a/pkg/downloader/manager_test.go b/pkg/downloader/manager_test.go index dd83c3dc2..ea235c13f 100644 --- a/pkg/downloader/manager_test.go +++ b/pkg/downloader/manager_test.go @@ -211,7 +211,7 @@ func TestUpdateBeforeBuild(t *testing.T) { Metadata: &chart.Metadata{ Name: "with-dependency", Version: "0.1.0", - APIVersion: "v1", + APIVersion: "v2", Dependencies: []*chart.Dependency{{ Name: d.Metadata.Name, Version: ">=0.1.0", @@ -285,7 +285,7 @@ func checkBuildWithOptionalFields(t *testing.T, chartName string, dep chart.Depe Metadata: &chart.Metadata{ Name: chartName, Version: "0.1.0", - APIVersion: "v1", + APIVersion: "v2", Dependencies: []*chart.Dependency{&dep}, }, } From 3d04c6c5ce5d019e3a1f58354ab9f67453a83f8a Mon Sep 17 00:00:00 2001 From: jabielecki <47531708+jabielecki@users.noreply.github.com> Date: Thu, 12 Dec 2019 12:41:55 +0100 Subject: [PATCH 62/65] ref(pkg/action): split test of filterList (#6875) The existing unit test doesn't cover the most important functionality of filterList(). Adding that check. Separately test the specific namespace-related behavior. Remove the dead variable anotherOldOne. Signed-off-by: Jakub Bielecki --- pkg/action/list_test.go | 55 ++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/pkg/action/list_test.go b/pkg/action/list_test.go index cd86aee68..378a747b0 100644 --- a/pkg/action/list_test.go +++ b/pkg/action/list_test.go @@ -237,27 +237,36 @@ func makeMeSomeReleases(store *storage.Storage, t *testing.T) { } func TestFilterList(t *testing.T) { - one := releaseStub() - one.Name = "one" - one.Namespace = "default" - one.Version = 1 - two := releaseStub() - two.Name = "two" - two.Namespace = "default" - two.Version = 1 - anotherOldOne := releaseStub() - anotherOldOne.Name = "one" - anotherOldOne.Namespace = "testing" - anotherOldOne.Version = 1 - anotherOne := releaseStub() - anotherOne.Name = "one" - anotherOne.Namespace = "testing" - anotherOne.Version = 2 - - list := []*release.Release{one, two, anotherOne} - expectedFilteredList := []*release.Release{one, two, anotherOne} - - filteredList := filterList(list) - - assert.ElementsMatch(t, expectedFilteredList, filteredList) + t.Run("should filter old versions of the same release", func(t *testing.T) { + r1 := releaseStub() + r1.Name = "r" + r1.Version = 1 + r2 := releaseStub() + r2.Name = "r" + r2.Version = 2 + another := releaseStub() + another.Name = "another" + another.Version = 1 + + filteredList := filterList([]*release.Release{r1, r2, another}) + expectedFilteredList := []*release.Release{r2, another} + + assert.ElementsMatch(t, expectedFilteredList, filteredList) + }) + + t.Run("should not filter out any version across namespaces", func(t *testing.T) { + r1 := releaseStub() + r1.Name = "r" + r1.Namespace = "default" + r1.Version = 1 + r2 := releaseStub() + r2.Name = "r" + r2.Namespace = "testing" + r2.Version = 2 + + filteredList := filterList([]*release.Release{r1, r2}) + expectedFilteredList := []*release.Release{r1, r2} + + assert.ElementsMatch(t, expectedFilteredList, filteredList) + }) } From 0fd76b2a2bca5b3febf6488c860a7c6502c70086 Mon Sep 17 00:00:00 2001 From: kvendingoldo Date: Fri, 13 Dec 2019 20:50:25 +0400 Subject: [PATCH 63/65] fix(cmd): Add message about deprecated chart (#6889) Signed-off-by: Alexander Sharov --- cmd/helm/install.go | 5 +++++ cmd/helm/install_test.go | 6 ++++++ cmd/helm/testdata/output/deprecated-chart.txt | 7 +++++++ cmd/helm/testdata/testcharts/deprecated/Chart.yaml | 8 ++++++++ cmd/helm/testdata/testcharts/deprecated/README.md | 3 +++ cmd/helm/upgrade.go | 4 ++++ 6 files changed, 33 insertions(+) create mode 100644 cmd/helm/testdata/output/deprecated-chart.txt create mode 100644 cmd/helm/testdata/testcharts/deprecated/Chart.yaml create mode 100644 cmd/helm/testdata/testcharts/deprecated/README.md diff --git a/cmd/helm/install.go b/cmd/helm/install.go index 176250f84..b75dfce74 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -17,6 +17,7 @@ limitations under the License. package main import ( + "fmt" "io" "time" @@ -182,6 +183,10 @@ func runInstall(args []string, client *action.Install, valueOpts *values.Options return nil, err } + if chartRequested.Metadata.Deprecated { + fmt.Fprintln(out, "WARNING: This chart is deprecated") + } + if req := chartRequested.Metadata.Dependencies; req != nil { // If CheckDependencies returns an error, we have unfulfilled dependencies. // As of Helm 2.4.0, this is treated as a stopping condition: diff --git a/cmd/helm/install_test.go b/cmd/helm/install_test.go index 9ab25417b..e8b573dfc 100644 --- a/cmd/helm/install_test.go +++ b/cmd/helm/install_test.go @@ -183,6 +183,12 @@ func TestInstall(t *testing.T) { wantError: true, golden: "output/subchart-schema-cli-negative.txt", }, + // Install deprecated chart + { + name: "install with warning about deprecated chart", + cmd: "install aeneas testdata/testcharts/deprecated --namespace default", + golden: "output/deprecated-chart.txt", + }, } runTestActionCmd(t, tests) diff --git a/cmd/helm/testdata/output/deprecated-chart.txt b/cmd/helm/testdata/output/deprecated-chart.txt new file mode 100644 index 000000000..e5be2c3f1 --- /dev/null +++ b/cmd/helm/testdata/output/deprecated-chart.txt @@ -0,0 +1,7 @@ +WARNING: This chart is deprecated +NAME: aeneas +LAST DEPLOYED: Fri Sep 2 22:04:05 1977 +NAMESPACE: default +STATUS: deployed +REVISION: 1 +TEST SUITE: None diff --git a/cmd/helm/testdata/testcharts/deprecated/Chart.yaml b/cmd/helm/testdata/testcharts/deprecated/Chart.yaml new file mode 100644 index 000000000..10185beeb --- /dev/null +++ b/cmd/helm/testdata/testcharts/deprecated/Chart.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +description: Deprecated testing chart +home: https://helm.sh/helm +name: deprecated +sources: + - https://github.com/helm/helm +version: 0.1.0 +deprecated: true diff --git a/cmd/helm/testdata/testcharts/deprecated/README.md b/cmd/helm/testdata/testcharts/deprecated/README.md new file mode 100644 index 000000000..0df9a8bbc --- /dev/null +++ b/cmd/helm/testdata/testcharts/deprecated/README.md @@ -0,0 +1,3 @@ +#Deprecated + +This space intentionally left blank. diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go index dce8ad74f..acfc23198 100644 --- a/cmd/helm/upgrade.go +++ b/cmd/helm/upgrade.go @@ -127,6 +127,10 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { } } + if ch.Metadata.Deprecated { + fmt.Fprintln(out, "WARNING: This chart is deprecated") + } + rel, err := client.Run(args[0], ch, vals) if err != nil { return errors.Wrap(err, "UPGRADE FAILED") From 0eaa881c4e699910f1db97ac889f573124f002f3 Mon Sep 17 00:00:00 2001 From: Jason Pickens Date: Tue, 17 Dec 2019 03:47:24 +1300 Subject: [PATCH 64/65] Add missing statuses to the status help text (#7035) Signed-off-by: Jason Pickens --- cmd/helm/status.go | 3 ++- pkg/release/status.go | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/cmd/helm/status.go b/cmd/helm/status.go index 92e12dbe0..92a947c26 100644 --- a/cmd/helm/status.go +++ b/cmd/helm/status.go @@ -31,12 +31,13 @@ import ( "helm.sh/helm/v3/pkg/release" ) +// NOTE: Keep the list of statuses up-to-date with pkg/release/status.go. var statusHelp = ` This command shows the status of a named release. The status consists of: - last deployment time - k8s namespace in which the release lives -- state of the release (can be: unknown, deployed, deleted, superseded, failed or deleting) +- state of the release (can be: unknown, deployed, uninstalled, superseded, failed, uninstalling, pending-install, pending-upgrade or pending-rollback) - list of resources that this release consists of, sorted by kind - details on last test suite run, if applicable - additional notes provided by the chart diff --git a/pkg/release/status.go b/pkg/release/status.go index cd025e279..0e535f9a4 100644 --- a/pkg/release/status.go +++ b/pkg/release/status.go @@ -19,6 +19,7 @@ package release type Status string // Describe the status of a release +// NOTE: Make sure to update cmd/helm/status.go when adding or modifying any of these statuses. const ( // StatusUnknown indicates that a release is in an uncertain state. StatusUnknown Status = "unknown" From a3f00fde691585ffa2dc4934c6813d69ff0ec284 Mon Sep 17 00:00:00 2001 From: Lennard Eijsackers Date: Mon, 16 Dec 2019 18:14:06 +0100 Subject: [PATCH 65/65] fix(helm): Validate number of arguments in install client The 'helm install' command returned confusing error messages if a flag was misspecified (e.g. `helm install name chart --set value foo`). This lead to an error indicating that a name should be specified for the command. Now an explicit check is done on the number of arguments passed, returning a message indicating the invalid arguments (`foo` in the example`). Closes #7225 Signed-off-by: Lennard Eijsackers --- pkg/action/install.go | 4 ++++ pkg/action/install_test.go | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/pkg/action/install.go b/pkg/action/install.go index 89a343a6f..dc5941810 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -555,6 +555,10 @@ func (i *Install) NameAndChart(args []string) (string, string, error) { return nil } + if len(args) > 2 { + return args[0], args[1], errors.Errorf("expected at most two arguments, unexpected arguments: %v", strings.Join(args[2:], ", ")) + } + if len(args) == 2 { return args[0], args[1], flagsNotSet() } diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go index 4637a4b10..d6f1c88cd 100644 --- a/pkg/action/install_test.go +++ b/pkg/action/install_test.go @@ -505,6 +505,14 @@ func TestNameAndChart(t *testing.T) { t.Fatal("expected an error") } is.Equal("must either provide a name or specify --generate-name", err.Error()) + + instAction.NameTemplate = "" + instAction.ReleaseName = "" + _, _, err = instAction.NameAndChart([]string{"foo", chartName, "bar"}) + if err == nil { + t.Fatal("expected an error") + } + is.Equal("expected at most two arguments, unexpected arguments: bar", err.Error()) } func TestNameAndChartGenerateName(t *testing.T) {