mirror of https://github.com/helm/helm.git
Authentication support for remote charts repositories (#3206)
Authentication support for remote charts repositories.
This commit is contained in:
parent
19c73207b2
commit
b6335b7dfe
|
@ -52,6 +52,8 @@ type fetchCmd struct {
|
|||
destdir string
|
||||
version string
|
||||
repoURL string
|
||||
username string
|
||||
password string
|
||||
|
||||
verify bool
|
||||
verifyLater bool
|
||||
|
@ -106,6 +108,8 @@ func newFetchCmd(out io.Writer) *cobra.Command {
|
|||
f.StringVar(&fch.keyFile, "key-file", "", "identify HTTPS client using this SSL key file")
|
||||
f.StringVar(&fch.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")
|
||||
f.BoolVar(&fch.devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored.")
|
||||
f.StringVar(&fch.username, "username", "", "chart repository username")
|
||||
f.StringVar(&fch.password, "password", "", "chart repository password")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
@ -117,6 +121,8 @@ func (f *fetchCmd) run() error {
|
|||
Keyring: f.keyring,
|
||||
Verify: downloader.VerifyNever,
|
||||
Getters: getter.All(settings),
|
||||
Username: f.username,
|
||||
Password: f.password,
|
||||
}
|
||||
|
||||
if f.verify {
|
||||
|
@ -138,7 +144,7 @@ func (f *fetchCmd) run() error {
|
|||
}
|
||||
|
||||
if f.repoURL != "" {
|
||||
chartURL, err := repo.FindChartInRepoURL(f.repoURL, f.chartRef, f.version, f.certFile, f.keyFile, f.caFile, getter.All(settings))
|
||||
chartURL, err := repo.FindChartInAuthRepoURL(f.repoURL, f.username, f.password, f.chartRef, f.version, f.certFile, f.keyFile, f.caFile, getter.All(settings))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -59,6 +59,8 @@ type inspectCmd struct {
|
|||
out io.Writer
|
||||
version string
|
||||
repoURL string
|
||||
username string
|
||||
password string
|
||||
|
||||
certFile string
|
||||
keyFile string
|
||||
|
@ -88,7 +90,7 @@ func newInspectCmd(out io.Writer) *cobra.Command {
|
|||
if err := checkArgsLength(len(args), "chart name"); err != nil {
|
||||
return err
|
||||
}
|
||||
cp, err := locateChartPath(insp.repoURL, args[0], insp.version, insp.verify, insp.keyring,
|
||||
cp, err := locateChartPath(insp.repoURL, insp.username, insp.password, args[0], insp.version, insp.verify, insp.keyring,
|
||||
insp.certFile, insp.keyFile, insp.caFile)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -107,7 +109,7 @@ func newInspectCmd(out io.Writer) *cobra.Command {
|
|||
if err := checkArgsLength(len(args), "chart name"); err != nil {
|
||||
return err
|
||||
}
|
||||
cp, err := locateChartPath(insp.repoURL, args[0], insp.version, insp.verify, insp.keyring,
|
||||
cp, err := locateChartPath(insp.repoURL, insp.username, insp.password, args[0], insp.version, insp.verify, insp.keyring,
|
||||
insp.certFile, insp.keyFile, insp.caFile)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -126,7 +128,7 @@ func newInspectCmd(out io.Writer) *cobra.Command {
|
|||
if err := checkArgsLength(len(args), "chart name"); err != nil {
|
||||
return err
|
||||
}
|
||||
cp, err := locateChartPath(insp.repoURL, args[0], insp.version, insp.verify, insp.keyring,
|
||||
cp, err := locateChartPath(insp.repoURL, insp.username, insp.password, args[0], insp.version, insp.verify, insp.keyring,
|
||||
insp.certFile, insp.keyFile, insp.caFile)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -145,7 +147,7 @@ func newInspectCmd(out io.Writer) *cobra.Command {
|
|||
if err := checkArgsLength(len(args), "chart name"); err != nil {
|
||||
return err
|
||||
}
|
||||
cp, err := locateChartPath(insp.repoURL, args[0], insp.version, insp.verify, insp.keyring,
|
||||
cp, err := locateChartPath(insp.repoURL, insp.username, insp.password, args[0], insp.version, insp.verify, insp.keyring,
|
||||
insp.certFile, insp.keyFile, insp.caFile)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -181,6 +183,18 @@ func newInspectCmd(out io.Writer) *cobra.Command {
|
|||
subCmd.Flags().StringVar(&insp.repoURL, repoURL, "", repoURLdesc)
|
||||
}
|
||||
|
||||
username := "username"
|
||||
usernamedesc := "chart repository username where to locate the requested chart"
|
||||
inspectCommand.Flags().StringVar(&insp.username, username, "", usernamedesc)
|
||||
valuesSubCmd.Flags().StringVar(&insp.username, username, "", usernamedesc)
|
||||
chartSubCmd.Flags().StringVar(&insp.username, username, "", usernamedesc)
|
||||
|
||||
password := "password"
|
||||
passworddesc := "chart repository password where to locate the requested chart"
|
||||
inspectCommand.Flags().StringVar(&insp.password, password, "", passworddesc)
|
||||
valuesSubCmd.Flags().StringVar(&insp.password, password, "", passworddesc)
|
||||
chartSubCmd.Flags().StringVar(&insp.password, password, "", passworddesc)
|
||||
|
||||
certFile := "cert-file"
|
||||
certFiledesc := "verify certificates of HTTPS-enabled servers using this CA bundle"
|
||||
for _, subCmd := range cmds {
|
||||
|
|
|
@ -118,6 +118,8 @@ type installCmd struct {
|
|||
timeout int64
|
||||
wait bool
|
||||
repoURL string
|
||||
username string
|
||||
password string
|
||||
devel bool
|
||||
depUp bool
|
||||
|
||||
|
@ -165,7 +167,7 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command {
|
|||
inst.version = ">0.0.0-0"
|
||||
}
|
||||
|
||||
cp, err := locateChartPath(inst.repoURL, args[0], inst.version, inst.verify, inst.keyring,
|
||||
cp, err := locateChartPath(inst.repoURL, inst.username, inst.password, args[0], inst.version, inst.verify, inst.keyring,
|
||||
inst.certFile, inst.keyFile, inst.caFile)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -191,6 +193,8 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command {
|
|||
f.Int64Var(&inst.timeout, "timeout", 300, "time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks)")
|
||||
f.BoolVar(&inst.wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment are in a ready state before marking the release as successful. It will wait for as long as --timeout")
|
||||
f.StringVar(&inst.repoURL, "repo", "", "chart repository url where to locate the requested chart")
|
||||
f.StringVar(&inst.username, "username", "", "chart repository username where to locate the requested chart")
|
||||
f.StringVar(&inst.password, "password", "", "chart repository password where to locate the requested chart")
|
||||
f.StringVar(&inst.certFile, "cert-file", "", "identify HTTPS client using this SSL certificate file")
|
||||
f.StringVar(&inst.keyFile, "key-file", "", "identify HTTPS client using this SSL key file")
|
||||
f.StringVar(&inst.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")
|
||||
|
@ -381,7 +385,7 @@ func (i *installCmd) printRelease(rel *release.Release) {
|
|||
// - URL
|
||||
//
|
||||
// If 'verify' is true, this will attempt to also verify the chart.
|
||||
func locateChartPath(repoURL, name, version string, verify bool, keyring,
|
||||
func locateChartPath(repoURL, username, password, name, version string, verify bool, keyring,
|
||||
certFile, keyFile, caFile string) (string, error) {
|
||||
name = strings.TrimSpace(name)
|
||||
version = strings.TrimSpace(version)
|
||||
|
@ -414,12 +418,14 @@ func locateChartPath(repoURL, name, version string, verify bool, keyring,
|
|||
Out: os.Stdout,
|
||||
Keyring: keyring,
|
||||
Getters: getter.All(settings),
|
||||
Username: username,
|
||||
Password: password,
|
||||
}
|
||||
if verify {
|
||||
dl.Verify = downloader.VerifyAlways
|
||||
}
|
||||
if repoURL != "" {
|
||||
chartURL, err := repo.FindChartInRepoURL(repoURL, name, version,
|
||||
chartURL, err := repo.FindChartInAuthRepoURL(repoURL, username, password, name, version,
|
||||
certFile, keyFile, caFile, getter.All(settings))
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
|
|
@ -30,6 +30,8 @@ import (
|
|||
type repoAddCmd struct {
|
||||
name string
|
||||
url string
|
||||
username string
|
||||
password string
|
||||
home helmpath.Home
|
||||
noupdate bool
|
||||
|
||||
|
@ -60,6 +62,8 @@ func newRepoAddCmd(out io.Writer) *cobra.Command {
|
|||
}
|
||||
|
||||
f := cmd.Flags()
|
||||
f.StringVar(&add.username, "username", "", "chart repository username")
|
||||
f.StringVar(&add.password, "password", "", "chart repository password")
|
||||
f.BoolVar(&add.noupdate, "no-update", false, "raise error if repo is already registered")
|
||||
f.StringVar(&add.certFile, "cert-file", "", "identify HTTPS client using this SSL certificate file")
|
||||
f.StringVar(&add.keyFile, "key-file", "", "identify HTTPS client using this SSL key file")
|
||||
|
@ -69,14 +73,14 @@ func newRepoAddCmd(out io.Writer) *cobra.Command {
|
|||
}
|
||||
|
||||
func (a *repoAddCmd) run() error {
|
||||
if err := addRepository(a.name, a.url, a.home, a.certFile, a.keyFile, a.caFile, a.noupdate); err != nil {
|
||||
if err := addRepository(a.name, a.url, a.username, a.password, a.home, a.certFile, a.keyFile, a.caFile, a.noupdate); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(a.out, "%q has been added to your repositories\n", a.name)
|
||||
return nil
|
||||
}
|
||||
|
||||
func addRepository(name, url string, home helmpath.Home, certFile, keyFile, caFile string, noUpdate bool) error {
|
||||
func addRepository(name, url, username, password string, home helmpath.Home, certFile, keyFile, caFile string, noUpdate bool) error {
|
||||
f, err := repo.LoadRepositoriesFile(home.RepositoryFile())
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -91,6 +95,8 @@ func addRepository(name, url string, home helmpath.Home, certFile, keyFile, caFi
|
|||
Name: name,
|
||||
Cache: cif,
|
||||
URL: url,
|
||||
Username: username,
|
||||
Password: password,
|
||||
CertFile: certFile,
|
||||
KeyFile: keyFile,
|
||||
CAFile: caFile,
|
||||
|
|
|
@ -80,7 +80,7 @@ func TestRepoAdd(t *testing.T) {
|
|||
|
||||
settings.Home = thome
|
||||
|
||||
if err := addRepository(testName, ts.URL(), hh, "", "", "", true); err != nil {
|
||||
if err := addRepository(testName, ts.URL(), "", "", hh, "", "", "", true); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
|
@ -93,11 +93,11 @@ func TestRepoAdd(t *testing.T) {
|
|||
t.Errorf("%s was not successfully inserted into %s", testName, hh.RepositoryFile())
|
||||
}
|
||||
|
||||
if err := addRepository(testName, ts.URL(), hh, "", "", "", false); err != nil {
|
||||
if err := addRepository(testName, ts.URL(), "", "", hh, "", "", "", false); err != nil {
|
||||
t.Errorf("Repository was not updated: %s", err)
|
||||
}
|
||||
|
||||
if err := addRepository(testName, ts.URL(), hh, "", "", "", false); err != nil {
|
||||
if err := addRepository(testName, ts.URL(), "", "", hh, "", "", "", false); err != nil {
|
||||
t.Errorf("Duplicate repository name was added")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ func TestRepoRemove(t *testing.T) {
|
|||
if err := removeRepoLine(b, testName, hh); err == nil {
|
||||
t.Errorf("Expected error removing %s, but did not get one.", testName)
|
||||
}
|
||||
if err := addRepository(testName, ts.URL(), hh, "", "", "", true); err != nil {
|
||||
if err := addRepository(testName, ts.URL(), "", "", hh, "", "", "", true); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
|
|
|
@ -73,6 +73,8 @@ type upgradeCmd struct {
|
|||
reuseValues bool
|
||||
wait bool
|
||||
repoURL string
|
||||
username string
|
||||
password string
|
||||
devel bool
|
||||
|
||||
certFile string
|
||||
|
@ -128,6 +130,8 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command {
|
|||
f.BoolVar(&upgrade.reuseValues, "reuse-values", false, "when upgrading, reuse the last release's values, and merge in any new values. If '--reset-values' is specified, this is ignored.")
|
||||
f.BoolVar(&upgrade.wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment are in a ready state before marking the release as successful. It will wait for as long as --timeout")
|
||||
f.StringVar(&upgrade.repoURL, "repo", "", "chart repository url where to locate the requested chart")
|
||||
f.StringVar(&upgrade.username, "username", "", "chart repository username where to locate the requested chart")
|
||||
f.StringVar(&upgrade.password, "password", "", "chart repository password where to locate the requested chart")
|
||||
f.StringVar(&upgrade.certFile, "cert-file", "", "identify HTTPS client using this SSL certificate file")
|
||||
f.StringVar(&upgrade.keyFile, "key-file", "", "identify HTTPS client using this SSL key file")
|
||||
f.StringVar(&upgrade.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")
|
||||
|
@ -139,7 +143,7 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command {
|
|||
}
|
||||
|
||||
func (u *upgradeCmd) run() error {
|
||||
chartPath, err := locateChartPath(u.repoURL, u.chart, u.version, u.verify, u.keyring, u.certFile, u.keyFile, u.caFile)
|
||||
chartPath, err := locateChartPath(u.repoURL, u.username, u.password, u.chart, u.version, u.verify, u.keyring, u.certFile, u.keyFile, u.caFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -148,6 +148,11 @@ Charts repository hosts its charts, so you may want to take a
|
|||
**Note:** A public GCS bucket can be accessed via simple HTTPS at this address
|
||||
`https://bucket-name.storage.googleapis.com/`.
|
||||
|
||||
### JFrog Artifactory
|
||||
|
||||
You can also set up chart repositories using JFrog Artifactory.
|
||||
Read more about chart repositories with JFrog Artifactory [here](https://www.jfrog.com/confluence/display/RTF/Helm+Chart+Repositories)
|
||||
|
||||
### Github Pages example
|
||||
|
||||
In a similar way you can create charts repository using GitHub Pages.
|
||||
|
@ -270,10 +275,10 @@ fantastic-charts https://fantastic-charts.storage.googleapis.com
|
|||
If the charts are backed by HTTP basic authentication, you can also supply the
|
||||
username and password here:
|
||||
|
||||
```console
|
||||
$ helm repo add fantastic-charts https://username:password@fantastic-charts.storage.googleapis.com
|
||||
``console
|
||||
$ helm repo add fantastic-charts https://fantastic-charts.storage.googleapis.com --username my-username --password my-password
|
||||
$ helm repo list
|
||||
fantastic-charts https://username:password@fantastic-charts.storage.googleapis.com
|
||||
fantastic-charts https://fantastic-charts.storage.googleapis.com
|
||||
```
|
||||
|
||||
**Note:** A repository will not be added if it does not contain a valid
|
||||
|
|
|
@ -33,10 +33,12 @@ helm fetch [flags] [chart URL | repo/chartname] [...]
|
|||
--devel use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored.
|
||||
--key-file string identify HTTPS client using this SSL key file
|
||||
--keyring string keyring containing public keys (default "~/.gnupg/pubring.gpg")
|
||||
--password string chart repository password
|
||||
--prov fetch the provenance file, but don't perform verification
|
||||
--repo string chart repository url where to locate the requested chart
|
||||
--untar if set to true, will untar the chart after downloading it
|
||||
--untardir string if untar is specified, this flag specifies the name of the directory into which the chart is expanded (default ".")
|
||||
--username string chart repository username
|
||||
--verify verify the package against its signature
|
||||
--version string specific version of a chart. Without this, the latest version is fetched
|
||||
```
|
||||
|
@ -54,5 +56,3 @@ helm fetch [flags] [chart URL | repo/chartname] [...]
|
|||
|
||||
### SEE ALSO
|
||||
* [helm](helm.md) - The Helm package manager for Kubernetes.
|
||||
|
||||
###### Auto generated by spf13/cobra on 8-Mar-2018
|
||||
|
|
|
@ -23,7 +23,9 @@ helm inspect [CHART]
|
|||
--cert-file string verify certificates of HTTPS-enabled servers using this CA bundle
|
||||
--key-file string identify HTTPS client using this SSL key file
|
||||
--keyring string path to the keyring containing public verification keys (default "~/.gnupg/pubring.gpg")
|
||||
--password string chart repository password where to locate the requested chart
|
||||
--repo string chart repository url where to locate the requested chart
|
||||
--username string chart repository username where to locate the requested chart
|
||||
--verify verify the provenance data for this chart
|
||||
--version string version of the chart. By default, the newest chart is shown
|
||||
```
|
||||
|
|
|
@ -21,7 +21,9 @@ helm inspect chart [CHART]
|
|||
--cert-file string verify certificates of HTTPS-enabled servers using this CA bundle
|
||||
--key-file string identify HTTPS client using this SSL key file
|
||||
--keyring string path to the keyring containing public verification keys (default "~/.gnupg/pubring.gpg")
|
||||
--password string chart repository password where to locate the requested chart
|
||||
--repo string chart repository url where to locate the requested chart
|
||||
--username string chart repository username where to locate the requested chart
|
||||
--verify verify the provenance data for this chart
|
||||
--version string version of the chart. By default, the newest chart is shown
|
||||
```
|
||||
|
|
|
@ -21,7 +21,9 @@ helm inspect values [CHART]
|
|||
--cert-file string verify certificates of HTTPS-enabled servers using this CA bundle
|
||||
--key-file string identify HTTPS client using this SSL key file
|
||||
--keyring string path to the keyring containing public verification keys (default "~/.gnupg/pubring.gpg")
|
||||
--password string chart repository password where to locate the requested chart
|
||||
--repo string chart repository url where to locate the requested chart
|
||||
--username string chart repository username where to locate the requested chart
|
||||
--verify verify the provenance data for this chart
|
||||
--version string version of the chart. By default, the newest chart is shown
|
||||
```
|
||||
|
|
|
@ -80,6 +80,7 @@ helm install [CHART]
|
|||
--name-template string specify template used to name the release
|
||||
--namespace string namespace to install the release into. Defaults to the current kube config namespace.
|
||||
--no-hooks prevent hooks from running during install
|
||||
--password string chart repository password where to locate the requested chart
|
||||
--replace re-use the given name, even if that name is already used. This is unsafe in production
|
||||
--repo string chart repository url where to locate the requested chart
|
||||
--set stringArray set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)
|
||||
|
@ -89,6 +90,7 @@ helm install [CHART]
|
|||
--tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem")
|
||||
--tls-key string path to TLS key file (default "$HELM_HOME/key.pem")
|
||||
--tls-verify enable TLS for request and verify remote
|
||||
--username string chart repository username where to locate the requested chart
|
||||
-f, --values valueFiles specify values in a YAML file or a URL(can specify multiple) (default [])
|
||||
--verify verify the package before installing it
|
||||
--version string specify the exact chart version to install. If this is not specified, the latest version is installed
|
||||
|
|
|
@ -18,6 +18,8 @@ helm repo add [flags] [NAME] [URL]
|
|||
--cert-file string identify HTTPS client using this SSL certificate file
|
||||
--key-file string identify HTTPS client using this SSL key file
|
||||
--no-update raise error if repo is already registered
|
||||
--password string chart repository password
|
||||
--username string chart repository username
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
|
|
@ -46,6 +46,7 @@ helm upgrade [RELEASE] [CHART]
|
|||
--keyring string path to the keyring that contains public signing keys (default "~/.gnupg/pubring.gpg")
|
||||
--namespace string namespace to install the release into (only used if --install is set). Defaults to the current kube config namespace
|
||||
--no-hooks disable pre/post upgrade hooks
|
||||
--password string chart repository password where to locate the requested chart
|
||||
--recreate-pods performs pods restart for the resource if applicable
|
||||
--repo string chart repository url where to locate the requested chart
|
||||
--reset-values when upgrading, reset the values to the ones built into the chart
|
||||
|
@ -57,6 +58,7 @@ helm upgrade [RELEASE] [CHART]
|
|||
--tls-cert string path to TLS certificate file (default "$HELM_HOME/cert.pem")
|
||||
--tls-key string path to TLS key file (default "$HELM_HOME/key.pem")
|
||||
--tls-verify enable TLS for request and verify remote
|
||||
--username string chart repository username where to locate the requested chart
|
||||
-f, --values valueFiles specify values in a YAML file or a URL(can specify multiple) (default [])
|
||||
--verify verify the provenance of the chart before upgrading
|
||||
--version string specify the exact chart version to use. If this is not specified, the latest version is used
|
||||
|
|
|
@ -67,6 +67,10 @@ type ChartDownloader struct {
|
|||
HelmHome helmpath.Home
|
||||
// Getter collection for the operation
|
||||
Getters getter.Providers
|
||||
// Chart repository username
|
||||
Username string
|
||||
// Chart repository password
|
||||
Password string
|
||||
}
|
||||
|
||||
// DownloadTo retrieves a chart. Depending on the settings, it may also download a provenance file.
|
||||
|
@ -81,7 +85,7 @@ type ChartDownloader struct {
|
|||
// Returns a string path to the location where the file was downloaded and a verification
|
||||
// (if provenance was verified), or an error if something bad happened.
|
||||
func (c *ChartDownloader) DownloadTo(ref, version, dest string) (string, *provenance.Verification, error) {
|
||||
u, g, err := c.ResolveChartVersion(ref, version)
|
||||
u, r, g, err := c.ResolveChartVersionAndGetRepo(ref, version)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
@ -100,7 +104,7 @@ func (c *ChartDownloader) DownloadTo(ref, version, dest string) (string, *proven
|
|||
// If provenance is requested, verify it.
|
||||
ver := &provenance.Verification{}
|
||||
if c.Verify > VerifyNever {
|
||||
body, err := g.Get(u.String() + ".prov")
|
||||
body, err := r.Client.Get(u.String() + ".prov")
|
||||
if err != nil {
|
||||
if c.Verify == VerifyAlways {
|
||||
return destfile, ver, fmt.Errorf("Failed to fetch provenance %q", u.String()+".prov")
|
||||
|
@ -140,96 +144,132 @@ func (c *ChartDownloader) DownloadTo(ref, version, dest string) (string, *proven
|
|||
// * If version is empty, this will return the URL for the latest version
|
||||
// * If no version can be found, an error is returned
|
||||
func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, getter.Getter, error) {
|
||||
u, r, _, err := c.ResolveChartVersionAndGetRepo(ref, version)
|
||||
if r != nil {
|
||||
return u, r.Client, err
|
||||
}
|
||||
return u, nil, err
|
||||
}
|
||||
|
||||
// Same as the ResolveChartVersion method, but returns the chart repositoryy.
|
||||
func (c *ChartDownloader) ResolveChartVersionAndGetRepo(ref, version string) (*url.URL, *repo.ChartRepository, *getter.HttpGetter, error) {
|
||||
u, err := url.Parse(ref)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("invalid chart URL format: %s", ref)
|
||||
return nil, nil, nil, fmt.Errorf("invalid chart URL format: %s", ref)
|
||||
}
|
||||
|
||||
rf, err := repo.LoadRepositoriesFile(c.HelmHome.RepositoryFile())
|
||||
if err != nil {
|
||||
return u, nil, err
|
||||
return u, nil, nil, err
|
||||
}
|
||||
|
||||
g, err := getter.NewHTTPGetter(ref, "", "", "")
|
||||
if err != nil {
|
||||
return u, nil, nil, err
|
||||
}
|
||||
g.SetCredentials(c.getRepoCredentials(nil))
|
||||
|
||||
if u.IsAbs() && len(u.Host) > 0 && len(u.Path) > 0 {
|
||||
// In this case, we have to find the parent repo that contains this chart
|
||||
// URL. And this is an unfortunate problem, as it requires actually going
|
||||
// through each repo cache file and finding a matching URL. But basically
|
||||
// we want to find the repo in case we have special SSL cert config
|
||||
// for that repo.
|
||||
|
||||
rc, err := c.scanReposForURL(ref, rf)
|
||||
if err != nil {
|
||||
// If there is no special config, return the default HTTP client and
|
||||
// swallow the error.
|
||||
if err == ErrNoOwnerRepo {
|
||||
getterConstructor, err := c.Getters.ByScheme(u.Scheme)
|
||||
if err != nil {
|
||||
return u, nil, err
|
||||
}
|
||||
getter, err := getterConstructor(ref, "", "", "")
|
||||
return u, getter, err
|
||||
r := &repo.ChartRepository{}
|
||||
r.Client = g
|
||||
g.SetCredentials(c.getRepoCredentials(r))
|
||||
return u, r, g, err
|
||||
}
|
||||
return u, nil, err
|
||||
return u, nil, nil, err
|
||||
}
|
||||
r, err := repo.NewChartRepository(rc, c.Getters)
|
||||
// If we get here, we don't need to go through the next phase of looking
|
||||
// up the URL. We have it already. So we just return.
|
||||
return u, r.Client, err
|
||||
return u, r, g, err
|
||||
}
|
||||
|
||||
// See if it's of the form: repo/path_to_chart
|
||||
p := strings.SplitN(u.Path, "/", 2)
|
||||
if len(p) < 2 {
|
||||
return u, nil, fmt.Errorf("Non-absolute URLs should be in form of repo_name/path_to_chart, got: %s", u)
|
||||
return u, nil, nil, fmt.Errorf("Non-absolute URLs should be in form of repo_name/path_to_chart, got: %s", u)
|
||||
}
|
||||
|
||||
repoName := p[0]
|
||||
chartName := p[1]
|
||||
rc, err := pickChartRepositoryConfigByName(repoName, rf.Repositories)
|
||||
if err != nil {
|
||||
return u, nil, err
|
||||
return u, nil, nil, err
|
||||
}
|
||||
|
||||
r, err := repo.NewChartRepository(rc, c.Getters)
|
||||
if err != nil {
|
||||
return u, nil, err
|
||||
return u, nil, nil, err
|
||||
}
|
||||
|
||||
// Next, we need to load the index, and actually look up the chart.
|
||||
i, err := repo.LoadIndexFile(c.HelmHome.CacheIndex(r.Config.Name))
|
||||
if err != nil {
|
||||
return u, r.Client, fmt.Errorf("no cached repo found. (try 'helm repo update'). %s", err)
|
||||
return u, r, g, fmt.Errorf("no cached repo found. (try 'helm repo update'). %s", err)
|
||||
}
|
||||
|
||||
cv, err := i.Get(chartName, version)
|
||||
if err != nil {
|
||||
return u, r.Client, fmt.Errorf("chart %q matching %s not found in %s index. (try 'helm repo update'). %s", chartName, version, r.Config.Name, err)
|
||||
return u, r, g, fmt.Errorf("chart %q matching %s not found in %s index. (try 'helm repo update'). %s", chartName, version, r.Config.Name, err)
|
||||
}
|
||||
|
||||
if len(cv.URLs) == 0 {
|
||||
return u, r.Client, fmt.Errorf("chart %q has no downloadable URLs", ref)
|
||||
return u, r, g, fmt.Errorf("chart %q has no downloadable URLs", ref)
|
||||
}
|
||||
|
||||
// TODO: Seems that picking first URL is not fully correct
|
||||
u, err = url.Parse(cv.URLs[0])
|
||||
if err != nil {
|
||||
return u, r.Client, fmt.Errorf("invalid chart URL format: %s", ref)
|
||||
return u, r, g, fmt.Errorf("invalid chart URL format: %s", ref)
|
||||
}
|
||||
|
||||
// If the URL is relative (no scheme), prepend the chart repo's base URL
|
||||
if !u.IsAbs() {
|
||||
repoURL, err := url.Parse(rc.URL)
|
||||
if err != nil {
|
||||
return repoURL, r.Client, err
|
||||
return repoURL, r, nil, err
|
||||
}
|
||||
q := repoURL.Query()
|
||||
// We need a trailing slash for ResolveReference to work, but make sure there isn't already one
|
||||
repoURL.Path = strings.TrimSuffix(repoURL.Path, "/") + "/"
|
||||
u = repoURL.ResolveReference(u)
|
||||
u.RawQuery = q.Encode()
|
||||
return u, r.Client, err
|
||||
g, err := getter.NewHTTPGetter(rc.URL, "", "", "")
|
||||
if err != nil {
|
||||
return repoURL, r, nil, err
|
||||
}
|
||||
g.SetCredentials(c.getRepoCredentials(r))
|
||||
return u, r, g, err
|
||||
}
|
||||
|
||||
return u, r.Client, nil
|
||||
return u, r, g, nil
|
||||
}
|
||||
|
||||
// If this ChartDownloader is not configured to use credentials, and the chart repository sent as an argument is,
|
||||
// then the repository's configured credentials are returned.
|
||||
// Else, this ChartDownloader's credentials are returned.
|
||||
func (c *ChartDownloader) getRepoCredentials(r *repo.ChartRepository) (username, password string) {
|
||||
username = c.Username
|
||||
password = c.Password
|
||||
if r != nil && r.Config != nil {
|
||||
if username == "" {
|
||||
username = r.Config.Username
|
||||
}
|
||||
if password == "" {
|
||||
password = r.Config.Password
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// VerifyChart takes a path to a chart archive and a keyring, and verifies the chart.
|
||||
|
|
|
@ -99,11 +99,11 @@ func TestDownload(t *testing.T) {
|
|||
t.Fatal("No http provider found")
|
||||
}
|
||||
|
||||
getter, err := provider.New(srv.URL, "", "", "")
|
||||
g, err := provider.New(srv.URL, "", "", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got, err := getter.Get(srv.URL)
|
||||
got, err := g.Get(srv.URL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -115,16 +115,21 @@ func TestDownload(t *testing.T) {
|
|||
// test with server backed by basic auth
|
||||
basicAuthSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
username, password, ok := r.BasicAuth()
|
||||
if !ok || username != "username" && password != "password" {
|
||||
if !ok || username != "username" || password != "password" {
|
||||
t.Errorf("Expected request to use basic auth and for username == 'username' and password == 'password', got '%v', '%s', '%s'", ok, username, password)
|
||||
}
|
||||
fmt.Fprint(w, expect)
|
||||
}))
|
||||
|
||||
defer basicAuthSrv.Close()
|
||||
|
||||
u, _ := url.ParseRequestURI(basicAuthSrv.URL)
|
||||
u.User = url.UserPassword("username", "password")
|
||||
got, err = getter.Get(u.String())
|
||||
httpgetter, err := getter.NewHTTPGetter(u.String(), "", "", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
httpgetter.SetCredentials("username", "password")
|
||||
got, err = httpgetter.Get(u.String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -197,14 +197,6 @@ func (m *Manager) downloadAll(deps []*chartutil.Dependency) error {
|
|||
return err
|
||||
}
|
||||
|
||||
dl := ChartDownloader{
|
||||
Out: m.Out,
|
||||
Verify: m.Verify,
|
||||
Keyring: m.Keyring,
|
||||
HelmHome: m.HelmHome,
|
||||
Getters: m.Getters,
|
||||
}
|
||||
|
||||
destPath := filepath.Join(m.ChartPath, "charts")
|
||||
tmpPath := filepath.Join(m.ChartPath, "tmpcharts")
|
||||
|
||||
|
@ -245,12 +237,22 @@ func (m *Manager) downloadAll(deps []*chartutil.Dependency) error {
|
|||
|
||||
// Any failure to resolve/download a chart should fail:
|
||||
// https://github.com/kubernetes/helm/issues/1439
|
||||
churl, err := findChartURL(dep.Name, dep.Version, dep.Repository, repos)
|
||||
churl, username, password, err := findChartURL(dep.Name, dep.Version, dep.Repository, repos)
|
||||
if err != nil {
|
||||
saveError = fmt.Errorf("could not find %s: %s", churl, err)
|
||||
break
|
||||
}
|
||||
|
||||
dl := ChartDownloader{
|
||||
Out: m.Out,
|
||||
Verify: m.Verify,
|
||||
Keyring: m.Keyring,
|
||||
HelmHome: m.HelmHome,
|
||||
Getters: m.Getters,
|
||||
Username: username,
|
||||
Password: password,
|
||||
}
|
||||
|
||||
if _, _, err := dl.DownloadTo(churl, "", destPath); err != nil {
|
||||
saveError = fmt.Errorf("could not download %s: %s", churl, err)
|
||||
break
|
||||
|
@ -476,22 +478,30 @@ func (m *Manager) parallelRepoUpdate(repos []*repo.Entry) error {
|
|||
// repoURL is the repository to search
|
||||
//
|
||||
// If it finds a URL that is "relative", it will prepend the repoURL.
|
||||
func findChartURL(name, version, repoURL string, repos map[string]*repo.ChartRepository) (string, error) {
|
||||
func findChartURL(name, version, repoURL string, repos map[string]*repo.ChartRepository) (url, username, password string, err error) {
|
||||
for _, cr := range repos {
|
||||
if urlutil.Equal(repoURL, cr.Config.URL) {
|
||||
entry, err := findEntryByName(name, cr)
|
||||
var entry repo.ChartVersions
|
||||
entry, err = findEntryByName(name, cr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return
|
||||
}
|
||||
ve, err := findVersionedEntry(version, entry)
|
||||
var ve *repo.ChartVersion
|
||||
ve, err = findVersionedEntry(version, entry)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return
|
||||
}
|
||||
|
||||
return normalizeURL(repoURL, ve.URLs[0])
|
||||
url, err = normalizeURL(repoURL, ve.URLs[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
username = cr.Config.Username
|
||||
password = cr.Config.Password
|
||||
return
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("chart %s not found in %s", name, repoURL)
|
||||
err = fmt.Errorf("chart %s not found in %s", name, repoURL)
|
||||
return
|
||||
}
|
||||
|
||||
// findEntryByName finds an entry in the chart repository whose name matches the given name.
|
||||
|
|
|
@ -77,14 +77,19 @@ func TestFindChartURL(t *testing.T) {
|
|||
version := "0.1.0"
|
||||
repoURL := "http://example.com/charts"
|
||||
|
||||
churl, err := findChartURL(name, version, repoURL, repos)
|
||||
churl, username, password, err := findChartURL(name, version, repoURL, repos)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if churl != "https://kubernetes-charts.storage.googleapis.com/alpine-0.1.0.tgz" {
|
||||
t.Errorf("Unexpected URL %q", churl)
|
||||
}
|
||||
|
||||
if username != "" {
|
||||
t.Errorf("Unexpected username %q", username)
|
||||
}
|
||||
if password != "" {
|
||||
t.Errorf("Unexpected password %q", password)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRepoNames(t *testing.T) {
|
||||
|
|
|
@ -28,12 +28,23 @@ import (
|
|||
)
|
||||
|
||||
//httpGetter is the efault HTTP(/S) backend handler
|
||||
type httpGetter struct {
|
||||
client *http.Client
|
||||
type HttpGetter struct {
|
||||
client *http.Client
|
||||
username string
|
||||
password string
|
||||
}
|
||||
|
||||
func (g *HttpGetter) SetCredentials(username, password string) {
|
||||
g.username = username
|
||||
g.password = password
|
||||
}
|
||||
|
||||
//Get performs a Get from repo.Getter and returns the body.
|
||||
func (g *httpGetter) Get(href string) (*bytes.Buffer, error) {
|
||||
func (g *HttpGetter) Get(href string) (*bytes.Buffer, error) {
|
||||
return g.get(href)
|
||||
}
|
||||
|
||||
func (g *HttpGetter) get(href string) (*bytes.Buffer, error) {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
|
||||
// Set a helm specific user agent so that a repo server and metrics can
|
||||
|
@ -44,6 +55,10 @@ func (g *httpGetter) Get(href string) (*bytes.Buffer, error) {
|
|||
}
|
||||
req.Header.Set("User-Agent", "Helm/"+strings.TrimPrefix(version.GetVersion(), "v"))
|
||||
|
||||
if g.username != "" && g.password != "" {
|
||||
req.SetBasicAuth(g.username, g.password)
|
||||
}
|
||||
|
||||
resp, err := g.client.Do(req)
|
||||
if err != nil {
|
||||
return buf, err
|
||||
|
@ -59,17 +74,22 @@ func (g *httpGetter) Get(href string) (*bytes.Buffer, error) {
|
|||
|
||||
// newHTTPGetter constructs a valid http/https client as Getter
|
||||
func newHTTPGetter(URL, CertFile, KeyFile, CAFile string) (Getter, error) {
|
||||
var client httpGetter
|
||||
return NewHTTPGetter(URL, CertFile, KeyFile, CAFile)
|
||||
}
|
||||
|
||||
// NewHTTPGetter constructs a valid http/https client as HttpGetter
|
||||
func NewHTTPGetter(URL, CertFile, KeyFile, CAFile string) (*HttpGetter, error) {
|
||||
var client HttpGetter
|
||||
if CertFile != "" && KeyFile != "" {
|
||||
tlsConf, err := tlsutil.NewClientTLS(CertFile, KeyFile, CAFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't create TLS config for client: %s", err.Error())
|
||||
return &client, fmt.Errorf("can't create TLS config for client: %s", err.Error())
|
||||
}
|
||||
tlsConf.BuildNameToCertificate()
|
||||
|
||||
sni, err := urlutil.ExtractHostname(URL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return &client, err
|
||||
}
|
||||
tlsConf.ServerName = sni
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ func TestHTTPGetter(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if hg, ok := g.(*httpGetter); !ok {
|
||||
if hg, 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.")
|
||||
|
@ -42,7 +42,7 @@ func TestHTTPGetter(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, ok := g.(*httpGetter); !ok {
|
||||
if _, ok := g.(*HttpGetter); !ok {
|
||||
t.Fatal("Expected newHTTPGetter to produce an httpGetter")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,8 @@ type Entry struct {
|
|||
Name string `json:"name"`
|
||||
Cache string `json:"cache"`
|
||||
URL string `json:"url"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
CertFile string `json:"certFile"`
|
||||
KeyFile string `json:"keyFile"`
|
||||
CAFile string `json:"caFile"`
|
||||
|
@ -117,7 +119,12 @@ func (r *ChartRepository) DownloadIndexFile(cachePath string) error {
|
|||
parsedURL.Path = strings.TrimSuffix(parsedURL.Path, "/") + "/index.yaml"
|
||||
|
||||
indexURL = parsedURL.String()
|
||||
resp, err := r.Client.Get(indexURL)
|
||||
g, err := getter.NewHTTPGetter(indexURL, r.Config.CertFile, r.Config.KeyFile, r.Config.CAFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.SetCredentials(r.Config.Username, r.Config.Password)
|
||||
resp, err := g.Get(indexURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -186,6 +193,13 @@ func (r *ChartRepository) generateIndex() error {
|
|||
// 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)
|
||||
}
|
||||
|
||||
// FindChartInRepoURL finds chart in chart repository pointed by repoURL
|
||||
// without adding repo to repositories.
|
||||
// Unlike the FindChartInRepoURL function, this function also receives credentials for the chart repository.
|
||||
func FindChartInAuthRepoURL(repoURL, username, password, chartName, chartVersion, certFile, keyFile, caFile string, getters getter.Providers) (string, error) {
|
||||
|
||||
// Download and write the index file to a temporary location
|
||||
tempIndexFile, err := ioutil.TempFile("", "tmp-repo-file")
|
||||
|
@ -196,6 +210,8 @@ func FindChartInRepoURL(repoURL, chartName, chartVersion, certFile, keyFile, caF
|
|||
|
||||
c := Entry{
|
||||
URL: repoURL,
|
||||
Username: username,
|
||||
Password: password,
|
||||
CertFile: certFile,
|
||||
KeyFile: keyFile,
|
||||
CAFile: caFile,
|
||||
|
|
Loading…
Reference in New Issue