diff --git a/pkg/minikube/cluster/cluster.go b/pkg/minikube/cluster/cluster.go index f32e8bcc7f..7d60f1ec93 100644 --- a/pkg/minikube/cluster/cluster.go +++ b/pkg/minikube/cluster/cluster.go @@ -19,7 +19,6 @@ package cluster import ( "bytes" "encoding/json" - "errors" "flag" "fmt" "io" @@ -39,7 +38,6 @@ import ( "github.com/docker/machine/libmachine/host" "github.com/docker/machine/libmachine/state" "github.com/golang/glog" - "golang.org/x/crypto/ssh" kubeApi "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/client/unversioned" "k8s.io/kubernetes/pkg/client/unversioned/clientcmd" @@ -211,101 +209,14 @@ var assets = []fileToCopy{ }, } -func (k *KubernetesConfig) getLocalkubeCacheFilepath() string { - return filepath.Join(constants.Minipath, "cache", "localkube", - filepath.Base("localkube-"+util.GetMD5Hash(k.KubernetesVersion))) -} - -func (k *KubernetesConfig) isLocalkubeCached() bool { - if _, err := os.Stat(k.getLocalkubeCacheFilepath()); os.IsNotExist(err) { - return false - } - return true -} - -func (k *KubernetesConfig) cacheLocalkube(response *http.Response) error { - // store localkube inside the .minikube dir - out, err := os.Create(k.getLocalkubeCacheFilepath()) - if err != nil { - - return err - } - defer out.Close() - defer response.Body.Close() - if _, err = io.Copy(out, response.Body); err != nil { - return err - } - return nil -} - -func (k *KubernetesConfig) downloadAndCacheLocalkube() error { - resp := &http.Response{} - err := errors.New("") - downloader := func() (err error) { - url, err := util.GetLocalkubeDownloadURL(k.KubernetesVersion, - constants.LocalkubeLinuxFilename) - if err != nil { - return err - } - resp, err = http.Get(url) - return err - } - - if err = util.Retry(5, downloader); err != nil { - return err - } - if err = k.cacheLocalkube(resp); err != nil { - return err - } - return nil -} - -func updateLocalkubeFromURL(config KubernetesConfig, client *ssh.Client) error { - if !config.isLocalkubeCached() { - if err := config.downloadAndCacheLocalkube(); err != nil { - return err - } - } - if err := config.transferCachedLocalkubeToVM(client); err != nil { - return err - } - return nil -} - -func (k *KubernetesConfig) transferCachedLocalkubeToVM(client *ssh.Client) error { - contents, err := ioutil.ReadFile(k.getLocalkubeCacheFilepath()) - if err != nil { - glog.Infof("Error loading asset out/localkube: %s", err) - return err - } - - if err = sshutil.Transfer(bytes.NewReader(contents), len(contents), "/usr/local/bin", - "localkube", "0777", client); err != nil { - return err - } - return nil -} - -func updateLocalkubeFromAsset(client *ssh.Client) error { - contents, err := Asset("out/localkube") - if err != nil { - glog.Infof("Error loading asset out/localkube: %s", err) - return err - } - if err := sshutil.Transfer(bytes.NewReader(contents), len(contents), "/usr/local/bin", - "localkube", "0777", client); err != nil { - return err - } - return nil -} - func UpdateCluster(h sshAble, d drivers.Driver, config KubernetesConfig) error { client, err := sshutil.NewSSHClient(d) if err != nil { return err } if localkubeURLWasSpecified(config) { - if err = updateLocalkubeFromURL(config, client); err != nil { + lCacher := localkubeCacher{config} + if err = updateLocalkubeFromURL(lCacher, client); err != nil { return err } } else { @@ -394,7 +305,6 @@ func createVirtualboxHost(config MachineConfig) drivers.Driver { func (m *MachineConfig) CacheMinikubeISOFromURL() error { // store the miniube-iso inside the .minikube dir - // TODO(aprindle) put this in a retry loop? response, err := http.Get(m.MinikubeISO) if err != nil { return err diff --git a/pkg/minikube/cluster/cluster_test.go b/pkg/minikube/cluster/cluster_test.go index 5bb3c8c5ad..3d00def8c5 100644 --- a/pkg/minikube/cluster/cluster_test.go +++ b/pkg/minikube/cluster/cluster_test.go @@ -568,3 +568,48 @@ func TestUpdateKubernetesVersion(t *testing.T) { t.Fatalf("File not copied. Expected transfers to contain: %s. It was: %s", contents, transferred) } } + +type nopCloser struct { + io.Reader +} + +func (nopCloser) Close() error { return nil } + +func TestIsLocalkubeCached(t *testing.T) { + tempDir := tests.MakeTempDir() + defer os.RemoveAll(tempDir) + + inputArr := [...]string{ + "v1.3.3", + "1.3.0", + "http://test-url.localkube.com/localkube-binary", + "file:///test/dir/to/localkube-binary", + } + + readCloser := nopCloser{} + + localkubeCacher := localkubeCacher{ + k8sConf: KubernetesConfig{}, + } + + inner := func(input string) { + localkubeCacher.k8sConf = KubernetesConfig{ + KubernetesVersion: input, + } + if localkubeCacher.isLocalkubeCached() { + t.Errorf("IsLocalKubeCached returned true even though %s was not cached", + localkubeCacher.getLocalkubeCacheFilepath()) + } + + readCloser = nopCloser{bytes.NewBufferString("test-localkube-binary-data")} + localkubeCacher.cacheLocalkube(readCloser) + if !localkubeCacher.isLocalkubeCached() { + t.Errorf("IsLocalKubeCached returned false even though %s was cached", + localkubeCacher.getLocalkubeCacheFilepath()) + } + + } + for _, input := range inputArr { + inner(input) + } +} diff --git a/pkg/minikube/cluster/localkube_caching.go b/pkg/minikube/cluster/localkube_caching.go new file mode 100644 index 0000000000..0ce8556ef6 --- /dev/null +++ b/pkg/minikube/cluster/localkube_caching.go @@ -0,0 +1,126 @@ +/* +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 cluster + +import ( + "bytes" + "errors" + "io" + "io/ioutil" + "net/http" + "net/url" + "os" + "path/filepath" + + "github.com/golang/glog" + "golang.org/x/crypto/ssh" + "k8s.io/minikube/pkg/minikube/constants" + "k8s.io/minikube/pkg/minikube/sshutil" + "k8s.io/minikube/pkg/util" +) + +// localkubeCacher is a struct with methods designed for caching localkube +type localkubeCacher struct { + k8sConf KubernetesConfig +} + +func (l *localkubeCacher) getLocalkubeCacheFilepath() string { + return filepath.Join(constants.Minipath, "cache", "localkube", + filepath.Base(url.QueryEscape("localkube-"+l.k8sConf.KubernetesVersion))) +} + +func (l *localkubeCacher) isLocalkubeCached() bool { + if _, err := os.Stat(l.getLocalkubeCacheFilepath()); os.IsNotExist(err) { + return false + } + return true +} + +func (l *localkubeCacher) cacheLocalkube(body io.ReadCloser) error { + // store localkube inside the .minikube dir + out, err := os.Create(l.getLocalkubeCacheFilepath()) + if err != nil { + return err + } + defer out.Close() + defer body.Close() + if _, err = io.Copy(out, body); err != nil { + return err + } + return nil +} + +func (l *localkubeCacher) downloadAndCacheLocalkube() error { + resp := &http.Response{} + err := errors.New("") + downloader := func() (err error) { + url, err := util.GetLocalkubeDownloadURL(l.k8sConf.KubernetesVersion, + constants.LocalkubeLinuxFilename) + if err != nil { + return err + } + resp, err = http.Get(url) + return err + } + + if err = util.Retry(5, downloader); err != nil { + return err + } + if err = l.cacheLocalkube(resp.Body); err != nil { + return err + } + return nil +} + +func updateLocalkubeFromURL(lCacher localkubeCacher, client *ssh.Client) error { + if !lCacher.isLocalkubeCached() { + if err := lCacher.downloadAndCacheLocalkube(); err != nil { + return err + } + } + if err := lCacher.transferCachedLocalkubeToVM(client); err != nil { + return err + } + return nil +} + +func (l *localkubeCacher) transferCachedLocalkubeToVM(client *ssh.Client) error { + contents, err := ioutil.ReadFile(l.getLocalkubeCacheFilepath()) + if err != nil { + glog.Infof("Error loading asset out/localkube: %s", err) + return err + } + + if err = sshutil.Transfer(bytes.NewReader(contents), len(contents), "/usr/local/bin", + "localkube", "0777", client); err != nil { + return err + } + return nil +} + +func updateLocalkubeFromAsset(client *ssh.Client) error { + contents, err := Asset("out/localkube") + if err != nil { + glog.Infof("Error loading asset out/localkube: %s", err) + return err + } + if err := sshutil.Transfer(bytes.NewReader(contents), len(contents), "/usr/local/bin", + "localkube", "0777", client); err != nil { + return err + } + return nil +} diff --git a/pkg/util/utils.go b/pkg/util/utils.go index d5cd290fdf..8119a2c6d1 100644 --- a/pkg/util/utils.go +++ b/pkg/util/utils.go @@ -17,8 +17,6 @@ limitations under the License. package util import ( - "crypto/md5" - "encoding/hex" "fmt" "io" "net/url" @@ -107,7 +105,6 @@ func GetLocalkubeDownloadURL(versionOrURL string, filename string) (string, erro return fmt.Sprintf("%s%s/%s", constants.LocalkubeDownloadURLPrefix, versionOrURL, filename), nil } -<<<<<<< 38d0f083510df2b7b91dc59fdbc8517b8d02fbd1 type MultiError struct { Errors []error }