diff --git a/cmd/helm/flags.go b/cmd/helm/flags.go index aa22603f4..1e06563d1 100644 --- a/cmd/helm/flags.go +++ b/cmd/helm/flags.go @@ -47,6 +47,7 @@ func addChartPathOptionsFlags(f *pflag.FlagSet, c *action.ChartPathOptions) { f.StringVar(&c.CertFile, "cert-file", "", "identify HTTPS client using this SSL certificate file") f.StringVar(&c.KeyFile, "key-file", "", "identify HTTPS client using this SSL key file") f.StringVar(&c.CaFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle") + f.StringVar(&c.Renegotiate, "renegotiate", "never", "TLS renegotiation strategy, valid options include 'never', 'once' and 'freely'") } // bindOutputFlag will add the output flag to the given command and bind the diff --git a/cmd/helm/repo_add.go b/cmd/helm/repo_add.go index e6afce3d5..32d630de8 100644 --- a/cmd/helm/repo_add.go +++ b/cmd/helm/repo_add.go @@ -49,6 +49,8 @@ type repoAddOptions struct { repoFile string repoCache string + + renegotiate string } func newRepoAddCmd(out io.Writer) *cobra.Command { @@ -75,6 +77,7 @@ func newRepoAddCmd(out io.Writer) *cobra.Command { f.StringVar(&o.certFile, "cert-file", "", "identify HTTPS client using this SSL certificate file") f.StringVar(&o.keyFile, "key-file", "", "identify HTTPS client using this SSL key file") f.StringVar(&o.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle") + f.StringVar(&o.renegotiate, "renegotiate", "never", "TLS renegotiation strategy, valid options include 'never', 'once' and 'freely'") return cmd } @@ -113,13 +116,14 @@ func (o *repoAddOptions) run(out io.Writer) error { } c := repo.Entry{ - Name: o.name, - URL: o.url, - Username: o.username, - Password: o.password, - CertFile: o.certFile, - KeyFile: o.keyFile, - CAFile: o.caFile, + Name: o.name, + URL: o.url, + Username: o.username, + Password: o.password, + CertFile: o.certFile, + KeyFile: o.keyFile, + CAFile: o.caFile, + Renegotiate: o.renegotiate, } r, err := repo.NewChartRepository(&c, getter.All(settings)) diff --git a/internal/tlsutil/tls.go b/internal/tlsutil/tls.go index ed7795dbe..4c50d0729 100644 --- a/internal/tlsutil/tls.go +++ b/internal/tlsutil/tls.go @@ -20,12 +20,47 @@ import ( "crypto/tls" "crypto/x509" "io/ioutil" + "strings" "github.com/pkg/errors" ) -// NewClientTLS returns tls.Config appropriate for client auth. +type TLSRenegotiationStrategy string + +const ( + RenegotiateNever string = "never" + RenegotiateOnceAsClient string = "once" + RenegotiateFreelyAsClient string = "freely" +) + +// Validate and return TLS renegotiation settings +func GetRenegotiation(option string) (strategy tls.RenegotiationSupport, err error) { + option = strings.ToLower(option) + switch option { + // RenegotiateNever disables renegotiation. + case RenegotiateNever: + return tls.RenegotiateNever, nil + // RenegotiateOnceAsClient allows a remote server to request + // renegotiation once per connection. + case RenegotiateOnceAsClient: + return tls.RenegotiateOnceAsClient, nil + // RenegotiateFreelyAsClient allows a remote server to repeatedly + // request renegotiation. + case RenegotiateFreelyAsClient: + return tls.RenegotiateFreelyAsClient, nil + } + return tls.RenegotiateNever, errors.New("invalid TLS Renegotiation strategy selected") +} + +// NewClientTLS returns tls.Config compatible with client auth but without +// support for TLS renegotiation func NewClientTLS(certFile, keyFile, caFile string) (*tls.Config, error) { + return NewClientTLSWithRenegotiate(certFile, keyFile, caFile, RenegotiateNever) +} + +// NewClientTLS returns tls.Config compatible with both client auth and TLS +// Renegotiation +func NewClientTLSWithRenegotiate(certFile, keyFile, caFile string, renegotiate string) (*tls.Config, error) { config := tls.Config{} if certFile != "" && keyFile != "" { @@ -44,6 +79,12 @@ func NewClientTLS(certFile, keyFile, caFile string) (*tls.Config, error) { config.RootCAs = cp } + renegotiation, err := GetRenegotiation(renegotiate) + if err != nil { + return nil, errors.Wrapf(err, "valid options include '%s', '%s' and '%s'", RenegotiateNever, RenegotiateOnceAsClient, RenegotiateFreelyAsClient) + } + config.Renegotiation = renegotiation + return &config, nil } diff --git a/internal/tlsutil/tlsutil_test.go b/internal/tlsutil/tlsutil_test.go index 24551fdec..57e93d0c3 100644 --- a/internal/tlsutil/tlsutil_test.go +++ b/internal/tlsutil/tlsutil_test.go @@ -61,12 +61,12 @@ func testfile(t *testing.T, file string) (path string) { return path } -func TestNewClientTLS(t *testing.T) { +func TestNewClientTLSWithRenegotiate(t *testing.T) { certFile := testfile(t, testCertFile) keyFile := testfile(t, testKeyFile) caCertFile := testfile(t, testCaCertFile) - cfg, err := NewClientTLS(certFile, keyFile, caCertFile) + cfg, err := NewClientTLSWithRenegotiate(certFile, keyFile, caCertFile, RenegotiateNever) if err != nil { t.Error(err) } @@ -81,7 +81,7 @@ func TestNewClientTLS(t *testing.T) { t.Fatalf("mismatch tls RootCAs, expecting non-nil") } - cfg, err = NewClientTLS("", "", caCertFile) + cfg, err = NewClientTLSWithRenegotiate("", "", caCertFile, RenegotiateNever) if err != nil { t.Error(err) } @@ -96,7 +96,7 @@ func TestNewClientTLS(t *testing.T) { t.Fatalf("mismatch tls RootCAs, expecting non-nil") } - cfg, err = NewClientTLS(certFile, keyFile, "") + cfg, err = NewClientTLSWithRenegotiate(certFile, keyFile, "", RenegotiateNever) if err != nil { t.Error(err) } @@ -110,4 +110,12 @@ func TestNewClientTLS(t *testing.T) { if cfg.RootCAs != nil { t.Fatalf("mismatch tls RootCAs, expecting nil") } + + cfgNoRenegotiate, err = NewClientTLS(certFile, keyFile, "") + if err != nil { + t.Error(err) + } + if cfg != cfgNoRenegotiate { + t.Fatalf("config mismatch, configs from NewClientTLS and NewClientTLSWithRenegotiate don't match") + } } diff --git a/internal/urlutil/urlutil.go b/internal/urlutil/urlutil.go index a8cf7398c..4f09abaf2 100644 --- a/internal/urlutil/urlutil.go +++ b/internal/urlutil/urlutil.go @@ -71,3 +71,12 @@ func ExtractHostname(addr string) (string, error) { } return u.Hostname(), nil } + +// ExtractScheme returns scheme from URL +func ExtractScheme(addr string) (string, error) { + u, err := url.Parse(addr) + if err != nil { + return "", err + } + return u.Scheme, nil +} diff --git a/pkg/action/install.go b/pkg/action/install.go index e368bcb28..6a2b4bc1d 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -93,15 +93,16 @@ type Install struct { // ChartPathOptions captures common options used for controlling chart paths type ChartPathOptions struct { - CaFile string // --ca-file - CertFile string // --cert-file - KeyFile string // --key-file - Keyring string // --keyring - Password string // --password - RepoURL string // --repo - Username string // --username - Verify bool // --verify - Version string // --version + CaFile string // --ca-file + CertFile string // --cert-file + KeyFile string // --key-file + Keyring string // --keyring + Password string // --password + RepoURL string // --repo + Username string // --username + Verify bool // --verify + Version string // --version + Renegotiate string // --renegotiate } // NewInstall creates a new Install object with the given configuration. @@ -670,8 +671,12 @@ func (c *ChartPathOptions) LocateChart(name string, settings *cli.EnvSettings) ( dl.Verify = downloader.VerifyAlways } if c.RepoURL != "" { - chartURL, err := repo.FindChartInAuthRepoURL(c.RepoURL, c.Username, c.Password, name, version, - c.CertFile, c.KeyFile, c.CaFile, getter.All(settings)) + finder := repo.NewChartFinder(c.RepoURL, name, version) + finder.SetCredentials(c.Username, c.Password) + finder.SetTLSFiles(c.CertFile, c.KeyFile, c.CaFile) + finder.SetTLSRenegotiation(c.Renegotiate) + finder.SetProvider(getter.All(settings)) + chartURL, err := finder.GetURL() if err != nil { return "", err } diff --git a/pkg/action/pull.go b/pkg/action/pull.go index b0a3d2598..ad8aa8a11 100644 --- a/pkg/action/pull.go +++ b/pkg/action/pull.go @@ -64,6 +64,7 @@ func (p *Pull) Run(chartRef string) (string, error) { Options: []getter.Option{ getter.WithBasicAuth(p.Username, p.Password), getter.WithTLSClientConfig(p.CertFile, p.KeyFile, p.CaFile), + getter.WithTLSRenegotiate(p.Renegotiate), }, RepositoryConfig: p.Settings.RepositoryConfig, RepositoryCache: p.Settings.RepositoryCache, @@ -88,7 +89,12 @@ func (p *Pull) Run(chartRef string) (string, error) { } if p.RepoURL != "" { - chartURL, err := repo.FindChartInAuthRepoURL(p.RepoURL, p.Username, p.Password, chartRef, p.Version, p.CertFile, p.KeyFile, p.CaFile, getter.All(p.Settings)) + finder := repo.NewChartFinder(p.RepoURL, chartRef, p.Version) + finder.SetCredentials(p.Username, p.Password) + finder.SetTLSFiles(p.CertFile, p.KeyFile, p.CaFile) + finder.SetProvider(getter.All(p.Settings)) + finder.SetTLSRenegotiation(p.Renegotiate) + chartURL, err := finder.GetURL() if err != nil { return out.String(), err } diff --git a/pkg/downloader/chart_downloader.go b/pkg/downloader/chart_downloader.go index f3d4321c5..f7a2ff925 100644 --- a/pkg/downloader/chart_downloader.go +++ b/pkg/downloader/chart_downloader.go @@ -182,6 +182,7 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, er c.Options, getter.WithURL(rc.URL), getter.WithTLSClientConfig(rc.CertFile, rc.KeyFile, rc.CAFile), + getter.WithTLSRenegotiate(rc.Renegotiate), ) if rc.Username != "" && rc.Password != "" { c.Options = append( @@ -218,6 +219,10 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, er c.Options = append(c.Options, getter.WithTLSClientConfig(r.Config.CertFile, r.Config.KeyFile, r.Config.CAFile)) } + if r.Config.Renegotiate != "" { + c.Options = append(c.Options, getter.WithTLSRenegotiate(r.Config.Renegotiate)) + } + // 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 e0692c8c8..efd4dd365 100644 --- a/pkg/downloader/chart_downloader_test.go +++ b/pkg/downloader/chart_downloader_test.go @@ -91,6 +91,7 @@ func TestResolveChartOpts(t *testing.T) { expect: []getter.Option{ getter.WithURL("https://example.com/foo-1.2.3.tgz"), getter.WithTLSClientConfig("cert", "key", "ca"), + getter.WithTLSRenegotiate("never"), }, }, } diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index e46af6944..0ae409f5a 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -535,7 +535,9 @@ func (m *Manager) findChartURL(name, version, repoURL string, repos map[string]* return } } - url, err = repo.FindChartInRepoURL(repoURL, name, version, "", "", "", m.Getters) + finder := repo.NewChartFinder(repoURL, name, version) + finder.SetProvider(m.Getters) + url, err = finder.GetURL() if err == nil { return } diff --git a/pkg/downloader/testdata/repositories.yaml b/pkg/downloader/testdata/repositories.yaml index 430865269..449a5c66d 100644 --- a/pkg/downloader/testdata/repositories.yaml +++ b/pkg/downloader/testdata/repositories.yaml @@ -21,3 +21,4 @@ repositories: certFile: "cert" keyFile: "key" caFile: "ca" + renegotiate: "never" diff --git a/pkg/getter/getter.go b/pkg/getter/getter.go index e11dbfcae..0cbeb7ad2 100644 --- a/pkg/getter/getter.go +++ b/pkg/getter/getter.go @@ -28,13 +28,14 @@ import ( // // Getters may or may not ignore these parameters as they are passed in. type options struct { - url string - certFile string - keyFile string - caFile string - username string - password string - userAgent string + url string + certFile string + keyFile string + caFile string + username string + password string + userAgent string + renegotiate string } // Option allows specifying various settings configurable by the user for overriding the defaults @@ -73,6 +74,13 @@ func WithTLSClientConfig(certFile, keyFile, caFile string) Option { } } +// WithTLSRenegotiate sets the TLS renegotiation support +func WithTLSRenegotiate(option string) Option { + return func(opts *options) { + opts.renegotiate = option + } +} + // Getter is an interface to support GET to the specified URL. type Getter interface { // Get file content by url string diff --git a/pkg/getter/httpgetter.go b/pkg/getter/httpgetter.go index 5b476ff2d..13a088bcd 100644 --- a/pkg/getter/httpgetter.go +++ b/pkg/getter/httpgetter.go @@ -89,17 +89,24 @@ func NewHTTPGetter(options ...Option) (Getter, error) { } func (g *HTTPGetter) httpClient() (*http.Client, error) { - if (g.opts.certFile != "" && g.opts.keyFile != "") || g.opts.caFile != "" { - tlsConf, err := tlsutil.NewClientTLS(g.opts.certFile, g.opts.keyFile, g.opts.caFile) + scheme, err := urlutil.ExtractScheme(g.opts.url) + if err != nil { + return nil, err + } + + if scheme == "https" { + tlsConf, err := tlsutil.NewClientTLSWithRenegotiate(g.opts.certFile, g.opts.keyFile, g.opts.caFile, g.opts.renegotiate) if err != nil { - return nil, errors.Wrap(err, "can't create TLS config for client") + return nil, errors.Wrap(err, "can't create TLS config") } + tlsConf.BuildNameToCertificate() sni, err := urlutil.ExtractHostname(g.opts.url) if err != nil { return nil, err } + tlsConf.ServerName = sni client := &http.Client{ diff --git a/pkg/getter/httpgetter_test.go b/pkg/getter/httpgetter_test.go index b20085574..8553badba 100644 --- a/pkg/getter/httpgetter_test.go +++ b/pkg/getter/httpgetter_test.go @@ -148,7 +148,7 @@ func TestDownloadTLS(t *testing.T) { 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) + tlsConf, err := tlsutil.NewClientTLSWithRenegotiate(pub, priv, ca, tlsutil.RenegotiateNever) if err != nil { t.Fatal(errors.Wrap(err, "can't create TLS config for client")) } @@ -162,6 +162,7 @@ func TestDownloadTLS(t *testing.T) { g, err := NewHTTPGetter( WithURL(u.String()), WithTLSClientConfig(pub, priv, ca), + WithTLSRenegotiate(tlsutil.RenegotiateNever), ) if err != nil { t.Fatal(err) @@ -177,7 +178,7 @@ func TestDownloadTLS(t *testing.T) { t.Fatal(err) } - if _, err := g.Get(u.String(), WithURL(u.String()), WithTLSClientConfig(pub, priv, ca)); err != nil { + if _, err := g.Get(u.String(), WithURL(u.String()), WithTLSClientConfig(pub, priv, ca), WithTLSRenegotiate(tlsutil.RenegotiateNever)); err != nil { t.Error(err) } @@ -187,7 +188,18 @@ func TestDownloadTLS(t *testing.T) { t.Fatal(err) } - if _, err := g.Get(u.String(), WithURL(u.String()), WithTLSClientConfig("", "", ca)); err != nil { + if _, err := g.Get(u.String(), WithURL(u.String()), WithTLSClientConfig("", "", ca), WithTLSRenegotiate(tlsutil.RenegotiateNever)); err != nil { t.Error(err) } + + // test with OnceAsClient TLS renegotiation + if _, err := g.Get(u.String(), WithURL(u.String()), WithTLSClientConfig(pub, priv, ca), WithTLSRenegotiate(tlsutil.RenegotiateOnceAsClient)); err != nil { + t.Error(err) + } + + // test with FreelyAsClient TLS renegotiation + if _, err := g.Get(u.String(), WithURL(u.String()), WithTLSClientConfig(pub, priv, ca), WithTLSRenegotiate(tlsutil.RenegotiateFreelyAsClient)); err != nil { + t.Error(err) + } + } diff --git a/pkg/getter/testdata/repository/repositories.yaml b/pkg/getter/testdata/repository/repositories.yaml index 1d884a0c7..6276c8d02 100644 --- a/pkg/getter/testdata/repository/repositories.yaml +++ b/pkg/getter/testdata/repository/repositories.yaml @@ -7,9 +7,11 @@ repositories: keyFile: "" name: stable url: https://kubernetes-charts.storage.googleapis.com + renegotiate: never - caFile: "" cache: repository/cache/local-index.yaml certFile: "" keyFile: "" name: local url: http://127.0.0.1:8879/charts + renegotiate: never diff --git a/pkg/repo/chartrepo.go b/pkg/repo/chartrepo.go index c8d0d6a3d..c4494b3b7 100644 --- a/pkg/repo/chartrepo.go +++ b/pkg/repo/chartrepo.go @@ -31,6 +31,7 @@ import ( "sigs.k8s.io/yaml" "helm.sh/helm/v3/pkg/chart/loader" + "helm.sh/helm/v3/pkg/cli" "helm.sh/helm/v3/pkg/getter" "helm.sh/helm/v3/pkg/helmpath" "helm.sh/helm/v3/pkg/provenance" @@ -38,13 +39,14 @@ import ( // Entry represents a collection of parameters for chart repository type Entry struct { - Name string `json:"name"` - URL string `json:"url"` - Username string `json:"username"` - Password string `json:"password"` - CertFile string `json:"certFile"` - KeyFile string `json:"keyFile"` - CAFile string `json:"caFile"` + Name string `json:"name"` + URL string `json:"url"` + Username string `json:"username"` + Password string `json:"password"` + CertFile string `json:"certFile"` + KeyFile string `json:"keyFile"` + CAFile string `json:"caFile"` + Renegotiate string `json:"renegotiate"` } // ChartRepository represents a chart repository @@ -76,9 +78,8 @@ func NewChartRepository(cfg *Entry, getters getter.Providers) (*ChartRepository, }, nil } -// Load loads a directory of charts as if it were a repository. -// -// It requires the presence of an index.yaml file in the directory. +// Loads a directory of charts as if it were a repository. +// requires the presence of an index.yaml file in the directory. func (r *ChartRepository) Load() error { dirInfo, err := os.Stat(r.Config.Name) if err != nil { @@ -122,6 +123,7 @@ func (r *ChartRepository) DownloadIndexFile() (string, error) { resp, err := r.Client.Get(indexURL, getter.WithURL(r.Config.URL), getter.WithTLSClientConfig(r.Config.CertFile, r.Config.KeyFile, r.Config.CAFile), + getter.WithTLSRenegotiate(r.Config.Renegotiate), getter.WithBasicAuth(r.Config.Username, r.Config.Password), ) if err != nil { @@ -180,38 +182,111 @@ func (r *ChartRepository) generateIndex() error { return nil } -// FindChartInRepoURL finds chart in chart repository pointed by repoURL -// without adding repo to repositories -func FindChartInRepoURL(repoURL, chartName, chartVersion, certFile, keyFile, caFile string, getters getter.Providers) (string, error) { - return FindChartInAuthRepoURL(repoURL, "", "", chartName, chartVersion, certFile, keyFile, caFile, getters) +type TLSConfig struct { + certFile string + keyFile string + caFile string + renegotiate string } -// FindChartInAuthRepoURL finds chart in chart repository pointed by repoURL -// without adding repo to repositories, like FindChartInRepoURL, -// but it also receives credentials for the chart repository. -func FindChartInAuthRepoURL(repoURL, username, password, chartName, chartVersion, certFile, keyFile, caFile string, getters getter.Providers) (string, error) { +type Credentials struct { + username string + password string +} + +type ChartFinder struct { + repoURL string + chartName string + chartVersion string + credentials Credentials + tlsConfig TLSConfig + providers getter.Providers +} + +type FindChart interface { + SetRepoURL(string) FindChart + SetChartName(string) FindChart + SetChartVersion(string) FindChart + SetCredentials(string, string) FindChart + SetTLSFiles(string, string, string) FindChart + SetTLSRenegotiation(string) FindChart + SetProviders(getter.Providers) FindChart + GetURL() (string, error) +} + +// Finder to locate charts in a chart repository without adding repo to +// repositories +func NewChartFinder(repoURL string, chartName string, chartVersion string) ChartFinder { + return ChartFinder{ + repoURL: repoURL, + chartName: chartName, + chartVersion: chartVersion, + credentials: Credentials{}, + tlsConfig: TLSConfig{}, + providers: getter.All(&cli.EnvSettings{}), + } +} + +func (cf *ChartFinder) SetRepoURL(url string) ChartFinder { + cf.repoURL = url + return *cf +} + +func (cf *ChartFinder) SetChartName(name string) ChartFinder { + cf.chartName = name + return *cf +} + +func (cf *ChartFinder) SetChartVersion(version string) ChartFinder { + cf.chartVersion = version + return *cf +} + +func (cf *ChartFinder) SetTLSFiles(certFile string, keyFile string, caFile string) ChartFinder { + cf.tlsConfig.certFile = certFile + cf.tlsConfig.keyFile = keyFile + cf.tlsConfig.caFile = caFile + return *cf +} + +func (cf *ChartFinder) SetCredentials(username string, password string) ChartFinder { + cf.credentials = Credentials{username, password} + return *cf +} + +func (cf *ChartFinder) SetTLSRenegotiation(renegotiate string) ChartFinder { + cf.tlsConfig.renegotiate = renegotiate + return *cf +} + +func (cf *ChartFinder) SetProvider(providers getter.Providers) ChartFinder { + cf.providers = providers + return *cf +} +func (cf *ChartFinder) GetURL() (string, error) { // Download and write the index file to a temporary location buf := make([]byte, 20) rand.Read(buf) name := strings.ReplaceAll(base64.StdEncoding.EncodeToString(buf), "/", "-") c := Entry{ - URL: repoURL, - Username: username, - Password: password, - CertFile: certFile, - KeyFile: keyFile, - CAFile: caFile, - Name: name, + URL: cf.repoURL, + Username: cf.credentials.username, + Password: cf.credentials.password, + CertFile: cf.tlsConfig.certFile, + KeyFile: cf.tlsConfig.keyFile, + CAFile: cf.tlsConfig.caFile, + Name: name, + Renegotiate: cf.tlsConfig.renegotiate, } - r, err := NewChartRepository(&c, getters) + r, err := NewChartRepository(&c, cf.providers) if err != nil { return "", err } idx, err := r.DownloadIndexFile() if err != nil { - return "", errors.Wrapf(err, "looks like %q is not a valid chart repository or cannot be reached", repoURL) + return "", errors.Wrapf(err, "looks like %q is not a valid chart repository or cannot be reached", cf.repoURL) } // Read the index file for the repository to get chart information and return chart URL @@ -220,13 +295,13 @@ func FindChartInAuthRepoURL(repoURL, username, password, chartName, chartVersion return "", err } - errMsg := fmt.Sprintf("chart %q", chartName) - if chartVersion != "" { - errMsg = fmt.Sprintf("%s version %q", errMsg, chartVersion) + errMsg := fmt.Sprintf("chart %q", cf.chartName) + if cf.chartVersion != "" { + errMsg = fmt.Sprintf("%s version %q", errMsg, cf.chartVersion) } - cv, err := repoIndex.Get(chartName, chartVersion) + cv, err := repoIndex.Get(cf.chartName, cf.chartVersion) if err != nil { - return "", errors.Errorf("%s not found in %s repository", errMsg, repoURL) + return "", errors.Errorf("%s not found in %s repository", errMsg, cf.repoURL) } if len(cv.URLs) == 0 { @@ -235,7 +310,7 @@ func FindChartInAuthRepoURL(repoURL, username, password, chartName, chartVersion chartURL := cv.URLs[0] - absoluteChartURL, err := ResolveReferenceURL(repoURL, chartURL) + absoluteChartURL, err := ResolveReferenceURL(cf.repoURL, chartURL) if err != nil { return "", errors.Wrap(err, "failed to make chart URL absolute") } @@ -243,6 +318,28 @@ func FindChartInAuthRepoURL(repoURL, username, password, chartName, chartVersion return absoluteChartURL, nil } +// Obsolete, use NewChartFinder/GetURL instead +// FindChartInRepoURL finds chart in chart repository pointed by repoURL +// without adding repo to repositories +func FindChartInRepoURL(repoURL string, chartName string, chartVersion string, certFile string, keyFile string, caFile string, getters getter.Providers) (string, error) { + finder := NewChartFinder(repoURL, chartName, chartVersion) + finder.SetTLSFiles(certFile, keyFile, caFile) + finder.SetProvider(getters) + return finder.GetURL() +} + +// Obsolete, use NewChartFinder/GetURL instead +// FindChartInAuthRepoURL finds chart in chart repository pointed by repoURL +// without adding repo to repositories, like FindChartInRepoURL, +// but it also receives credentials for the chart repository. +func FindChartInAuthRepoURL(repoURL string, username string, password string, chartName string, chartVersion string, certFile string, keyFile string, caFile string, getters getter.Providers) (string, error) { + finder := NewChartFinder(repoURL, chartName, chartVersion) + finder.SetCredentials(username, password) + finder.SetTLSFiles(certFile, keyFile, caFile) + finder.SetProvider(getters) + return finder.GetURL() +} + // ResolveReferenceURL resolves refURL relative to baseURL. // If refURL is absolute, it simply returns refURL. func ResolveReferenceURL(baseURL, refURL string) (string, error) { diff --git a/pkg/repo/testdata/repositories.yaml b/pkg/repo/testdata/repositories.yaml index a28c48eab..7cbc2c4fe 100644 --- a/pkg/repo/testdata/repositories.yaml +++ b/pkg/repo/testdata/repositories.yaml @@ -3,6 +3,8 @@ repositories: - name: stable url: https://example.com/stable/charts cache: stable-index.yaml + renegotiate: never - name: incubator url: https://example.com/incubator cache: incubator-index.yaml + renegotiate: never