Add client with TLS transport (#1)

add client with TLS transport
pull/1670/head
Anton Galitsyn 9 years ago committed by GitHub
parent 5517d00a48
commit f97f0fd1e0

@ -17,11 +17,13 @@ package main
import ( import (
"io" "io"
"net/http"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/helm/cmd/helm/downloader" "k8s.io/helm/cmd/helm/downloader"
"k8s.io/helm/cmd/helm/helmpath" "k8s.io/helm/cmd/helm/helmpath"
"k8s.io/helm/pkg/util"
) )
const dependencyBuildDesc = ` const dependencyBuildDesc = `
@ -36,11 +38,16 @@ of 'helm dependency update'.
` `
type dependencyBuildCmd struct { type dependencyBuildCmd struct {
out io.Writer
chartpath string chartpath string
verify bool verify bool
keyring string keyring string
helmhome helmpath.Home helmhome helmpath.Home
certFile string
keyFile string
caFile string
out io.Writer
} }
func newDependencyBuildCmd(out io.Writer) *cobra.Command { func newDependencyBuildCmd(out io.Writer) *cobra.Command {
@ -66,16 +73,30 @@ func newDependencyBuildCmd(out io.Writer) *cobra.Command {
f := cmd.Flags() f := cmd.Flags()
f.BoolVar(&dbc.verify, "verify", false, "verify the packages against signatures") f.BoolVar(&dbc.verify, "verify", false, "verify the packages against signatures")
f.StringVar(&dbc.keyring, "keyring", defaultKeyring(), "keyring containing public keys") f.StringVar(&dbc.keyring, "keyring", defaultKeyring(), "keyring containing public keys")
f.StringVar(&dbc.certFile, "cert-file", "", "identify HTTPS client using this SSL certificate file")
f.StringVar(&dbc.keyFile, "key-file", "", "identify HTTPS client using this SSL key file")
f.StringVar(&dbc.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")
return cmd return cmd
} }
func (d *dependencyBuildCmd) run() error { func (d *dependencyBuildCmd) run() error {
var client *http.Client
var err error
if d.certFile != "" && d.keyFile != "" && d.caFile != "" {
client, err = util.NewHTTPClientTLS(d.certFile, d.keyFile, d.caFile)
if err != nil {
return err
}
} else {
client = http.DefaultClient
}
man := &downloader.Manager{ man := &downloader.Manager{
Out: d.out, Out: d.out,
ChartPath: d.chartpath, ChartPath: d.chartpath,
HelmHome: d.helmhome, HelmHome: d.helmhome,
Keyring: d.keyring, Keyring: d.keyring,
Client: client,
} }
if d.verify { if d.verify {
man.Verify = downloader.VerifyIfPossible man.Verify = downloader.VerifyIfPossible

@ -17,11 +17,13 @@ package main
import ( import (
"io" "io"
"net/http"
"path/filepath" "path/filepath"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/helm/cmd/helm/downloader" "k8s.io/helm/cmd/helm/downloader"
"k8s.io/helm/cmd/helm/helmpath" "k8s.io/helm/cmd/helm/helmpath"
"k8s.io/helm/pkg/util"
) )
const dependencyUpDesc = ` const dependencyUpDesc = `
@ -36,11 +38,16 @@ rebuild the requirements to an exact version.
// dependencyUpdateCmd describes a 'helm dependency update' // dependencyUpdateCmd describes a 'helm dependency update'
type dependencyUpdateCmd struct { type dependencyUpdateCmd struct {
out io.Writer
chartpath string chartpath string
helmhome helmpath.Home helmhome helmpath.Home
verify bool verify bool
keyring string keyring string
certFile string
keyFile string
caFile string
out io.Writer
} }
// newDependencyUpdateCmd creates a new dependency update command. // newDependencyUpdateCmd creates a new dependency update command.
@ -75,17 +82,31 @@ func newDependencyUpdateCmd(out io.Writer) *cobra.Command {
f := cmd.Flags() f := cmd.Flags()
f.BoolVar(&duc.verify, "verify", false, "verify the packages against signatures") f.BoolVar(&duc.verify, "verify", false, "verify the packages against signatures")
f.StringVar(&duc.keyring, "keyring", defaultKeyring(), "keyring containing public keys") f.StringVar(&duc.keyring, "keyring", defaultKeyring(), "keyring containing public keys")
f.StringVar(&duc.certFile, "cert-file", "", "identify HTTPS client using this SSL certificate file")
f.StringVar(&duc.keyFile, "key-file", "", "identify HTTPS client using this SSL key file")
f.StringVar(&duc.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")
return cmd return cmd
} }
// run runs the full dependency update process. // run runs the full dependency update process.
func (d *dependencyUpdateCmd) run() error { func (d *dependencyUpdateCmd) run() error {
var client *http.Client
var err error
if d.certFile != "" && d.keyFile != "" && d.caFile != "" {
client, err = util.NewHTTPClientTLS(d.certFile, d.keyFile, d.caFile)
if err != nil {
return err
}
} else {
client = http.DefaultClient
}
man := &downloader.Manager{ man := &downloader.Manager{
Out: d.out, Out: d.out,
ChartPath: d.chartpath, ChartPath: d.chartpath,
HelmHome: d.helmhome, HelmHome: d.helmhome,
Keyring: d.keyring, Keyring: d.keyring,
Client: client,
} }
if d.verify { if d.verify {
man.Verify = downloader.VerifyIfPossible man.Verify = downloader.VerifyIfPossible

@ -58,6 +58,8 @@ type ChartDownloader struct {
Keyring string Keyring string
// HelmHome is the $HELM_HOME. // HelmHome is the $HELM_HOME.
HelmHome helmpath.Home HelmHome helmpath.Home
// A Client is an HTTP client.
Client *http.Client
} }
// DownloadTo retrieves a chart. Depending on the settings, it may also download a provenance file. // DownloadTo retrieves a chart. Depending on the settings, it may also download a provenance file.
@ -76,7 +78,7 @@ func (c *ChartDownloader) DownloadTo(ref, version, dest string) (string, *proven
if err != nil { if err != nil {
return "", nil, err return "", nil, err
} }
data, err := download(u.String()) data, err := download(u.String(), c.Client)
if err != nil { if err != nil {
return "", nil, err return "", nil, err
} }
@ -91,7 +93,7 @@ func (c *ChartDownloader) DownloadTo(ref, version, dest string) (string, *proven
ver := &provenance.Verification{} ver := &provenance.Verification{}
if c.Verify > VerifyNever { if c.Verify > VerifyNever {
body, err := download(u.String() + ".prov") body, err := download(u.String()+".prov", c.Client)
if err != nil { if err != nil {
if c.Verify == VerifyAlways { if c.Verify == VerifyAlways {
return destfile, ver, fmt.Errorf("Failed to fetch provenance %q", u.String()+".prov") return destfile, ver, fmt.Errorf("Failed to fetch provenance %q", u.String()+".prov")
@ -211,10 +213,10 @@ func VerifyChart(path string, keyring string) (*provenance.Verification, error)
} }
// download performs a simple HTTP Get and returns the body. // download performs a simple HTTP Get and returns the body.
func download(href string) (*bytes.Buffer, error) { func download(href string, client *http.Client) (*bytes.Buffer, error) {
buf := bytes.NewBuffer(nil) buf := bytes.NewBuffer(nil)
resp, err := http.Get(href) resp, err := client.Get(href)
if err != nil { if err != nil {
return buf, err return buf, err
} }

@ -82,7 +82,7 @@ func TestDownload(t *testing.T) {
})) }))
defer srv.Close() defer srv.Close()
got, err := download(srv.URL) got, err := download(srv.URL, http.DefaultClient)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -132,6 +132,7 @@ func TestDownloadTo(t *testing.T) {
Out: os.Stderr, Out: os.Stderr,
Verify: VerifyAlways, Verify: VerifyAlways,
Keyring: "testdata/helm-test-key.pub", Keyring: "testdata/helm-test-key.pub",
Client: http.DefaultClient,
} }
cname := "/signtest-0.1.0.tgz" cname := "/signtest-0.1.0.tgz"
where, v, err := c.DownloadTo(srv.URL()+cname, "", dest) where, v, err := c.DownloadTo(srv.URL()+cname, "", dest)

@ -20,6 +20,7 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"net/http"
"net/url" "net/url"
"os" "os"
"path" "path"
@ -49,6 +50,8 @@ type Manager struct {
Verify VerificationStrategy Verify VerificationStrategy
// Keyring is the key ring file. // Keyring is the key ring file.
Keyring string Keyring string
// A Client is an HTTP client.
Client *http.Client
} }
// Build rebuilds a local charts directory from a lockfile. // Build rebuilds a local charts directory from a lockfile.
@ -179,6 +182,7 @@ func (m *Manager) downloadAll(deps []*chartutil.Dependency) error {
Verify: m.Verify, Verify: m.Verify,
Keyring: m.Keyring, Keyring: m.Keyring,
HelmHome: m.HelmHome, HelmHome: m.HelmHome,
Client: m.Client,
} }
destPath := filepath.Join(m.ChartPath, "charts") destPath := filepath.Join(m.ChartPath, "charts")
@ -295,7 +299,7 @@ func (m *Manager) parallelRepoUpdate(repos []*repo.Entry) {
for _, re := range repos { for _, re := range repos {
wg.Add(1) wg.Add(1)
go func(n, u string) { go func(n, u string) {
if err := repo.DownloadIndexFile(n, u, m.HelmHome.CacheIndex(n)); err != nil { if err := repo.DownloadIndexFile(n, u, m.HelmHome.CacheIndex(n), http.DefaultClient); err != nil {
fmt.Fprintf(out, "...Unable to get an update from the %q chart repository (%s):\n\t%s\n", n, u, err) fmt.Fprintf(out, "...Unable to get an update from the %q chart repository (%s):\n\t%s\n", n, u, err)
} else { } else {
fmt.Fprintf(out, "...Successfully got an update from the %q chart repository\n", n) fmt.Fprintf(out, "...Successfully got an update from the %q chart repository\n", n)

@ -20,6 +20,7 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"net/http"
"os" "os"
"path/filepath" "path/filepath"
@ -27,6 +28,7 @@ import (
"k8s.io/helm/cmd/helm/downloader" "k8s.io/helm/cmd/helm/downloader"
"k8s.io/helm/cmd/helm/helmpath" "k8s.io/helm/cmd/helm/helmpath"
"k8s.io/helm/pkg/chartutil" "k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/util"
) )
const fetchDesc = ` const fetchDesc = `
@ -54,6 +56,10 @@ type fetchCmd struct {
verify bool verify bool
keyring string keyring string
certFile string
keyFile string
caFile string
out io.Writer out io.Writer
} }
@ -85,17 +91,30 @@ func newFetchCmd(out io.Writer) *cobra.Command {
f.StringVar(&fch.version, "version", "", "specific version of a chart. Without this, the latest version is fetched") f.StringVar(&fch.version, "version", "", "specific version of a chart. Without this, the latest version is fetched")
f.StringVar(&fch.keyring, "keyring", defaultKeyring(), "keyring containing public keys") f.StringVar(&fch.keyring, "keyring", defaultKeyring(), "keyring containing public keys")
f.StringVarP(&fch.destdir, "destination", "d", ".", "location to write the chart. If this and tardir are specified, tardir is appended to this") f.StringVarP(&fch.destdir, "destination", "d", ".", "location to write the chart. If this and tardir are specified, tardir is appended to this")
f.StringVar(&fch.certFile, "cert-file", "", "identify HTTPS client using this SSL certificate file")
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")
return cmd return cmd
} }
func (f *fetchCmd) run() error { func (f *fetchCmd) run() error {
pname := f.chartRef var client *http.Client
var err error
if f.certFile != "" && f.keyFile != "" && f.caFile != "" {
client, err = util.NewHTTPClientTLS(f.certFile, f.keyFile, f.caFile)
if err != nil {
return err
}
} else {
client = http.DefaultClient
}
c := downloader.ChartDownloader{ c := downloader.ChartDownloader{
HelmHome: helmpath.Home(homePath()), HelmHome: helmpath.Home(homePath()),
Out: f.out, Out: f.out,
Keyring: f.keyring, Keyring: f.keyring,
Verify: downloader.VerifyNever, Verify: downloader.VerifyNever,
Client: client,
} }
if f.verify { if f.verify {
@ -114,7 +133,7 @@ func (f *fetchCmd) run() error {
defer os.RemoveAll(dest) defer os.RemoveAll(dest)
} }
saved, v, err := c.DownloadTo(pname, f.version, dest) saved, v, err := c.DownloadTo(f.chartRef, f.version, dest)
if err != nil { if err != nil {
return err return err
} }

@ -20,6 +20,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"net/http"
"os" "os"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -172,7 +173,7 @@ func ensureHome(home helmpath.Home, out io.Writer) error {
return err return err
} }
cif := home.CacheIndex(stableRepository) cif := home.CacheIndex(stableRepository)
if err := repo.DownloadIndexFile(stableRepository, stableRepositoryURL, cif); err != nil { if err := repo.DownloadIndexFile(stableRepository, stableRepositoryURL, cif, http.DefaultClient); err != nil {
fmt.Fprintf(out, "WARNING: Failed to download %s: %s (run 'helm repo update')\n", stableRepository, err) fmt.Fprintf(out, "WARNING: Failed to download %s: %s (run 'helm repo update')\n", stableRepository, err)
} }
} else if fi.IsDir() { } else if fi.IsDir() {

@ -22,6 +22,7 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"net/http"
"os" "os"
"path/filepath" "path/filepath"
"strconv" "strconv"
@ -360,6 +361,8 @@ func locateChartPath(name, version string, verify bool, keyring string) (string,
HelmHome: helmpath.Home(homePath()), HelmHome: helmpath.Home(homePath()),
Out: os.Stdout, Out: os.Stdout,
Keyring: keyring, Keyring: keyring,
// TODO: this should be configurable
Client: http.DefaultClient,
} }
if verify { if verify {
dl.Verify = downloader.VerifyAlways dl.Verify = downloader.VerifyAlways

@ -19,20 +19,27 @@ package main
import ( import (
"fmt" "fmt"
"io" "io"
"net/http"
"path/filepath" "path/filepath"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/helm/cmd/helm/helmpath" "k8s.io/helm/cmd/helm/helmpath"
"k8s.io/helm/pkg/repo" "k8s.io/helm/pkg/repo"
"k8s.io/helm/pkg/util"
) )
type repoAddCmd struct { type repoAddCmd struct {
name string name string
url string url string
home helmpath.Home home helmpath.Home
out io.Writer
noupdate bool noupdate bool
certFile string
keyFile string
caFile string
out io.Writer
} }
func newRepoAddCmd(out io.Writer) *cobra.Command { func newRepoAddCmd(out io.Writer) *cobra.Command {
@ -55,17 +62,32 @@ func newRepoAddCmd(out io.Writer) *cobra.Command {
return add.run() return add.run()
}, },
} }
f := cmd.Flags() f := cmd.Flags()
f.BoolVar(&add.noupdate, "no-update", false, "raise error if repo is already registered") 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")
f.StringVar(&add.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")
return cmd return cmd
} }
func (a *repoAddCmd) run() error { func (a *repoAddCmd) run() error {
var client *http.Client
var err error var err error
if a.certFile != "" && a.keyFile != "" && a.caFile != "" {
client, err = util.NewHTTPClientTLS(a.certFile, a.keyFile, a.caFile)
if err != nil {
return err
}
} else {
client = http.DefaultClient
}
if a.noupdate { if a.noupdate {
err = addRepository(a.name, a.url, a.home) err = addRepository(a.name, a.url, a.home, client)
} else { } else {
err = updateRepository(a.name, a.url, a.home) err = updateRepository(a.name, a.url, a.home, client)
} }
if err != nil { if err != nil {
return err return err
@ -74,9 +96,9 @@ func (a *repoAddCmd) run() error {
return nil return nil
} }
func addRepository(name, url string, home helmpath.Home) error { func addRepository(name, url string, home helmpath.Home, client *http.Client) error {
cif := home.CacheIndex(name) cif := home.CacheIndex(name)
if err := repo.DownloadIndexFile(name, url, cif); err != nil { if err := repo.DownloadIndexFile(name, url, cif, client); err != nil {
return fmt.Errorf("Looks like %q is not a valid chart repository or cannot be reached: %s", url, err.Error()) return fmt.Errorf("Looks like %q is not a valid chart repository or cannot be reached: %s", url, err.Error())
} }
@ -101,9 +123,9 @@ func insertRepoLine(name, url string, home helmpath.Home) error {
return f.WriteFile(home.RepositoryFile(), 0644) return f.WriteFile(home.RepositoryFile(), 0644)
} }
func updateRepository(name, url string, home helmpath.Home) error { func updateRepository(name, url string, home helmpath.Home, client *http.Client) error {
cif := home.CacheIndex(name) cif := home.CacheIndex(name)
if err := repo.DownloadIndexFile(name, url, cif); err != nil { if err := repo.DownloadIndexFile(name, url, cif, client); err != nil {
return err return err
} }

@ -18,6 +18,7 @@ package main
import ( import (
"bytes" "bytes"
"net/http"
"os" "os"
"testing" "testing"
@ -80,7 +81,7 @@ func TestRepoAdd(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
if err := addRepository(testName, ts.URL(), hh); err != nil { if err := addRepository(testName, ts.URL(), hh, http.DefaultClient); err != nil {
t.Error(err) t.Error(err)
} }
@ -93,11 +94,11 @@ func TestRepoAdd(t *testing.T) {
t.Errorf("%s was not successfully inserted into %s", testName, hh.RepositoryFile()) t.Errorf("%s was not successfully inserted into %s", testName, hh.RepositoryFile())
} }
if err := updateRepository(testName, ts.URL(), hh); err != nil { if err := updateRepository(testName, ts.URL(), hh, http.DefaultClient); err != nil {
t.Errorf("Repository was not updated: %s", err) t.Errorf("Repository was not updated: %s", err)
} }
if err := addRepository(testName, ts.URL(), hh); err == nil { if err := addRepository(testName, ts.URL(), hh, http.DefaultClient); err == nil {
t.Errorf("Duplicate repository name was added") t.Errorf("Duplicate repository name was added")
} }
} }

@ -20,12 +20,14 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"net/http"
"sync" "sync"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/helm/cmd/helm/helmpath" "k8s.io/helm/cmd/helm/helmpath"
"k8s.io/helm/pkg/repo" "k8s.io/helm/pkg/repo"
"k8s.io/helm/pkg/util"
) )
const updateDesc = ` const updateDesc = `
@ -37,9 +39,14 @@ future releases.
` `
type repoUpdateCmd struct { type repoUpdateCmd struct {
update func([]*repo.Entry, bool, io.Writer, helmpath.Home) update func([]*repo.Entry, bool, io.Writer, helmpath.Home, *http.Client)
out io.Writer
home helmpath.Home home helmpath.Home
certFile string
keyFile string
caFile string
out io.Writer
} }
func newRepoUpdateCmd(out io.Writer) *cobra.Command { func newRepoUpdateCmd(out io.Writer) *cobra.Command {
@ -57,10 +64,27 @@ func newRepoUpdateCmd(out io.Writer) *cobra.Command {
return u.run() return u.run()
}, },
} }
f := cmd.Flags()
f.StringVar(&u.certFile, "cert-file", "", "identify HTTPS client using this SSL certificate file")
f.StringVar(&u.keyFile, "key-file", "", "identify HTTPS client using this SSL key file")
f.StringVar(&u.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")
return cmd return cmd
} }
func (u *repoUpdateCmd) run() error { func (u *repoUpdateCmd) run() error {
var client *http.Client
var err error
if u.certFile != "" && u.keyFile != "" && u.caFile != "" {
client, err = util.NewHTTPClientTLS(u.certFile, u.keyFile, u.caFile)
if err != nil {
return err
}
} else {
client = http.DefaultClient
}
f, err := repo.LoadRepositoriesFile(u.home.RepositoryFile()) f, err := repo.LoadRepositoriesFile(u.home.RepositoryFile())
if err != nil { if err != nil {
return err return err
@ -70,11 +94,11 @@ func (u *repoUpdateCmd) run() error {
return errors.New("no repositories found. You must add one before updating") return errors.New("no repositories found. You must add one before updating")
} }
u.update(f.Repositories, flagDebug, u.out, u.home) u.update(f.Repositories, flagDebug, u.out, u.home, client)
return nil return nil
} }
func updateCharts(repos []*repo.Entry, verbose bool, out io.Writer, home helmpath.Home) { func updateCharts(repos []*repo.Entry, verbose bool, out io.Writer, home helmpath.Home, client *http.Client) {
fmt.Fprintln(out, "Hang tight while we grab the latest from your chart repositories...") fmt.Fprintln(out, "Hang tight while we grab the latest from your chart repositories...")
var wg sync.WaitGroup var wg sync.WaitGroup
for _, re := range repos { for _, re := range repos {
@ -85,7 +109,7 @@ func updateCharts(repos []*repo.Entry, verbose bool, out io.Writer, home helmpat
// We skip local because the indices are symlinked. // We skip local because the indices are symlinked.
return return
} }
err := repo.DownloadIndexFile(n, u, home.CacheIndex(n)) err := repo.DownloadIndexFile(n, u, home.CacheIndex(n), client)
if err != nil { if err != nil {
fmt.Fprintf(out, "...Unable to get an update from the %q chart repository (%s):\n\t%s\n", n, u, err) fmt.Fprintf(out, "...Unable to get an update from the %q chart repository (%s):\n\t%s\n", n, u, err)
} else { } else {

@ -19,6 +19,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"io" "io"
"net/http"
"os" "os"
"strings" "strings"
"testing" "testing"
@ -43,7 +44,7 @@ func TestUpdateCmd(t *testing.T) {
out := bytes.NewBuffer(nil) out := bytes.NewBuffer(nil)
// Instead of using the HTTP updater, we provide our own for this test. // Instead of using the HTTP updater, we provide our own for this test.
// The TestUpdateCharts test verifies the HTTP behavior independently. // The TestUpdateCharts test verifies the HTTP behavior independently.
updater := func(repos []*repo.Entry, verbose bool, out io.Writer, home helmpath.Home) { updater := func(repos []*repo.Entry, verbose bool, out io.Writer, home helmpath.Home, client *http.Client) {
for _, re := range repos { for _, re := range repos {
fmt.Fprintln(out, re.Name) fmt.Fprintln(out, re.Name)
} }
@ -83,7 +84,7 @@ func TestUpdateCharts(t *testing.T) {
repos := []*repo.Entry{ repos := []*repo.Entry{
{Name: "charts", URL: srv.URL()}, {Name: "charts", URL: srv.URL()},
} }
updateCharts(repos, false, buf, helmpath.Home(thome)) updateCharts(repos, false, buf, helmpath.Home(thome), http.DefaultClient)
got := buf.String() got := buf.String()
if strings.Contains(got, "Unable to get an update") { if strings.Contains(got, "Unable to get an update") {

@ -229,11 +229,11 @@ func IndexDirectory(dir, baseURL string) (*IndexFile, error) {
} }
// DownloadIndexFile fetches the index from a repository. // DownloadIndexFile fetches the index from a repository.
func DownloadIndexFile(repoName, url, indexFilePath string) error { func DownloadIndexFile(repoName, url, indexFilePath string, client *http.Client) error {
var indexURL string var indexURL string
indexURL = strings.TrimSuffix(url, "/") + "/index.yaml" indexURL = strings.TrimSuffix(url, "/") + "/index.yaml"
resp, err := http.Get(indexURL) resp, err := client.Get(indexURL)
if err != nil { if err != nil {
return err return err
} }

@ -133,7 +133,7 @@ func TestDownloadIndexFile(t *testing.T) {
defer os.RemoveAll(dirName) defer os.RemoveAll(dirName)
path := filepath.Join(dirName, testRepo+"-index.yaml") path := filepath.Join(dirName, testRepo+"-index.yaml")
if err := DownloadIndexFile(testRepo, srv.URL, path); err != nil { if err := DownloadIndexFile(testRepo, srv.URL, path, http.DefaultClient); err != nil {
t.Errorf("%#v", err) t.Errorf("%#v", err)
} }

@ -0,0 +1,68 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
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 util
import (
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
)
// 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
}
cp, err := CertPoolFromFile(caFile)
if err != nil {
return nil, err
}
return &tls.Config{
Certificates: []tls.Certificate{*cert},
RootCAs: cp,
}, nil
}
// CertPoolFromFile returns an x509.CertPool containing the certificates
// in the given PEM-encoded file.
// Returns an error if the file could not be read, a certificate could not
// be parsed, or if the file does not contain any certificates
func CertPoolFromFile(filename string) (*x509.CertPool, error) {
b, err := ioutil.ReadFile(filename)
if err != nil {
return nil, fmt.Errorf("can't read CA file: %v", filename)
}
cp := x509.NewCertPool()
if !cp.AppendCertsFromPEM(b) {
return nil, fmt.Errorf("failed to append certificates from file: %s", filename)
}
return cp, nil
}
// CertFromFilePair returns an tls.Certificate containing the
// certificates public/private key pair from a pair of given PEM-encoded files.
// Returns an error if the file could not be read, a certificate could not
// be parsed, or if the file does not contain any certificates
func CertFromFilePair(certFile, keyFile string) (*tls.Certificate, error) {
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
return nil, fmt.Errorf("can't load key pair from cert %s and key %s", certFile, keyFile)
}
return &cert, err
}

@ -0,0 +1,37 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
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 util
import (
"fmt"
"net/http"
)
// NewHTTPClientTLS constructs http.Client with configured TLS for http.Transport
func NewHTTPClientTLS(certFile, keyFile, caFile string) (*http.Client, error) {
tlsConf, err := NewClientTLS(certFile, keyFile, caFile)
if err != nil {
return nil, fmt.Errorf("can't create TLS config for client: %s", err.Error())
}
tlsConf.BuildNameToCertificate()
client := &http.Client{
Transport: &http.Transport{
TLSClientConfig: tlsConf,
},
}
return client, nil
}
Loading…
Cancel
Save